From cd83df386bc0c567bda9a00ed297467b6046d785 Mon Sep 17 00:00:00 2001 From: Gabriel Schulhof Date: Fri, 20 Apr 2018 22:57:33 -0400 Subject: [PATCH 001/173] n-api: initialize a module via a special symbol Much like regular modules, N-API modules can also benefit from having a special symbol which they can expose. Fixes: https://github.com/nodejs/node/issues/19845 PR-URL: https://github.com/nodejs/node/pull/20161 Reviewed-By: Ben Noordhuis --- doc/api/n-api.md | 26 ++++++++++++++++++++++++ src/node.cc | 9 ++++++++ src/node_api.cc | 15 +++++++++----- src/node_api.h | 21 ++++++++++++++++++- src/node_internals.h | 5 +++++ test/addons-napi/1_hello_world/binding.c | 4 +--- test/addons-napi/1_hello_world/test.js | 11 ++++++++-- 7 files changed, 80 insertions(+), 11 deletions(-) diff --git a/doc/api/n-api.md b/doc/api/n-api.md index 826b83e2251f32..26b5e87463948e 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -982,6 +982,32 @@ napi_value Init(napi_env env, napi_value exports) { } ``` +If you expect that your module will be loaded multiple times during the lifetime +of the Node.js process, you can use the `NAPI_MODULE_INIT` macro to initialize +your module: + +```C +NAPI_MODULE_INIT() { + napi_value answer; + napi_status result; + + status = napi_create_int64(env, 42, &answer); + if (status != napi_ok) return NULL; + + status = napi_set_named_property(env, exports, "answer", answer); + if (status != napi_ok) return NULL; + + return exports; +} +``` + +This macro includes `NAPI_MODULE`, and declares an `Init` function with a +special name and with visibility beyond the addon. This will allow Node.js to +initialize the module even if it is loaded multiple times. + +The variables `env` and `exports` will be available inside the function body +following the macro invocation. + For more details on setting properties on objects, see the section on [Working with JavaScript Properties][]. diff --git a/src/node.cc b/src/node.cc index 90defba40ba95e..032963bff41a69 100644 --- a/src/node.cc +++ b/src/node.cc @@ -2227,6 +2227,13 @@ inline InitializerCallback GetInitializerCallback(DLib* dlib) { return reinterpret_cast(dlib->GetSymbolAddress(name)); } +inline napi_addon_register_func GetNapiInitializerCallback(DLib* dlib) { + const char* name = + STRINGIFY(NAPI_MODULE_INITIALIZER_BASE) STRINGIFY(NAPI_MODULE_VERSION); + return + reinterpret_cast(dlib->GetSymbolAddress(name)); +} + // DLOpen is process.dlopen(module, filename, flags). // Used to load 'module.node' dynamically shared objects. // @@ -2283,6 +2290,8 @@ static void DLOpen(const FunctionCallbackInfo& args) { if (mp == nullptr) { if (auto callback = GetInitializerCallback(&dlib)) { callback(exports, module, context); + } else if (auto napi_callback = GetNapiInitializerCallback(&dlib)) { + napi_module_register_by_symbol(exports, module, context, napi_callback); } else { dlib.Close(); env->ThrowError("Module did not self-register."); diff --git a/src/node_api.cc b/src/node_api.cc index ea7ddba77dc2e2..4878cf241edc04 100644 --- a/src/node_api.cc +++ b/src/node_api.cc @@ -858,16 +858,23 @@ void napi_module_register_cb(v8::Local exports, v8::Local module, v8::Local context, void* priv) { - napi_module* mod = static_cast(priv); + napi_module_register_by_symbol(exports, module, context, + static_cast(priv)->nm_register_func); +} + +} // end of anonymous namespace +void napi_module_register_by_symbol(v8::Local exports, + v8::Local module, + v8::Local context, + napi_addon_register_func init) { // Create a new napi_env for this module or reference one if a pre-existing // one is found. napi_env env = v8impl::GetEnv(context); napi_value _exports; NAPI_CALL_INTO_MODULE_THROW(env, - _exports = mod->nm_register_func(env, - v8impl::JsValueFromV8LocalValue(exports))); + _exports = init(env, v8impl::JsValueFromV8LocalValue(exports))); // If register function returned a non-null exports object different from // the exports object we passed it, set that as the "exports" property of @@ -879,8 +886,6 @@ void napi_module_register_cb(v8::Local exports, } } -} // end of anonymous namespace - // Registers a NAPI module. void napi_module_register(napi_module* mod) { node::node_module* nm = new node::node_module { diff --git a/src/node_api.h b/src/node_api.h index aaf002b7584449..b010d32db7b086 100644 --- a/src/node_api.h +++ b/src/node_api.h @@ -90,9 +90,28 @@ typedef struct { } \ EXTERN_C_END -#define NAPI_MODULE(modname, regfunc) \ +#define NAPI_MODULE(modname, regfunc) \ NAPI_MODULE_X(modname, regfunc, NULL, 0) // NOLINT (readability/null_usage) +#define NAPI_MODULE_INITIALIZER_BASE napi_register_module_v + +#define NAPI_MODULE_INITIALIZER_X(base, version) \ + NAPI_MODULE_INITIALIZER_X_HELPER(base, version) +#define NAPI_MODULE_INITIALIZER_X_HELPER(base, version) base##version + +#define NAPI_MODULE_INITIALIZER \ + NAPI_MODULE_INITIALIZER_X(NAPI_MODULE_INITIALIZER_BASE, \ + NAPI_MODULE_VERSION) + +#define NAPI_MODULE_INIT() \ + EXTERN_C_START \ + NAPI_MODULE_EXPORT napi_value \ + NAPI_MODULE_INITIALIZER(napi_env env, napi_value exports); \ + EXTERN_C_END \ + NAPI_MODULE(NODE_GYP_MODULE_NAME, NAPI_MODULE_INITIALIZER) \ + napi_value NAPI_MODULE_INITIALIZER(napi_env env, \ + napi_value exports) + #define NAPI_AUTO_LENGTH SIZE_MAX EXTERN_C_START diff --git a/src/node_internals.h b/src/node_internals.h index 50047e330724fe..b8acfa63c26ecf 100644 --- a/src/node_internals.h +++ b/src/node_internals.h @@ -33,6 +33,7 @@ #include "tracing/trace_event.h" #include "node_perf_common.h" #include "node_debug_options.h" +#include "node_api.h" #include #include @@ -840,6 +841,10 @@ static inline const char *errno_string(int errorno) { } // namespace node +void napi_module_register_by_symbol(v8::Local exports, + v8::Local module, + v8::Local context, + napi_addon_register_func init); #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS diff --git a/test/addons-napi/1_hello_world/binding.c b/test/addons-napi/1_hello_world/binding.c index 27d49079966d09..6efc14ee66e18f 100644 --- a/test/addons-napi/1_hello_world/binding.c +++ b/test/addons-napi/1_hello_world/binding.c @@ -10,10 +10,8 @@ napi_value Method(napi_env env, napi_callback_info info) { return world; } -napi_value Init(napi_env env, napi_value exports) { +NAPI_MODULE_INIT() { napi_property_descriptor desc = DECLARE_NAPI_PROPERTY("hello", Method); NAPI_CALL(env, napi_define_properties(env, exports, 1, &desc)); return exports; } - -NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) diff --git a/test/addons-napi/1_hello_world/test.js b/test/addons-napi/1_hello_world/test.js index c975c48a733f5c..d1d67d34f688c9 100644 --- a/test/addons-napi/1_hello_world/test.js +++ b/test/addons-napi/1_hello_world/test.js @@ -1,6 +1,13 @@ 'use strict'; const common = require('../../common'); const assert = require('assert'); -const addon = require(`./build/${common.buildType}/binding`); +const bindingPath = require.resolve(`./build/${common.buildType}/binding`); +const binding = require(bindingPath); +assert.strictEqual(binding.hello(), 'world'); +console.log('binding.hello() =', binding.hello()); -assert.strictEqual(addon.hello(), 'world'); +// Test multiple loading of the same module. +delete require.cache[bindingPath]; +const rebinding = require(bindingPath); +assert.strictEqual(rebinding.hello(), 'world'); +assert.notStrictEqual(binding.hello, rebinding.hello); From a4dae6c22671b19886c5b7c2b653aebdbaaa6e69 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Mon, 23 Apr 2018 09:14:32 +0200 Subject: [PATCH 002/173] src: prefer false instead of bool zero MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit updates node_crypto.cc VerifySpkac function to use false instead of 0 for its return bool value i. PR-URL: https://github.com/nodejs/node/pull/20218 Reviewed-By: Anna Henningsen Reviewed-By: Joyee Cheung Reviewed-By: Richard Lau Reviewed-By: Michaël Zasso Reviewed-By: Minwoo Jung Reviewed-By: Colin Ihrig Reviewed-By: James M Snell --- src/node_crypto.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 111227e665c000..970ec04f14530a 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -5148,7 +5148,7 @@ void GetCurves(const FunctionCallbackInfo& args) { bool VerifySpkac(const char* data, unsigned int len) { - bool i = 0; + bool i = false; EVP_PKEY* pkey = nullptr; NETSCAPE_SPKI* spki = nullptr; From bd2e52109652ee7b0fb84fa8ead462a03048df53 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Mon, 23 Apr 2018 11:16:45 +0200 Subject: [PATCH 003/173] src: rename return var in VerifySpkac functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit renames the verification result variable, that is currently named i, to verify_result. PR-URL: https://github.com/nodejs/node/pull/20218 Reviewed-By: Anna Henningsen Reviewed-By: Joyee Cheung Reviewed-By: Richard Lau Reviewed-By: Michaël Zasso Reviewed-By: Minwoo Jung Reviewed-By: Colin Ihrig Reviewed-By: James M Snell --- src/node_crypto.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 970ec04f14530a..8595dc6fb83058 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -5148,7 +5148,7 @@ void GetCurves(const FunctionCallbackInfo& args) { bool VerifySpkac(const char* data, unsigned int len) { - bool i = false; + bool verify_result = false; EVP_PKEY* pkey = nullptr; NETSCAPE_SPKI* spki = nullptr; @@ -5160,7 +5160,7 @@ bool VerifySpkac(const char* data, unsigned int len) { if (pkey == nullptr) goto exit; - i = NETSCAPE_SPKI_verify(spki, pkey) > 0; + verify_result = NETSCAPE_SPKI_verify(spki, pkey) > 0; exit: if (pkey != nullptr) @@ -5169,23 +5169,23 @@ bool VerifySpkac(const char* data, unsigned int len) { if (spki != nullptr) NETSCAPE_SPKI_free(spki); - return i; + return verify_result; } void VerifySpkac(const FunctionCallbackInfo& args) { - bool i = false; + bool verify_result = false; size_t length = Buffer::Length(args[0]); if (length == 0) - return args.GetReturnValue().Set(i); + return args.GetReturnValue().Set(verify_result); char* data = Buffer::Data(args[0]); CHECK_NE(data, nullptr); - i = VerifySpkac(data, length); + verify_result = VerifySpkac(data, length); - args.GetReturnValue().Set(i); + args.GetReturnValue().Set(verify_result); } From 9eacd66bcb21d8e3faf667b5e77ff0f1352f4a9b Mon Sep 17 00:00:00 2001 From: Kyle Farnung Date: Fri, 20 Apr 2018 18:41:20 -0700 Subject: [PATCH 004/173] lib: make sure `console` is writable The code currently assumes that `console` is already writable, but that's only if it was previously defined as writable. If it hasn't already been defined then the default value is false. Refs: https://github.com/nodejs/node/pull/17708 PR-URL: https://github.com/nodejs/node/pull/20185 Reviewed-By: Anna Henningsen Reviewed-By: Colin Ihrig Reviewed-By: Ruben Bridgewater Reviewed-By: Trivikram Kamat Reviewed-By: James M Snell --- lib/internal/bootstrap/node.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js index 7762aac84691d6..f9bed03d269fb2 100644 --- a/lib/internal/bootstrap/node.js +++ b/lib/internal/bootstrap/node.js @@ -356,7 +356,8 @@ Object.defineProperty(global, 'console', { configurable: true, enumerable: false, - value: wrappedConsole + value: wrappedConsole, + writable: true }); setupInspector(originalConsole, wrappedConsole, CJSModule); } From b5584c448ab3b5db13122a19c0988b08410b3274 Mon Sep 17 00:00:00 2001 From: Vse Mozhet Byt Date: Sat, 21 Apr 2018 05:41:16 +0300 Subject: [PATCH 005/173] tools: modernize and optimize doc/addon-verify.js Modernize: * Replace `var` with `const` / `let`. * Replace common functions with arrow functions. * Use destructuring. * Use `String.prototype.padStart()`, `String.prototype.endsWith()`. Optimize: * Reduce function calls. * Reduce intermediate variables. * Cache retrieved object properties. * Move RegExp declaration out of a cycle. * Simplify RegExps. * Replace RegExp with string when string suffices. * Remove conditions that cannot be false. * Replace for..in with `Object.keys().forEach()`. Also, eliminate needlessly complicated function chains: * `ondone` callback only checks errors; * if there is an error, it is called once and throws, then script exits; * if there are no errors, it is noop; * so there is no need to wrap it into `once()` function * and there is no need to call it without errors; * we can eliminate it and replace with `throw` where an error occurs; * we can also replace `onprogress` callback with `console.log` in place; * at last, we can eliminate `waiting` counter and `once()` utility. The new script produces results identical to the old ones. PR-URL: https://github.com/nodejs/node/pull/20188 Reviewed-By: Trivikram Kamat Reviewed-By: James M Snell --- tools/doc/addon-verify.js | 98 +++++++++++++++------------------------ 1 file changed, 37 insertions(+), 61 deletions(-) diff --git a/tools/doc/addon-verify.js b/tools/doc/addon-verify.js index 9fcc71ed93f0c9..a3d1beb4b8e12e 100644 --- a/tools/doc/addon-verify.js +++ b/tools/doc/addon-verify.js @@ -1,68 +1,52 @@ 'use strict'; -const fs = require('fs'); -const path = require('path'); -const marked = require('marked'); +const { mkdir, readFileSync, writeFile } = require('fs'); +const { resolve } = require('path'); +const { lexer } = require('marked'); -const rootDir = path.resolve(__dirname, '..', '..'); -const doc = path.resolve(rootDir, 'doc', 'api', 'addons.md'); -const verifyDir = path.resolve(rootDir, 'test', 'addons'); +const rootDir = resolve(__dirname, '..', '..'); +const doc = resolve(rootDir, 'doc', 'api', 'addons.md'); +const verifyDir = resolve(rootDir, 'test', 'addons'); -const contents = fs.readFileSync(doc).toString(); - -const tokens = marked.lexer(contents); +const tokens = lexer(readFileSync(doc, 'utf8')); +const addons = {}; let id = 0; - let currentHeader; -const addons = {}; -tokens.forEach((token) => { - if (token.type === 'heading' && token.text) { - currentHeader = token.text; - addons[currentHeader] = { - files: {} - }; + +const validNames = /^\/\/\s+(.*\.(?:cc|h|js))[\r\n]/; +tokens.forEach(({ type, text }) => { + if (type === 'heading') { + currentHeader = text; + addons[currentHeader] = { files: {} }; } - if (token.type === 'code') { - var match = token.text.match(/^\/\/\s+(.*\.(?:cc|h|js))[\r\n]/); + if (type === 'code') { + const match = text.match(validNames); if (match !== null) { - addons[currentHeader].files[match[1]] = token.text; + addons[currentHeader].files[match[1]] = text; } } }); -for (var header in addons) { - verifyFiles(addons[header].files, - header, - console.log.bind(null, 'wrote'), - function(err) { if (err) throw err; }); -} -function once(fn) { - var once = false; - return function() { - if (once) - return; - once = true; - fn.apply(this, arguments); - }; -} +Object.keys(addons).forEach((header) => { + verifyFiles(addons[header].files, header); +}); + +function verifyFiles(files, blockName) { + const fileNames = Object.keys(files); -function verifyFiles(files, blockName, onprogress, ondone) { // Must have a .cc and a .js to be a valid test. - if (!Object.keys(files).some((name) => /\.cc$/.test(name)) || - !Object.keys(files).some((name) => /\.js$/.test(name))) { + if (!fileNames.some((name) => name.endsWith('.cc')) || + !fileNames.some((name) => name.endsWith('.js'))) { return; } - blockName = blockName - .toLowerCase() - .replace(/\s/g, '_') - .replace(/[^a-z\d_]/g, ''); - const dir = path.resolve( + blockName = blockName.toLowerCase().replace(/\s/g, '_').replace(/\W/g, ''); + const dir = resolve( verifyDir, - `${(++id < 10 ? '0' : '') + id}_${blockName}` + `${String(++id).padStart(2, '0')}_${blockName}` ); - files = Object.keys(files).map(function(name) { + files = fileNames.map((name) => { if (name === 'test.js') { files[name] = `'use strict'; const common = require('../../common'); @@ -73,42 +57,34 @@ ${files[name].replace( `; } return { - path: path.resolve(dir, name), + path: resolve(dir, name), name: name, content: files[name] }; }); files.push({ - path: path.resolve(dir, 'binding.gyp'), + path: resolve(dir, 'binding.gyp'), content: JSON.stringify({ targets: [ { target_name: 'addon', defines: [ 'V8_DEPRECATION_WARNINGS=1' ], - sources: files.map(function(file) { - return file.name; - }) + sources: files.map(({ name }) => name) } ] }) }); - fs.mkdir(dir, function() { + mkdir(dir, () => { // Ignore errors. - const done = once(ondone); - var waiting = files.length; - files.forEach(function(file) { - fs.writeFile(file.path, file.content, function(err) { + files.forEach(({ path, content }) => { + writeFile(path, content, (err) => { if (err) - return done(err); - - if (onprogress) - onprogress(file.path); + throw err; - if (--waiting === 0) - done(); + console.log(`Wrote ${path}`); }); }); }); From c5b34590031472fac421b4b2095b94bd96a60430 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Fri, 20 Apr 2018 22:45:31 -0700 Subject: [PATCH 006/173] build: use -9 with `kill` in Makefile Fixes: https://github.com/nodejs/node/issues/20194 PR-URL: https://github.com/nodejs/node/pull/20195 Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: Luigi Pinca Reviewed-By: Anna Henningsen Reviewed-By: Colin Ihrig Reviewed-By: Ruben Bridgewater --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index f499788d9d86cc..6736d601685dce 100644 --- a/Makefile +++ b/Makefile @@ -393,7 +393,7 @@ clear-stalled: ps awwx | grep Release/node | grep -v grep | cat @PS_OUT=`ps awwx | grep Release/node | grep -v grep | awk '{print $$1}'`; \ if [ "$${PS_OUT}" ]; then \ - echo $${PS_OUT} | xargs kill; \ + echo $${PS_OUT} | xargs kill -9; \ fi .PHONY: test-gc @@ -439,7 +439,7 @@ test-ci-js: | clear-stalled ps awwx | grep Release/node | grep -v grep | cat @PS_OUT=`ps awwx | grep Release/node | grep -v grep | awk '{print $$1}'`; \ if [ "$${PS_OUT}" ]; then \ - echo $${PS_OUT} | xargs kill; exit 1; \ + echo $${PS_OUT} | xargs kill -9; exit 1; \ fi .PHONY: test-ci @@ -454,7 +454,7 @@ test-ci: | clear-stalled build-addons build-addons-napi doc-only ps awwx | grep Release/node | grep -v grep | cat @PS_OUT=`ps awwx | grep Release/node | grep -v grep | awk '{print $$1}'`; \ if [ "$${PS_OUT}" ]; then \ - echo $${PS_OUT} | xargs kill; exit 1; \ + echo $${PS_OUT} | xargs kill -9; exit 1; \ fi .PHONY: build-ci From 3bc5353110eade297ed80fa6d4005a06964f1de2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Nie=C3=9Fen?= Date: Tue, 24 Apr 2018 22:03:12 +0200 Subject: [PATCH 007/173] doc: fix spelling of API name in 10.0.0 changelog PR-URL: https://github.com/nodejs/node/pull/20257 Refs: https://github.com/nodejs/node/pull/19403 Reviewed-By: Luigi Pinca Reviewed-By: James M Snell Reviewed-By: Rich Trott Reviewed-By: Gus Caplan Reviewed-By: Michael Dawson --- doc/changelogs/CHANGELOG_V10.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/changelogs/CHANGELOG_V10.md b/doc/changelogs/CHANGELOG_V10.md index 1f027679b3bf83..2ec64e147f94f5 100644 --- a/doc/changelogs/CHANGELOG_V10.md +++ b/doc/changelogs/CHANGELOG_V10.md @@ -58,7 +58,7 @@ * EventEmitter * The `EventEmitter.prototype.off()` method has been added as an alias for `EventEmitter.prototype.removeListener()`. [[`3bb6f07d52`](https://github.com/nodejs/node/commit/3bb6f07d52)] * File System - * The `fs.promises` API provides experimental promisified versions of the `fs` functions. [[`329fc78e49`](https://github.com/nodejs/node/commit/329fc78e49)] + * The `fs/promises` API provides experimental promisified versions of the `fs` functions. [[`329fc78e49`](https://github.com/nodejs/node/commit/329fc78e49)] * Invalid path errors are now thrown synchronously. [[`d8f73385e2`](https://github.com/nodejs/node/commit/d8f73385e2)] * The `fs.readFile()` method now partitions reads to avoid thread pool exhaustion. [[`67a4ce1c6e`](https://github.com/nodejs/node/commit/67a4ce1c6e)] * HTTP @@ -88,7 +88,7 @@ * Timers * The `enroll()` and `unenroll()` methods have been deprecated. [[`68783ae0b8`](https://github.com/nodejs/node/commit/68783ae0b8)] * TLS - * The `tls.convertNONProtocols()` method has been deprecated. [[`9204a0db6e`](https://github.com/nodejs/node/commit/9204a0db6e)] + * The `tls.convertNPNProtocols()` method has been deprecated. [[`9204a0db6e`](https://github.com/nodejs/node/commit/9204a0db6e)] * Support for NPN (next protocol negotiation) has been dropped. [[`5bfbe5ceae`](https://github.com/nodejs/node/commit/5bfbe5ceae)] * The `ecdhCurve` default is now `'auto'`. [[`af78840b19`](https://github.com/nodejs/node/commit/af78840b19)] * Trace Events From 26525ef5ab865f9881085ae2e806252deff01cda Mon Sep 17 00:00:00 2001 From: Vse Mozhet Byt Date: Wed, 25 Apr 2018 01:33:14 +0300 Subject: [PATCH 008/173] doc: fix typos in doc/changelogs/CHANGELOG_V10.md PR-URL: https://github.com/nodejs/node/pull/20265 Reviewed-By: Gus Caplan Reviewed-By: Ruben Bridgewater --- doc/changelogs/CHANGELOG_V10.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/changelogs/CHANGELOG_V10.md b/doc/changelogs/CHANGELOG_V10.md index 2ec64e147f94f5..b3d4a008203c14 100644 --- a/doc/changelogs/CHANGELOG_V10.md +++ b/doc/changelogs/CHANGELOG_V10.md @@ -92,7 +92,7 @@ * Support for NPN (next protocol negotiation) has been dropped. [[`5bfbe5ceae`](https://github.com/nodejs/node/commit/5bfbe5ceae)] * The `ecdhCurve` default is now `'auto'`. [[`af78840b19`](https://github.com/nodejs/node/commit/af78840b19)] * Trace Events - * A new `trace_events` top-level module allows trace event categories to be enabled/disabld at runtime. [[`da5d818a54`](https://github.com/nodejs/node/commit/da5d818a54)] + * A new `trace_events` top-level module allows trace event categories to be enabled/disabled at runtime. [[`da5d818a54`](https://github.com/nodejs/node/commit/da5d818a54)] * URL * The WHATWG URL API is now a global. [[`312414662b`](https://github.com/nodejs/node/commit/312414662b)] * Util @@ -113,7 +113,7 @@ The following APIs have been deprecated in Node.js 10.0.0 * Previously deprecated internal getters/setters on `net.Server` has reached end-of-life and have been removed. [[`3701b02309`](https://github.com/nodejs/node/commit/3701b02309)] * Use of non-string values for `process.env` has been deprecated in documentation. [[`5826fe4e79`](https://github.com/nodejs/node/commit/5826fe4e79)] * Use of `process.assert()` will emit a runtime deprecation warning. [[`703e37cf3f`](https://github.com/nodejs/node/commit/703e37cf3f)] -* Previously deprecated `NODE\_REPL\_HISTORY\_FILE` environment variable has reached end-of-life and has been removed. [[`60c9ad7979`](https://github.com/nodejs/node/commit/60c9ad7979)] +* Previously deprecated `NODE_REPL_HISTORY_FILE` environment variable has reached end-of-life and has been removed. [[`60c9ad7979`](https://github.com/nodejs/node/commit/60c9ad7979)] * Use of the `timers.enroll()` and `timers.unenroll()` methods will emit a runtime deprecation warning. [[`68783ae0b8`](https://github.com/nodejs/node/commit/68783ae0b8)] * Use of the `tls.convertNPNProtocols()` method will emit a runtime deprecation warning. Support for NPN has been removed from Node.js. [[`9204a0db6e`](https://github.com/nodejs/node/commit/9204a0db6e)] * The `crypto.fips` property has been deprecated in documentation. [[`6e7992e8b8`](https://github.com/nodejs/node/commit/6e7992e8b8)] @@ -138,7 +138,7 @@ The following APIs have been deprecated in Node.js 10.0.0 * [[`876836b135`](https://github.com/nodejs/node/commit/876836b135)] - **(SEMVER-MAJOR)** **benchmark**: rename file (Ruben Bridgewater) [#18790](https://github.com/nodejs/node/pull/18790) * [[`e9ec9ff269`](https://github.com/nodejs/node/commit/e9ec9ff269)] - **(SEMVER-MAJOR)** **benchmark**: add buffer fill benchmark (Ruben Bridgewater) [#18790](https://github.com/nodejs/node/pull/18790) * [[`94d64877ff`](https://github.com/nodejs/node/commit/94d64877ff)] - **(SEMVER-MAJOR)** **benchmark**: improve buffer.readInt(B|L)E benchmarks (Rich Trott) [#11146](https://github.com/nodejs/node/pull/11146) -* [[`9d4ab90117`](https://github.com/nodejs/node/commit/9d4ab90117)] - **(SEMVER-MAJOR)** **buffer**: do deprecation warning outside `node\_modules` (Anna Henningsen) [#19524](https://github.com/nodejs/node/pull/19524) +* [[`9d4ab90117`](https://github.com/nodejs/node/commit/9d4ab90117)] - **(SEMVER-MAJOR)** **buffer**: do deprecation warning outside `node_modules` (Anna Henningsen) [#19524](https://github.com/nodejs/node/pull/19524) * [[`e8bb1f35df`](https://github.com/nodejs/node/commit/e8bb1f35df)] - **(SEMVER-MAJOR)** **buffer**: refactor all read/write functions (Ruben Bridgewater) [#18395](https://github.com/nodejs/node/pull/18395) * [[`a6c490cc8e`](https://github.com/nodejs/node/commit/a6c490cc8e)] - **(SEMVER-MAJOR)** **buffer**: remove double ln (Ruben Bridgewater) [#18395](https://github.com/nodejs/node/pull/18395) * [[`1411b30f46`](https://github.com/nodejs/node/commit/1411b30f46)] - **(SEMVER-MAJOR)** **buffer**: move c++ float functions to js (Ruben Bridgewater) [#18395](https://github.com/nodejs/node/pull/18395) @@ -710,12 +710,12 @@ The following APIs have been deprecated in Node.js 10.0.0 * [[`070a82e82c`](https://github.com/nodejs/node/commit/070a82e82c)] - **module**: replace "magic" numbers by constants (Sergey Golovin) [#18869](https://github.com/nodejs/node/pull/18869) * [[`c86fe511f4`](https://github.com/nodejs/node/commit/c86fe511f4)] - **module**: replace magic numbers by constants (Sergey Golovin) [#18785](https://github.com/nodejs/node/pull/18785) * [[`3b9cc424a4`](https://github.com/nodejs/node/commit/3b9cc424a4)] - **module**: remove unused code in module.js (Rich Trott) [#18768](https://github.com/nodejs/node/pull/18768) -* [[`c529168249`](https://github.com/nodejs/node/commit/c529168249)] - **n-api**: add more `int64\_t` tests (Kyle Farnung) [#19402](https://github.com/nodejs/node/pull/19402) +* [[`c529168249`](https://github.com/nodejs/node/commit/c529168249)] - **n-api**: add more `int64_t` tests (Kyle Farnung) [#19402](https://github.com/nodejs/node/pull/19402) * [[`a342cd693c`](https://github.com/nodejs/node/commit/a342cd693c)] - **net**: honor default values in Socket constructor (Santiago Gimeno) [#19971](https://github.com/nodejs/node/pull/19971) * [[`923fb5cc18`](https://github.com/nodejs/node/commit/923fb5cc18)] - **net**: track bytesWritten in C++ land (Anna Henningsen) [#19551](https://github.com/nodejs/node/pull/19551) * [[`7c73cd4c70`](https://github.com/nodejs/node/commit/7c73cd4c70)] - **net**: emit error on invalid address family (cjihrig) [#19415](https://github.com/nodejs/node/pull/19415) * [[`67b5985c08`](https://github.com/nodejs/node/commit/67b5985c08)] - **net**: fix usage of writeBuffer in makeSyncWrite (Joyee Cheung) [#19103](https://github.com/nodejs/node/pull/19103) -* [[`03ddd13d8a`](https://github.com/nodejs/node/commit/03ddd13d8a)] - **net**: use `\_final` instead of `on('finish')` (Anna Henningsen) [#18608](https://github.com/nodejs/node/pull/18608) +* [[`03ddd13d8a`](https://github.com/nodejs/node/commit/03ddd13d8a)] - **net**: use `_final` instead of `on('finish')` (Anna Henningsen) [#18608](https://github.com/nodejs/node/pull/18608) * [[`e85c20b511`](https://github.com/nodejs/node/commit/e85c20b511)] - **net,http2**: merge write error handling & property names (Anna Henningsen) [#19734](https://github.com/nodejs/node/pull/19734) * [[`496d6023e0`](https://github.com/nodejs/node/commit/496d6023e0)] - **net,stream**: remove DuplexBase (Luigi Pinca) [#19779](https://github.com/nodejs/node/pull/19779) * [[`2ec6995555`](https://github.com/nodejs/node/commit/2ec6995555)] - **perf_hooks**: simplify perf\_hooks (James M Snell) [#19563](https://github.com/nodejs/node/pull/19563) From 99e0b913c62ccd31ad11292cf4fd153b1e6c1467 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Mon, 23 Apr 2018 14:54:23 +0200 Subject: [PATCH 009/173] test: add checkMethods function for Certificate This commit adds a checkMethods function so that it can be reused to avoid duplicating the same code for instance methods, and static methods of the Certificate object. PR-URL: https://github.com/nodejs/node/pull/20224 Reviewed-By: Ruben Bridgewater Reviewed-By: James M Snell Reviewed-By: Trivikram Kamat --- test/parallel/test-crypto-certificate.js | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/test/parallel/test-crypto-certificate.js b/test/parallel/test-crypto-certificate.js index f94c82474e95aa..3252e53aa4fd09 100644 --- a/test/parallel/test-crypto-certificate.js +++ b/test/parallel/test-crypto-certificate.js @@ -36,9 +36,7 @@ const spkacValid = fixtures.readSync('spkac.valid'); const spkacFail = fixtures.readSync('spkac.fail'); const spkacPem = fixtures.readSync('spkac.pem'); -{ - // Test instance methods - const certificate = new Certificate(); +function checkMethods(certificate) { assert.strictEqual(certificate.verifySpkac(spkacValid), true); assert.strictEqual(certificate.verifySpkac(spkacFail), false); @@ -57,21 +55,13 @@ const spkacPem = fixtures.readSync('spkac.pem'); } { - // Test static methods - assert.strictEqual(Certificate.verifySpkac(spkacValid), true); - assert.strictEqual(Certificate.verifySpkac(spkacFail), false); - - assert.strictEqual( - stripLineEndings(Certificate.exportPublicKey(spkacValid).toString('utf8')), - stripLineEndings(spkacPem.toString('utf8')) - ); - assert.strictEqual(Certificate.exportPublicKey(spkacFail), ''); + // Test instance methods + checkMethods(new Certificate()); +} - assert.strictEqual( - Certificate.exportChallenge(spkacValid).toString('utf8'), - 'fb9ab814-6677-42a4-a60c-f905d1a6924d' - ); - assert.strictEqual(Certificate.exportChallenge(spkacFail), ''); +{ + // Test static methods + checkMethods(Certificate); } function stripLineEndings(obj) { From 6bf816fde2b9c9b947204ad3588dd4808956431a Mon Sep 17 00:00:00 2001 From: Ulan Degenbaev Date: Thu, 12 Apr 2018 22:01:11 +0200 Subject: [PATCH 010/173] src: limit foreground tasks draining loop Foreground tasks that repost themselves can force the draining loop to run indefinitely long without giving other tasks chance to run. This limits the foreground task draining loop to run only the tasks that were in the tasks queue at the beginning of the loop. PR-URL: https://github.com/nodejs/node/pull/19987 Fixes: https://github.com/nodejs/node/issues/19937 Reviewed-By: Anna Henningsen Reviewed-By: James M Snell Reviewed-By: Yang Guo Reviewed-By: Colin Ihrig Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: Ben Noordhuis Reviewed-By: Anatoli Papirovski Reviewed-By: Khaidi Chu --- node.gyp | 1 + src/inspector_agent.cc | 2 +- src/node_platform.cc | 22 ++++++++++++--- src/node_platform.h | 10 +++++-- test/cctest/test_platform.cc | 55 ++++++++++++++++++++++++++++++++++++ 5 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 test/cctest/test_platform.cc diff --git a/node.gyp b/node.gyp index 8347beb18245ca..abed8ad4c48c10 100644 --- a/node.gyp +++ b/node.gyp @@ -961,6 +961,7 @@ 'test/cctest/test_base64.cc', 'test/cctest/test_node_postmortem_metadata.cc', 'test/cctest/test_environment.cc', + 'test/cctest/test_platform.cc', 'test/cctest/test_util.cc', 'test/cctest/test_url.cc' ], diff --git a/src/inspector_agent.cc b/src/inspector_agent.cc index e143d316d2e6fa..fffaecdef3ddfa 100644 --- a/src/inspector_agent.cc +++ b/src/inspector_agent.cc @@ -316,7 +316,7 @@ class NodeInspectorClient : public V8InspectorClient { terminated_ = false; running_nested_loop_ = true; while (!terminated_ && channel_->waitForFrontendMessage()) { - platform_->FlushForegroundTasks(env_->isolate()); + while (platform_->FlushForegroundTasks(env_->isolate())) {} } terminated_ = false; running_nested_loop_ = false; diff --git a/src/node_platform.cc b/src/node_platform.cc index d96db086925c01..b8f1344727cfd6 100644 --- a/src/node_platform.cc +++ b/src/node_platform.cc @@ -95,7 +95,7 @@ void PerIsolatePlatformData::PostDelayedTask( } PerIsolatePlatformData::~PerIsolatePlatformData() { - FlushForegroundTasksInternal(); + while (FlushForegroundTasksInternal()) {} CancelPendingDelayedTasks(); uv_close(reinterpret_cast(flush_tasks_), @@ -223,7 +223,13 @@ bool PerIsolatePlatformData::FlushForegroundTasksInternal() { }); }); } - while (std::unique_ptr task = foreground_tasks_.Pop()) { + // Move all foreground tasks into a separate queue and flush that queue. + // This way tasks that are posted while flushing the queue will be run on the + // next call of FlushForegroundTasksInternal. + std::queue> tasks = foreground_tasks_.PopAll(); + while (!tasks.empty()) { + std::unique_ptr task = std::move(tasks.front()); + tasks.pop(); did_work = true; RunForegroundTask(std::move(task)); } @@ -254,8 +260,8 @@ void NodePlatform::CallDelayedOnForegroundThread(Isolate* isolate, std::unique_ptr(task), delay_in_seconds); } -void NodePlatform::FlushForegroundTasks(v8::Isolate* isolate) { - ForIsolate(isolate)->FlushForegroundTasksInternal(); +bool NodePlatform::FlushForegroundTasks(v8::Isolate* isolate) { + return ForIsolate(isolate)->FlushForegroundTasksInternal(); } void NodePlatform::CancelPendingDelayedTasks(v8::Isolate* isolate) { @@ -348,4 +354,12 @@ void TaskQueue::Stop() { tasks_available_.Broadcast(scoped_lock); } +template +std::queue> TaskQueue::PopAll() { + Mutex::ScopedLock scoped_lock(lock_); + std::queue> result; + result.swap(task_queue_); + return result; +} + } // namespace node diff --git a/src/node_platform.h b/src/node_platform.h index b7546057871a1d..8f6ff89f491fe3 100644 --- a/src/node_platform.h +++ b/src/node_platform.h @@ -26,6 +26,7 @@ class TaskQueue { void Push(std::unique_ptr task); std::unique_ptr Pop(); std::unique_ptr BlockingPop(); + std::queue> PopAll(); void NotifyOfCompletion(); void BlockingDrain(); void Stop(); @@ -65,7 +66,9 @@ class PerIsolatePlatformData : void ref(); int unref(); - // Returns true iff work was dispatched or executed. + // Returns true if work was dispatched or executed. New tasks that are + // posted during flushing of the queue are postponed until the next + // flushing. bool FlushForegroundTasksInternal(); void CancelPendingDelayedTasks(); @@ -130,7 +133,10 @@ class NodePlatform : public MultiIsolatePlatform { double CurrentClockTimeMillis() override; v8::TracingController* GetTracingController() override; - void FlushForegroundTasks(v8::Isolate* isolate); + // Returns true if work was dispatched or executed. New tasks that are + // posted during flushing of the queue are postponed until the next + // flushing. + bool FlushForegroundTasks(v8::Isolate* isolate); void RegisterIsolate(IsolateData* isolate_data, uv_loop_t* loop) override; void UnregisterIsolate(IsolateData* isolate_data) override; diff --git a/test/cctest/test_platform.cc b/test/cctest/test_platform.cc new file mode 100644 index 00000000000000..876547480b7032 --- /dev/null +++ b/test/cctest/test_platform.cc @@ -0,0 +1,55 @@ +#include "node_internals.h" +#include "libplatform/libplatform.h" + +#include +#include "gtest/gtest.h" +#include "node_test_fixture.h" + +// This task increments the given run counter and reposts itself until the +// repost counter reaches zero. +class RepostingTask : public v8::Task { + public: + explicit RepostingTask(int repost_count, + int* run_count, + v8::Isolate* isolate, + node::NodePlatform* platform) + : repost_count_(repost_count), + run_count_(run_count), + isolate_(isolate), + platform_(platform) {} + + // v8::Task implementation + void Run() final { + ++*run_count_; + if (repost_count_ > 0) { + --repost_count_; + platform_->CallOnForegroundThread(isolate_, + new RepostingTask(repost_count_, run_count_, isolate_, platform_)); + } + } + + private: + int repost_count_; + int* run_count_; + v8::Isolate* isolate_; + node::NodePlatform* platform_; +}; + +class PlatformTest : public EnvironmentTestFixture {}; + +TEST_F(PlatformTest, SkipNewTasksInFlushForegroundTasks) { + v8::Isolate::Scope isolate_scope(isolate_); + const v8::HandleScope handle_scope(isolate_); + const Argv argv; + Env env {handle_scope, argv}; + int run_count = 0; + platform->CallOnForegroundThread( + isolate_, new RepostingTask(2, &run_count, isolate_, platform.get())); + EXPECT_TRUE(platform->FlushForegroundTasks(isolate_)); + EXPECT_EQ(1, run_count); + EXPECT_TRUE(platform->FlushForegroundTasks(isolate_)); + EXPECT_EQ(2, run_count); + EXPECT_TRUE(platform->FlushForegroundTasks(isolate_)); + EXPECT_EQ(3, run_count); + EXPECT_FALSE(platform->FlushForegroundTasks(isolate_)); +} From 171cbb1c6423714998351c9c3c0e6145481335bf Mon Sep 17 00:00:00 2001 From: Hackzzila Date: Tue, 24 Apr 2018 21:14:12 -0500 Subject: [PATCH 011/173] doc: fix net.Socket link inconsistencies PR-URL: https://github.com/nodejs/node/pull/20271 Reviewed-By: Vse Mozhet Byt Reviewed-By: Rich Trott Reviewed-By: Trivikram Kamat Reviewed-By: Luigi Pinca --- doc/api/tty.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/api/tty.md b/doc/api/tty.md index 193005c017dda7..f8bc4feec3e86d 100644 --- a/doc/api/tty.md +++ b/doc/api/tty.md @@ -77,8 +77,8 @@ Note that `CTRL`+`C` will no longer cause a `SIGINT` when in this mode. added: v0.5.8 --> -The `tty.WriteStream` class is a subclass of `net.Socket` that represents the -writable side of a TTY. In normal circumstances, [`process.stdout`][] and +The `tty.WriteStream` class is a subclass of [`net.Socket`][] that represents +the writable side of a TTY. In normal circumstances, [`process.stdout`][] and [`process.stderr`][] will be the only `tty.WriteStream` instances created for a Node.js process and there should be no reason to create additional instances. From 3bf736e569bd3fafe82a63e88c7adc644ba0a39b Mon Sep 17 00:00:00 2001 From: Zachary Vacura Date: Wed, 25 Apr 2018 01:33:01 -0500 Subject: [PATCH 012/173] doc: update pull request template in guide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/20277 Refs: https://github.com/nodejs/node/pull/19125 Reviewed-By: Tobias Nießen Reviewed-By: Vse Mozhet Byt Reviewed-By: Luigi Pinca --- doc/guides/contributing/pull-requests.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/doc/guides/contributing/pull-requests.md b/doc/guides/contributing/pull-requests.md index f481a2cacb9f01..c248c1b9b6ec6f 100644 --- a/doc/guides/contributing/pull-requests.md +++ b/doc/guides/contributing/pull-requests.md @@ -334,9 +334,6 @@ Contributors guide: https://github.com/nodejs/node/blob/master/CONTRIBUTING.md - [ ] tests and/or benchmarks are included - [ ] documentation is changed or added - [ ] commit message follows [commit guidelines](https://github.com/nodejs/node/blob/master/doc/guides/contributing/pull-requests.md#commit-message-guidelines) - -#### Affected core subsystem(s) - ``` Please try to do your best at filling out the details, but feel free to skip From d4b19cf43fd61c04f6186b0aaf27aca4a0f2b34a Mon Sep 17 00:00:00 2001 From: Gabriel Schulhof Date: Mon, 23 Apr 2018 22:31:20 -0400 Subject: [PATCH 013/173] test,n-api: re-write test_error in C PR-URL: https://github.com/nodejs/node/pull/20244 Reviewed-By: Daniel Bevenius Reviewed-By: James M Snell Reviewed-By: Anna Henningsen Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: Colin Ihrig Reviewed-By: Trivikram Kamat --- test/addons-napi/test_error/binding.gyp | 2 +- .../{test_error.cc => test_error.c} | 30 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) rename test/addons-napi/test_error/{test_error.cc => test_error.c} (87%) diff --git a/test/addons-napi/test_error/binding.gyp b/test/addons-napi/test_error/binding.gyp index c2defd9551a31b..2923e15adca1a1 100644 --- a/test/addons-napi/test_error/binding.gyp +++ b/test/addons-napi/test_error/binding.gyp @@ -2,7 +2,7 @@ "targets": [ { "target_name": "test_error", - "sources": [ "test_error.cc" ] + "sources": [ "test_error.c" ] } ] } diff --git a/test/addons-napi/test_error/test_error.cc b/test/addons-napi/test_error/test_error.c similarity index 87% rename from test/addons-napi/test_error/test_error.cc rename to test/addons-napi/test_error/test_error.c index 4ab20bd7522a3b..1cad38098c9917 100644 --- a/test/addons-napi/test_error/test_error.cc +++ b/test/addons-napi/test_error/test_error.c @@ -4,7 +4,7 @@ napi_value checkError(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; - NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, nullptr, nullptr)); + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); bool r; NAPI_CALL(env, napi_is_error(env, args[0], &r)); @@ -20,43 +20,43 @@ napi_value throwExistingError(napi_env env, napi_callback_info info) { napi_value error; NAPI_CALL(env, napi_create_string_utf8( env, "existing error", NAPI_AUTO_LENGTH, &message)); - NAPI_CALL(env, napi_create_error(env, nullptr, message, &error)); + NAPI_CALL(env, napi_create_error(env, NULL, message, &error)); NAPI_CALL(env, napi_throw(env, error)); - return nullptr; + return NULL; } napi_value throwError(napi_env env, napi_callback_info info) { - NAPI_CALL(env, napi_throw_error(env, nullptr, "error")); - return nullptr; + NAPI_CALL(env, napi_throw_error(env, NULL, "error")); + return NULL; } napi_value throwRangeError(napi_env env, napi_callback_info info) { - NAPI_CALL(env, napi_throw_range_error(env, nullptr, "range error")); - return nullptr; + NAPI_CALL(env, napi_throw_range_error(env, NULL, "range error")); + return NULL; } napi_value throwTypeError(napi_env env, napi_callback_info info) { - NAPI_CALL(env, napi_throw_type_error(env, nullptr, "type error")); - return nullptr; + NAPI_CALL(env, napi_throw_type_error(env, NULL, "type error")); + return NULL; } napi_value throwErrorCode(napi_env env, napi_callback_info info) { NAPI_CALL(env, napi_throw_error(env, "ERR_TEST_CODE", "Error [error]")); - return nullptr; + return NULL; } napi_value throwRangeErrorCode(napi_env env, napi_callback_info info) { NAPI_CALL(env, napi_throw_range_error(env, "ERR_TEST_CODE", "RangeError [range error]")); - return nullptr; + return NULL; } napi_value throwTypeErrorCode(napi_env env, napi_callback_info info) { NAPI_CALL(env, napi_throw_type_error(env, "ERR_TEST_CODE", "TypeError [type error]")); - return nullptr; + return NULL; } @@ -65,7 +65,7 @@ napi_value createError(napi_env env, napi_callback_info info) { napi_value message; NAPI_CALL(env, napi_create_string_utf8( env, "error", NAPI_AUTO_LENGTH, &message)); - NAPI_CALL(env, napi_create_error(env, nullptr, message, &result)); + NAPI_CALL(env, napi_create_error(env, NULL, message, &result)); return result; } @@ -74,7 +74,7 @@ napi_value createRangeError(napi_env env, napi_callback_info info) { napi_value message; NAPI_CALL(env, napi_create_string_utf8( env, "range error", NAPI_AUTO_LENGTH, &message)); - NAPI_CALL(env, napi_create_range_error(env, nullptr, message, &result)); + NAPI_CALL(env, napi_create_range_error(env, NULL, message, &result)); return result; } @@ -83,7 +83,7 @@ napi_value createTypeError(napi_env env, napi_callback_info info) { napi_value message; NAPI_CALL(env, napi_create_string_utf8( env, "type error", NAPI_AUTO_LENGTH, &message)); - NAPI_CALL(env, napi_create_type_error(env, nullptr, message, &result)); + NAPI_CALL(env, napi_create_type_error(env, NULL, message, &result)); return result; } From b239591ed8ddbfb073aa522dd68b2e25f805dc05 Mon Sep 17 00:00:00 2001 From: Gabriel Schulhof Date: Mon, 23 Apr 2018 22:20:47 -0400 Subject: [PATCH 014/173] n-api,test: make methods static PR-URL: https://github.com/nodejs/node/pull/20243 Reviewed-By: Colin Ihrig Reviewed-By: Trivikram Kamat --- test/addons-napi/1_hello_world/binding.c | 2 +- .../2_function_arguments/binding.c | 4 +-- test/addons-napi/3_callbacks/binding.c | 6 ++-- test/addons-napi/4_object_factory/binding.c | 4 +-- test/addons-napi/5_function_factory/binding.c | 6 ++-- test/addons-napi/test_array/test_array.c | 12 +++---- test/addons-napi/test_buffer/test_buffer.c | 16 ++++----- .../test_constructor/test_constructor.c | 12 +++---- .../test_constructor/test_constructor_name.c | 4 +-- .../test_conversions/test_conversions.c | 22 ++++++------ .../addons-napi/test_dataview/test_dataview.c | 6 ++-- .../test_env_sharing/compare_env.c | 4 +-- test/addons-napi/test_env_sharing/store_env.c | 2 +- test/addons-napi/test_fatal/test_fatal.c | 6 ++-- .../test_fatal_exception.c | 4 +-- .../addons-napi/test_function/test_function.c | 6 ++-- test/addons-napi/test_general/test_general.c | 36 +++++++++---------- .../test_handle_scope/test_handle_scope.c | 10 +++--- test/addons-napi/test_make_callback/binding.c | 3 +- test/addons-napi/test_new_target/binding.c | 8 ++--- test/addons-napi/test_number/test_number.c | 8 ++--- test/addons-napi/test_object/test_object.c | 20 +++++------ test/addons-napi/test_promise/test_promise.c | 9 ++--- .../test_properties/test_properties.c | 10 +++--- .../test_reference/test_reference.c | 21 +++++------ test/addons-napi/test_string/test_string.c | 21 +++++------ test/addons-napi/test_symbol/test_symbol.c | 6 ++-- .../test_typedarray/test_typedarray.c | 8 ++--- 28 files changed, 139 insertions(+), 137 deletions(-) diff --git a/test/addons-napi/1_hello_world/binding.c b/test/addons-napi/1_hello_world/binding.c index 6efc14ee66e18f..02cd5dd2f19418 100644 --- a/test/addons-napi/1_hello_world/binding.c +++ b/test/addons-napi/1_hello_world/binding.c @@ -2,7 +2,7 @@ #include "../common.h" #include -napi_value Method(napi_env env, napi_callback_info info) { +static napi_value Method(napi_env env, napi_callback_info info) { napi_value world; const char* str = "world"; size_t str_len = strlen(str); diff --git a/test/addons-napi/2_function_arguments/binding.c b/test/addons-napi/2_function_arguments/binding.c index c45ca0871db8ec..7d88c3d9e4ff19 100644 --- a/test/addons-napi/2_function_arguments/binding.c +++ b/test/addons-napi/2_function_arguments/binding.c @@ -1,7 +1,7 @@ #include #include "../common.h" -napi_value Add(napi_env env, napi_callback_info info) { +static napi_value Add(napi_env env, napi_callback_info info) { size_t argc = 2; napi_value args[2]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -29,7 +29,7 @@ napi_value Add(napi_env env, napi_callback_info info) { return sum; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor desc = DECLARE_NAPI_PROPERTY("add", Add); NAPI_CALL(env, napi_define_properties(env, exports, 1, &desc)); return exports; diff --git a/test/addons-napi/3_callbacks/binding.c b/test/addons-napi/3_callbacks/binding.c index 7ebacf1d0653e9..1c0dd8126ce4ef 100644 --- a/test/addons-napi/3_callbacks/binding.c +++ b/test/addons-napi/3_callbacks/binding.c @@ -2,7 +2,7 @@ #include "../common.h" #include -napi_value RunCallback(napi_env env, napi_callback_info info) { +static napi_value RunCallback(napi_env env, napi_callback_info info) { size_t argc = 2; napi_value args[2]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -34,7 +34,7 @@ napi_value RunCallback(napi_env env, napi_callback_info info) { return NULL; } -napi_value RunCallbackWithRecv(napi_env env, napi_callback_info info) { +static napi_value RunCallbackWithRecv(napi_env env, napi_callback_info info) { size_t argc = 2; napi_value args[2]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -45,7 +45,7 @@ napi_value RunCallbackWithRecv(napi_env env, napi_callback_info info) { return NULL; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor desc[2] = { DECLARE_NAPI_PROPERTY("RunCallback", RunCallback), DECLARE_NAPI_PROPERTY("RunCallbackWithRecv", RunCallbackWithRecv), diff --git a/test/addons-napi/4_object_factory/binding.c b/test/addons-napi/4_object_factory/binding.c index 38b8ec8e1cab48..0ed95e93512a0b 100644 --- a/test/addons-napi/4_object_factory/binding.c +++ b/test/addons-napi/4_object_factory/binding.c @@ -1,7 +1,7 @@ #include #include "../common.h" -napi_value CreateObject(napi_env env, napi_callback_info info) { +static napi_value CreateObject(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -14,7 +14,7 @@ napi_value CreateObject(napi_env env, napi_callback_info info) { return obj; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { NAPI_CALL(env, napi_create_function(env, "exports", -1, CreateObject, NULL, &exports)); return exports; diff --git a/test/addons-napi/5_function_factory/binding.c b/test/addons-napi/5_function_factory/binding.c index 8cc41f6aac5c3d..19460b9ddc55f2 100644 --- a/test/addons-napi/5_function_factory/binding.c +++ b/test/addons-napi/5_function_factory/binding.c @@ -1,20 +1,20 @@ #include #include "../common.h" -napi_value MyFunction(napi_env env, napi_callback_info info) { +static napi_value MyFunction(napi_env env, napi_callback_info info) { napi_value str; NAPI_CALL(env, napi_create_string_utf8(env, "hello world", -1, &str)); return str; } -napi_value CreateFunction(napi_env env, napi_callback_info info) { +static napi_value CreateFunction(napi_env env, napi_callback_info info) { napi_value fn; NAPI_CALL(env, napi_create_function(env, "theFunction", -1, MyFunction, NULL, &fn)); return fn; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { NAPI_CALL(env, napi_create_function(env, "exports", -1, CreateFunction, NULL, &exports)); return exports; diff --git a/test/addons-napi/test_array/test_array.c b/test/addons-napi/test_array/test_array.c index f13867ca74f848..bd4f867c0c9117 100644 --- a/test/addons-napi/test_array/test_array.c +++ b/test/addons-napi/test_array/test_array.c @@ -2,7 +2,7 @@ #include #include "../common.h" -napi_value TestGetElement(napi_env env, napi_callback_info info) { +static napi_value TestGetElement(napi_env env, napi_callback_info info) { size_t argc = 2; napi_value args[2]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -45,7 +45,7 @@ napi_value TestGetElement(napi_env env, napi_callback_info info) { return ret; } -napi_value TestHasElement(napi_env env, napi_callback_info info) { +static napi_value TestHasElement(napi_env env, napi_callback_info info) { size_t argc = 2; napi_value args[2]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -84,7 +84,7 @@ napi_value TestHasElement(napi_env env, napi_callback_info info) { return ret; } -napi_value TestDeleteElement(napi_env env, napi_callback_info info) { +static napi_value TestDeleteElement(napi_env env, napi_callback_info info) { size_t argc = 2; napi_value args[2]; @@ -119,7 +119,7 @@ napi_value TestDeleteElement(napi_env env, napi_callback_info info) { return ret; } -napi_value New(napi_env env, napi_callback_info info) { +static napi_value New(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -147,7 +147,7 @@ napi_value New(napi_env env, napi_callback_info info) { return ret; } -napi_value NewWithLength(napi_env env, napi_callback_info info) { +static napi_value NewWithLength(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -169,7 +169,7 @@ napi_value NewWithLength(napi_env env, napi_callback_info info) { return ret; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor descriptors[] = { DECLARE_NAPI_PROPERTY("TestGetElement", TestGetElement), DECLARE_NAPI_PROPERTY("TestHasElement", TestHasElement), diff --git a/test/addons-napi/test_buffer/test_buffer.c b/test/addons-napi/test_buffer/test_buffer.c index 657eb7b3a051bf..552d280615739f 100644 --- a/test/addons-napi/test_buffer/test_buffer.c +++ b/test/addons-napi/test_buffer/test_buffer.c @@ -20,7 +20,7 @@ static void noopDeleter(napi_env env, void* data, void* finalize_hint) { deleterCallCount++; } -napi_value newBuffer(napi_env env, napi_callback_info info) { +static napi_value newBuffer(napi_env env, napi_callback_info info) { napi_value theBuffer; char* theCopy; const unsigned int kBufferSize = sizeof(theText); @@ -37,7 +37,7 @@ napi_value newBuffer(napi_env env, napi_callback_info info) { return theBuffer; } -napi_value newExternalBuffer(napi_env env, napi_callback_info info) { +static napi_value newExternalBuffer(napi_env env, napi_callback_info info) { napi_value theBuffer; char* theCopy = strdup(theText); NAPI_ASSERT(env, theCopy, "Failed to copy static text for newExternalBuffer"); @@ -53,20 +53,20 @@ napi_value newExternalBuffer(napi_env env, napi_callback_info info) { return theBuffer; } -napi_value getDeleterCallCount(napi_env env, napi_callback_info info) { +static napi_value getDeleterCallCount(napi_env env, napi_callback_info info) { napi_value callCount; NAPI_CALL(env, napi_create_int32(env, deleterCallCount, &callCount)); return callCount; } -napi_value copyBuffer(napi_env env, napi_callback_info info) { +static napi_value copyBuffer(napi_env env, napi_callback_info info) { napi_value theBuffer; NAPI_CALL(env, napi_create_buffer_copy( env, sizeof(theText), theText, NULL, &theBuffer)); return theBuffer; } -napi_value bufferHasInstance(napi_env env, napi_callback_info info) { +static napi_value bufferHasInstance(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -85,7 +85,7 @@ napi_value bufferHasInstance(napi_env env, napi_callback_info info) { return returnValue; } -napi_value bufferInfo(napi_env env, napi_callback_info info) { +static napi_value bufferInfo(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -106,7 +106,7 @@ napi_value bufferInfo(napi_env env, napi_callback_info info) { return returnValue; } -napi_value staticBuffer(napi_env env, napi_callback_info info) { +static napi_value staticBuffer(napi_env env, napi_callback_info info) { napi_value theBuffer; NAPI_CALL( env, @@ -119,7 +119,7 @@ napi_value staticBuffer(napi_env env, napi_callback_info info) { return theBuffer; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_value theValue; NAPI_CALL(env, diff --git a/test/addons-napi/test_constructor/test_constructor.c b/test/addons-napi/test_constructor/test_constructor.c index 4ee8323dd6ed40..8cc092049aef10 100644 --- a/test/addons-napi/test_constructor/test_constructor.c +++ b/test/addons-napi/test_constructor/test_constructor.c @@ -4,7 +4,7 @@ static double value_ = 1; static double static_value_ = 10; -napi_value GetValue(napi_env env, napi_callback_info info) { +static napi_value GetValue(napi_env env, napi_callback_info info) { size_t argc = 0; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, NULL, NULL, NULL)); @@ -16,7 +16,7 @@ napi_value GetValue(napi_env env, napi_callback_info info) { return number; } -napi_value SetValue(napi_env env, napi_callback_info info) { +static napi_value SetValue(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -28,7 +28,7 @@ napi_value SetValue(napi_env env, napi_callback_info info) { return NULL; } -napi_value Echo(napi_env env, napi_callback_info info) { +static napi_value Echo(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -38,14 +38,14 @@ napi_value Echo(napi_env env, napi_callback_info info) { return args[0]; } -napi_value New(napi_env env, napi_callback_info info) { +static napi_value New(napi_env env, napi_callback_info info) { napi_value _this; NAPI_CALL(env, napi_get_cb_info(env, info, NULL, NULL, &_this, NULL)); return _this; } -napi_value GetStaticValue(napi_env env, napi_callback_info info) { +static napi_value GetStaticValue(napi_env env, napi_callback_info info) { size_t argc = 0; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, NULL, NULL, NULL)); @@ -58,7 +58,7 @@ napi_value GetStaticValue(napi_env env, napi_callback_info info) { } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_value number; NAPI_CALL(env, napi_create_double(env, value_, &number)); diff --git a/test/addons-napi/test_constructor/test_constructor_name.c b/test/addons-napi/test_constructor/test_constructor_name.c index a5c89791f0f0cd..b30ea4333747d3 100644 --- a/test/addons-napi/test_constructor/test_constructor_name.c +++ b/test/addons-napi/test_constructor/test_constructor_name.c @@ -3,14 +3,14 @@ napi_ref constructor_; -napi_value New(napi_env env, napi_callback_info info) { +static napi_value New(napi_env env, napi_callback_info info) { napi_value _this; NAPI_CALL(env, napi_get_cb_info(env, info, NULL, NULL, &_this, NULL)); return _this; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_value cons; NAPI_CALL(env, napi_define_class( env, "MyObject_Extra", 8, New, NULL, 0, NULL, &cons)); diff --git a/test/addons-napi/test_conversions/test_conversions.c b/test/addons-napi/test_conversions/test_conversions.c index 4f92bafa35b79d..845b7e7c56d7df 100644 --- a/test/addons-napi/test_conversions/test_conversions.c +++ b/test/addons-napi/test_conversions/test_conversions.c @@ -1,7 +1,7 @@ #include #include "../common.h" -napi_value AsBool(napi_env env, napi_callback_info info) { +static napi_value AsBool(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -15,7 +15,7 @@ napi_value AsBool(napi_env env, napi_callback_info info) { return output; } -napi_value AsInt32(napi_env env, napi_callback_info info) { +static napi_value AsInt32(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -29,7 +29,7 @@ napi_value AsInt32(napi_env env, napi_callback_info info) { return output; } -napi_value AsUInt32(napi_env env, napi_callback_info info) { +static napi_value AsUInt32(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -43,7 +43,7 @@ napi_value AsUInt32(napi_env env, napi_callback_info info) { return output; } -napi_value AsInt64(napi_env env, napi_callback_info info) { +static napi_value AsInt64(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -57,7 +57,7 @@ napi_value AsInt64(napi_env env, napi_callback_info info) { return output; } -napi_value AsDouble(napi_env env, napi_callback_info info) { +static napi_value AsDouble(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -71,7 +71,7 @@ napi_value AsDouble(napi_env env, napi_callback_info info) { return output; } -napi_value AsString(napi_env env, napi_callback_info info) { +static napi_value AsString(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -87,7 +87,7 @@ napi_value AsString(napi_env env, napi_callback_info info) { return output; } -napi_value ToBool(napi_env env, napi_callback_info info) { +static napi_value ToBool(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -98,7 +98,7 @@ napi_value ToBool(napi_env env, napi_callback_info info) { return output; } -napi_value ToNumber(napi_env env, napi_callback_info info) { +static napi_value ToNumber(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -109,7 +109,7 @@ napi_value ToNumber(napi_env env, napi_callback_info info) { return output; } -napi_value ToObject(napi_env env, napi_callback_info info) { +static napi_value ToObject(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -120,7 +120,7 @@ napi_value ToObject(napi_env env, napi_callback_info info) { return output; } -napi_value ToString(napi_env env, napi_callback_info info) { +static napi_value ToString(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -131,7 +131,7 @@ napi_value ToString(napi_env env, napi_callback_info info) { return output; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor descriptors[] = { DECLARE_NAPI_PROPERTY("asBool", AsBool), DECLARE_NAPI_PROPERTY("asInt32", AsInt32), diff --git a/test/addons-napi/test_dataview/test_dataview.c b/test/addons-napi/test_dataview/test_dataview.c index 4d29ed07e9e6f7..8d29743522022f 100644 --- a/test/addons-napi/test_dataview/test_dataview.c +++ b/test/addons-napi/test_dataview/test_dataview.c @@ -2,7 +2,7 @@ #include #include "../common.h" -napi_value CreateDataView(napi_env env, napi_callback_info info) { +static napi_value CreateDataView(napi_env env, napi_callback_info info) { size_t argc = 3; napi_value args [3]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -49,7 +49,7 @@ napi_value CreateDataView(napi_env env, napi_callback_info info) { return output_dataview; } -napi_value CreateDataViewFromJSDataView(napi_env env, napi_callback_info info) { +static napi_value CreateDataViewFromJSDataView(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args [1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -85,7 +85,7 @@ napi_value CreateDataViewFromJSDataView(napi_env env, napi_callback_info info) { return output_dataview; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor descriptors[] = { DECLARE_NAPI_PROPERTY("CreateDataView", CreateDataView), DECLARE_NAPI_PROPERTY("CreateDataViewFromJSDataView", diff --git a/test/addons-napi/test_env_sharing/compare_env.c b/test/addons-napi/test_env_sharing/compare_env.c index 6a93ce52c64025..3326a34067219a 100644 --- a/test/addons-napi/test_env_sharing/compare_env.c +++ b/test/addons-napi/test_env_sharing/compare_env.c @@ -1,7 +1,7 @@ #include #include "../common.h" -napi_value compare(napi_env env, napi_callback_info info) { +static napi_value compare(napi_env env, napi_callback_info info) { napi_value external; size_t argc = 1; void* data; @@ -14,7 +14,7 @@ napi_value compare(napi_env env, napi_callback_info info) { return return_value; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { NAPI_CALL(env, napi_create_function( env, "exports", NAPI_AUTO_LENGTH, compare, NULL, &exports)); return exports; diff --git a/test/addons-napi/test_env_sharing/store_env.c b/test/addons-napi/test_env_sharing/store_env.c index 809f5f7a4b2eed..0559b178cba68b 100644 --- a/test/addons-napi/test_env_sharing/store_env.c +++ b/test/addons-napi/test_env_sharing/store_env.c @@ -1,7 +1,7 @@ #include #include "../common.h" -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_value external; NAPI_CALL(env, napi_create_external(env, env, NULL, NULL, &external)); return external; diff --git a/test/addons-napi/test_fatal/test_fatal.c b/test/addons-napi/test_fatal/test_fatal.c index add8bebf3be7e3..b9248d40d49e6a 100644 --- a/test/addons-napi/test_fatal/test_fatal.c +++ b/test/addons-napi/test_fatal/test_fatal.c @@ -1,18 +1,18 @@ #include #include "../common.h" -napi_value Test(napi_env env, napi_callback_info info) { +static napi_value Test(napi_env env, napi_callback_info info) { napi_fatal_error("test_fatal::Test", NAPI_AUTO_LENGTH, "fatal message", NAPI_AUTO_LENGTH); return NULL; } -napi_value TestStringLength(napi_env env, napi_callback_info info) { +static napi_value TestStringLength(napi_env env, napi_callback_info info) { napi_fatal_error("test_fatal::TestStringLength", 16, "fatal message", 13); return NULL; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor properties[] = { DECLARE_NAPI_PROPERTY("Test", Test), DECLARE_NAPI_PROPERTY("TestStringLength", TestStringLength), diff --git a/test/addons-napi/test_fatal_exception/test_fatal_exception.c b/test/addons-napi/test_fatal_exception/test_fatal_exception.c index fd81c56d856db8..3cc810ccc0d10c 100644 --- a/test/addons-napi/test_fatal_exception/test_fatal_exception.c +++ b/test/addons-napi/test_fatal_exception/test_fatal_exception.c @@ -1,7 +1,7 @@ #include #include "../common.h" -napi_value Test(napi_env env, napi_callback_info info) { +static napi_value Test(napi_env env, napi_callback_info info) { napi_value err; size_t argc = 1; @@ -12,7 +12,7 @@ napi_value Test(napi_env env, napi_callback_info info) { return NULL; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor properties[] = { DECLARE_NAPI_PROPERTY("Test", Test), }; diff --git a/test/addons-napi/test_function/test_function.c b/test/addons-napi/test_function/test_function.c index b0350e6ee22876..2c361933cfa071 100644 --- a/test/addons-napi/test_function/test_function.c +++ b/test/addons-napi/test_function/test_function.c @@ -1,7 +1,7 @@ #include #include "../common.h" -napi_value TestCallFunction(napi_env env, napi_callback_info info) { +static napi_value TestCallFunction(napi_env env, napi_callback_info info) { size_t argc = 10; napi_value args[10]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -26,11 +26,11 @@ napi_value TestCallFunction(napi_env env, napi_callback_info info) { return result; } -napi_value TestFunctionName(napi_env env, napi_callback_info info) { +static napi_value TestFunctionName(napi_env env, napi_callback_info info) { return NULL; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_value fn1; NAPI_CALL(env, napi_create_function( env, NULL, NAPI_AUTO_LENGTH, TestCallFunction, NULL, &fn1)); diff --git a/test/addons-napi/test_general/test_general.c b/test/addons-napi/test_general/test_general.c index 05cdd76e3c1e64..8f429f939fb89e 100644 --- a/test/addons-napi/test_general/test_general.c +++ b/test/addons-napi/test_general/test_general.c @@ -2,7 +2,7 @@ #include #include "../common.h" -napi_value testStrictEquals(napi_env env, napi_callback_info info) { +static napi_value testStrictEquals(napi_env env, napi_callback_info info) { size_t argc = 2; napi_value args[2]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -15,7 +15,7 @@ napi_value testStrictEquals(napi_env env, napi_callback_info info) { return result; } -napi_value testGetPrototype(napi_env env, napi_callback_info info) { +static napi_value testGetPrototype(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -26,7 +26,7 @@ napi_value testGetPrototype(napi_env env, napi_callback_info info) { return result; } -napi_value testGetVersion(napi_env env, napi_callback_info info) { +static napi_value testGetVersion(napi_env env, napi_callback_info info) { uint32_t version; napi_value result; NAPI_CALL(env, napi_get_version(env, &version)); @@ -34,7 +34,7 @@ napi_value testGetVersion(napi_env env, napi_callback_info info) { return result; } -napi_value testGetNodeVersion(napi_env env, napi_callback_info info) { +static napi_value testGetNodeVersion(napi_env env, napi_callback_info info) { const napi_node_version* node_version; napi_value result, major, minor, patch, release; NAPI_CALL(env, napi_get_node_version(env, &node_version)); @@ -53,7 +53,7 @@ napi_value testGetNodeVersion(napi_env env, napi_callback_info info) { return result; } -napi_value doInstanceOf(napi_env env, napi_callback_info info) { +static napi_value doInstanceOf(napi_env env, napi_callback_info info) { size_t argc = 2; napi_value args[2]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -67,19 +67,19 @@ napi_value doInstanceOf(napi_env env, napi_callback_info info) { return result; } -napi_value getNull(napi_env env, napi_callback_info info) { +static napi_value getNull(napi_env env, napi_callback_info info) { napi_value result; NAPI_CALL(env, napi_get_null(env, &result)); return result; } -napi_value getUndefined(napi_env env, napi_callback_info info) { +static napi_value getUndefined(napi_env env, napi_callback_info info) { napi_value result; NAPI_CALL(env, napi_get_undefined(env, &result)); return result; } -napi_value createNapiError(napi_env env, napi_callback_info info) { +static napi_value createNapiError(napi_env env, napi_callback_info info) { napi_value value; NAPI_CALL(env, napi_create_string_utf8(env, "xyz", 3, &value)); @@ -99,7 +99,7 @@ napi_value createNapiError(napi_env env, napi_callback_info info) { return NULL; } -napi_value testNapiErrorCleanup(napi_env env, napi_callback_info info) { +static napi_value testNapiErrorCleanup(napi_env env, napi_callback_info info) { const napi_extended_error_info *error_info = 0; NAPI_CALL(env, napi_get_last_error_info(env, &error_info)); @@ -110,7 +110,7 @@ napi_value testNapiErrorCleanup(napi_env env, napi_callback_info info) { return result; } -napi_value testNapiTypeof(napi_env env, napi_callback_info info) { +static napi_value testNapiTypeof(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -157,7 +157,7 @@ static void deref_item(napi_env env, void* data, void* hint) { deref_item_called = true; } -napi_value deref_item_was_called(napi_env env, napi_callback_info info) { +static napi_value deref_item_was_called(napi_env env, napi_callback_info info) { napi_value it_was_called; NAPI_CALL(env, napi_get_boolean(env, deref_item_called, &it_was_called)); @@ -165,7 +165,7 @@ napi_value deref_item_was_called(napi_env env, napi_callback_info info) { return it_was_called; } -napi_value wrap(napi_env env, napi_callback_info info) { +static napi_value wrap(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value to_wrap; @@ -177,7 +177,7 @@ napi_value wrap(napi_env env, napi_callback_info info) { return NULL; } -napi_value remove_wrap(napi_env env, napi_callback_info info) { +static napi_value remove_wrap(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value wrapped; void* data; @@ -193,7 +193,7 @@ static void test_finalize(napi_env env, void* data, void* hint) { finalize_called = true; } -napi_value test_finalize_wrap(napi_env env, napi_callback_info info) { +static napi_value test_finalize_wrap(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value js_object; @@ -203,7 +203,7 @@ napi_value test_finalize_wrap(napi_env env, napi_callback_info info) { return NULL; } -napi_value finalize_was_called(napi_env env, napi_callback_info info) { +static napi_value finalize_was_called(napi_env env, napi_callback_info info) { napi_value it_was_called; NAPI_CALL(env, napi_get_boolean(env, finalize_called, &it_was_called)); @@ -211,7 +211,7 @@ napi_value finalize_was_called(napi_env env, napi_callback_info info) { return it_was_called; } -napi_value testAdjustExternalMemory(napi_env env, napi_callback_info info) { +static napi_value testAdjustExternalMemory(napi_env env, napi_callback_info info) { napi_value result; int64_t adjustedValue; @@ -221,7 +221,7 @@ napi_value testAdjustExternalMemory(napi_env env, napi_callback_info info) { return result; } -napi_value testNapiRun(napi_env env, napi_callback_info info) { +static napi_value testNapiRun(napi_env env, napi_callback_info info) { napi_value script, result; size_t argc = 1; @@ -232,7 +232,7 @@ napi_value testNapiRun(napi_env env, napi_callback_info info) { return result; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor descriptors[] = { DECLARE_NAPI_PROPERTY("testStrictEquals", testStrictEquals), DECLARE_NAPI_PROPERTY("testGetPrototype", testGetPrototype), diff --git a/test/addons-napi/test_handle_scope/test_handle_scope.c b/test/addons-napi/test_handle_scope/test_handle_scope.c index 31efbcf3dd4d7b..76f31f7882b61b 100644 --- a/test/addons-napi/test_handle_scope/test_handle_scope.c +++ b/test/addons-napi/test_handle_scope/test_handle_scope.c @@ -7,7 +7,7 @@ // the right right thing would be quite hard so we keep it // simple for now. -napi_value NewScope(napi_env env, napi_callback_info info) { +static napi_value NewScope(napi_env env, napi_callback_info info) { napi_handle_scope scope; napi_value output = NULL; @@ -17,7 +17,7 @@ napi_value NewScope(napi_env env, napi_callback_info info) { return NULL; } -napi_value NewScopeEscape(napi_env env, napi_callback_info info) { +static napi_value NewScopeEscape(napi_env env, napi_callback_info info) { napi_escapable_handle_scope scope; napi_value output = NULL; napi_value escapee = NULL; @@ -29,7 +29,7 @@ napi_value NewScopeEscape(napi_env env, napi_callback_info info) { return escapee; } -napi_value NewScopeEscapeTwice(napi_env env, napi_callback_info info) { +static napi_value NewScopeEscapeTwice(napi_env env, napi_callback_info info) { napi_escapable_handle_scope scope; napi_value output = NULL; napi_value escapee = NULL; @@ -44,7 +44,7 @@ napi_value NewScopeEscapeTwice(napi_env env, napi_callback_info info) { return NULL; } -napi_value NewScopeWithException(napi_env env, napi_callback_info info) { +static napi_value NewScopeWithException(napi_env env, napi_callback_info info) { napi_handle_scope scope; size_t argc; napi_value exception_function; @@ -68,7 +68,7 @@ napi_value NewScopeWithException(napi_env env, napi_callback_info info) { return NULL; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor properties[] = { DECLARE_NAPI_PROPERTY("NewScope", NewScope), DECLARE_NAPI_PROPERTY("NewScopeEscape", NewScopeEscape), diff --git a/test/addons-napi/test_make_callback/binding.c b/test/addons-napi/test_make_callback/binding.c index 23750f56b838fc..8eedd5b1b3b167 100644 --- a/test/addons-napi/test_make_callback/binding.c +++ b/test/addons-napi/test_make_callback/binding.c @@ -3,8 +3,7 @@ #define MAX_ARGUMENTS 10 -static -napi_value MakeCallback(napi_env env, napi_callback_info info) { +static napi_value MakeCallback(napi_env env, napi_callback_info info) { size_t argc = MAX_ARGUMENTS; size_t n; napi_value args[MAX_ARGUMENTS]; diff --git a/test/addons-napi/test_new_target/binding.c b/test/addons-napi/test_new_target/binding.c index a74d4bb2f877be..0c542ebaba693d 100644 --- a/test/addons-napi/test_new_target/binding.c +++ b/test/addons-napi/test_new_target/binding.c @@ -1,7 +1,7 @@ #include #include "../common.h" -napi_value BaseClass(napi_env env, napi_callback_info info) { +static napi_value BaseClass(napi_env env, napi_callback_info info) { napi_value newTargetArg; NAPI_CALL(env, napi_get_new_target(env, info, &newTargetArg)); napi_value thisArg; @@ -22,7 +22,7 @@ napi_value BaseClass(napi_env env, napi_callback_info info) { return thisArg; } -napi_value Constructor(napi_env env, napi_callback_info info) { +static napi_value Constructor(napi_env env, napi_callback_info info) { bool result; napi_value newTargetArg; NAPI_CALL(env, napi_get_new_target(env, info, &newTargetArg)); @@ -45,7 +45,7 @@ napi_value Constructor(napi_env env, napi_callback_info info) { return thisArg; } -napi_value OrdinaryFunction(napi_env env, napi_callback_info info) { +static napi_value OrdinaryFunction(napi_env env, napi_callback_info info) { napi_value newTargetArg; NAPI_CALL(env, napi_get_new_target(env, info, &newTargetArg)); @@ -56,7 +56,7 @@ napi_value OrdinaryFunction(napi_env env, napi_callback_info info) { return _true; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { const napi_property_descriptor desc[] = { DECLARE_NAPI_PROPERTY("BaseClass", BaseClass), DECLARE_NAPI_PROPERTY("OrdinaryFunction", OrdinaryFunction), diff --git a/test/addons-napi/test_number/test_number.c b/test/addons-napi/test_number/test_number.c index a1a70950083324..19b0ae83f051df 100644 --- a/test/addons-napi/test_number/test_number.c +++ b/test/addons-napi/test_number/test_number.c @@ -1,7 +1,7 @@ #include #include "../common.h" -napi_value Test(napi_env env, napi_callback_info info) { +static napi_value Test(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -23,7 +23,7 @@ napi_value Test(napi_env env, napi_callback_info info) { return output; } -napi_value TestInt32Truncation(napi_env env, napi_callback_info info) { +static napi_value TestInt32Truncation(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -45,7 +45,7 @@ napi_value TestInt32Truncation(napi_env env, napi_callback_info info) { return output; } -napi_value TestInt64Truncation(napi_env env, napi_callback_info info) { +static napi_value TestInt64Truncation(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -67,7 +67,7 @@ napi_value TestInt64Truncation(napi_env env, napi_callback_info info) { return output; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor descriptors[] = { DECLARE_NAPI_PROPERTY("Test", Test), DECLARE_NAPI_PROPERTY("TestInt32Truncation", TestInt32Truncation), diff --git a/test/addons-napi/test_object/test_object.c b/test/addons-napi/test_object/test_object.c index ccf1573114a6f1..046f71fa414735 100644 --- a/test/addons-napi/test_object/test_object.c +++ b/test/addons-napi/test_object/test_object.c @@ -4,7 +4,7 @@ static int test_value = 3; -napi_value Get(napi_env env, napi_callback_info info) { +static napi_value Get(napi_env env, napi_callback_info info) { size_t argc = 2; napi_value args[2]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -30,7 +30,7 @@ napi_value Get(napi_env env, napi_callback_info info) { return output; } -napi_value Set(napi_env env, napi_callback_info info) { +static napi_value Set(napi_env env, napi_callback_info info) { size_t argc = 3; napi_value args[3]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -57,7 +57,7 @@ napi_value Set(napi_env env, napi_callback_info info) { return valuetrue; } -napi_value Has(napi_env env, napi_callback_info info) { +static napi_value Has(napi_env env, napi_callback_info info) { size_t argc = 2; napi_value args[2]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -85,7 +85,7 @@ napi_value Has(napi_env env, napi_callback_info info) { return ret; } -napi_value HasOwn(napi_env env, napi_callback_info info) { +static napi_value HasOwn(napi_env env, napi_callback_info info) { size_t argc = 2; napi_value args[2]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -113,7 +113,7 @@ napi_value HasOwn(napi_env env, napi_callback_info info) { return ret; } -napi_value Delete(napi_env env, napi_callback_info info) { +static napi_value Delete(napi_env env, napi_callback_info info) { size_t argc = 2; napi_value args[2]; @@ -138,7 +138,7 @@ napi_value Delete(napi_env env, napi_callback_info info) { return ret; } -napi_value New(napi_env env, napi_callback_info info) { +static napi_value New(napi_env env, napi_callback_info info) { napi_value ret; NAPI_CALL(env, napi_create_object(env, &ret)); @@ -157,7 +157,7 @@ napi_value New(napi_env env, napi_callback_info info) { return ret; } -napi_value Inflate(napi_env env, napi_callback_info info) { +static napi_value Inflate(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -193,7 +193,7 @@ napi_value Inflate(napi_env env, napi_callback_info info) { return obj; } -napi_value Wrap(napi_env env, napi_callback_info info) { +static napi_value Wrap(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value arg; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, &arg, NULL, NULL)); @@ -202,7 +202,7 @@ napi_value Wrap(napi_env env, napi_callback_info info) { return NULL; } -napi_value Unwrap(napi_env env, napi_callback_info info) { +static napi_value Unwrap(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value arg; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, &arg, NULL, NULL)); @@ -216,7 +216,7 @@ napi_value Unwrap(napi_env env, napi_callback_info info) { return result; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor descriptors[] = { DECLARE_NAPI_PROPERTY("Get", Get), DECLARE_NAPI_PROPERTY("Set", Set), diff --git a/test/addons-napi/test_promise/test_promise.c b/test/addons-napi/test_promise/test_promise.c index aa89c022bc1a4a..3e2ec48572af4c 100644 --- a/test/addons-napi/test_promise/test_promise.c +++ b/test/addons-napi/test_promise/test_promise.c @@ -3,7 +3,7 @@ napi_deferred deferred = NULL; -napi_value createPromise(napi_env env, napi_callback_info info) { +static napi_value createPromise(napi_env env, napi_callback_info info) { napi_value promise; // We do not overwrite an existing deferred. @@ -16,7 +16,8 @@ napi_value createPromise(napi_env env, napi_callback_info info) { return promise; } -napi_value concludeCurrentPromise(napi_env env, napi_callback_info info) { +static napi_value +concludeCurrentPromise(napi_env env, napi_callback_info info) { napi_value argv[2]; size_t argc = 2; bool resolution; @@ -34,7 +35,7 @@ napi_value concludeCurrentPromise(napi_env env, napi_callback_info info) { return NULL; } -napi_value isPromise(napi_env env, napi_callback_info info) { +static napi_value isPromise(napi_env env, napi_callback_info info) { napi_value promise, result; size_t argc = 1; bool is_promise; @@ -46,7 +47,7 @@ napi_value isPromise(napi_env env, napi_callback_info info) { return result; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor descriptors[] = { DECLARE_NAPI_PROPERTY("createPromise", createPromise), DECLARE_NAPI_PROPERTY("concludeCurrentPromise", concludeCurrentPromise), diff --git a/test/addons-napi/test_properties/test_properties.c b/test/addons-napi/test_properties/test_properties.c index a95c7013c2cabb..2754812f4dad27 100644 --- a/test/addons-napi/test_properties/test_properties.c +++ b/test/addons-napi/test_properties/test_properties.c @@ -3,7 +3,7 @@ static double value_ = 1; -napi_value GetValue(napi_env env, napi_callback_info info) { +static napi_value GetValue(napi_env env, napi_callback_info info) { size_t argc = 0; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, NULL, NULL, NULL)); @@ -15,7 +15,7 @@ napi_value GetValue(napi_env env, napi_callback_info info) { return number; } -napi_value SetValue(napi_env env, napi_callback_info info) { +static napi_value SetValue(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -27,7 +27,7 @@ napi_value SetValue(napi_env env, napi_callback_info info) { return NULL; } -napi_value Echo(napi_env env, napi_callback_info info) { +static napi_value Echo(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -37,7 +37,7 @@ napi_value Echo(napi_env env, napi_callback_info info) { return args[0]; } -napi_value HasNamedProperty(napi_env env, napi_callback_info info) { +static napi_value HasNamedProperty(napi_env env, napi_callback_info info) { size_t argc = 2; napi_value args[2]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -59,7 +59,7 @@ napi_value HasNamedProperty(napi_env env, napi_callback_info info) { return result; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_value number; NAPI_CALL(env, napi_create_double(env, value_, &number)); diff --git a/test/addons-napi/test_reference/test_reference.c b/test/addons-napi/test_reference/test_reference.c index f34adc6693b6fe..641b1cb82ba8e1 100644 --- a/test/addons-napi/test_reference/test_reference.c +++ b/test/addons-napi/test_reference/test_reference.c @@ -5,7 +5,7 @@ static int test_value = 1; static int finalize_count = 0; static napi_ref test_reference = NULL; -napi_value GetFinalizeCount(napi_env env, napi_callback_info info) { +static napi_value GetFinalizeCount(napi_env env, napi_callback_info info) { napi_value result; NAPI_CALL(env, napi_create_int32(env, finalize_count, &result)); return result; @@ -18,7 +18,7 @@ void FinalizeExternal(napi_env env, void* data, void* hint) { finalize_count++; } -napi_value CreateExternal(napi_env env, napi_callback_info info) { +static napi_value CreateExternal(napi_env env, napi_callback_info info) { int* data = &test_value; napi_value result; @@ -33,7 +33,8 @@ napi_value CreateExternal(napi_env env, napi_callback_info info) { return result; } -napi_value CreateExternalWithFinalize(napi_env env, napi_callback_info info) { +static napi_value +CreateExternalWithFinalize(napi_env env, napi_callback_info info) { napi_value result; NAPI_CALL(env, napi_create_external(env, @@ -46,7 +47,7 @@ napi_value CreateExternalWithFinalize(napi_env env, napi_callback_info info) { return result; } -napi_value CheckExternal(napi_env env, napi_callback_info info) { +static napi_value CheckExternal(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value arg; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, &arg, NULL, NULL)); @@ -67,7 +68,7 @@ napi_value CheckExternal(napi_env env, napi_callback_info info) { return NULL; } -napi_value CreateReference(napi_env env, napi_callback_info info) { +static napi_value CreateReference(napi_env env, napi_callback_info info) { NAPI_ASSERT(env, test_reference == NULL, "The test allows only one reference at a time."); @@ -88,7 +89,7 @@ napi_value CreateReference(napi_env env, napi_callback_info info) { return NULL; } -napi_value DeleteReference(napi_env env, napi_callback_info info) { +static napi_value DeleteReference(napi_env env, napi_callback_info info) { NAPI_ASSERT(env, test_reference != NULL, "A reference must have been created."); @@ -97,7 +98,7 @@ napi_value DeleteReference(napi_env env, napi_callback_info info) { return NULL; } -napi_value IncrementRefcount(napi_env env, napi_callback_info info) { +static napi_value IncrementRefcount(napi_env env, napi_callback_info info) { NAPI_ASSERT(env, test_reference != NULL, "A reference must have been created."); @@ -109,7 +110,7 @@ napi_value IncrementRefcount(napi_env env, napi_callback_info info) { return result; } -napi_value DecrementRefcount(napi_env env, napi_callback_info info) { +static napi_value DecrementRefcount(napi_env env, napi_callback_info info) { NAPI_ASSERT(env, test_reference != NULL, "A reference must have been created."); @@ -121,7 +122,7 @@ napi_value DecrementRefcount(napi_env env, napi_callback_info info) { return result; } -napi_value GetReferenceValue(napi_env env, napi_callback_info info) { +static napi_value GetReferenceValue(napi_env env, napi_callback_info info) { NAPI_ASSERT(env, test_reference != NULL, "A reference must have been created."); @@ -130,7 +131,7 @@ napi_value GetReferenceValue(napi_env env, napi_callback_info info) { return result; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor descriptors[] = { DECLARE_NAPI_GETTER("finalizeCount", GetFinalizeCount), DECLARE_NAPI_PROPERTY("createExternal", CreateExternal), diff --git a/test/addons-napi/test_string/test_string.c b/test/addons-napi/test_string/test_string.c index 99a3f7d3545a20..4e6da7bf86849f 100644 --- a/test/addons-napi/test_string/test_string.c +++ b/test/addons-napi/test_string/test_string.c @@ -2,7 +2,7 @@ #include #include "../common.h" -napi_value TestLatin1(napi_env env, napi_callback_info info) { +static napi_value TestLatin1(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -28,7 +28,7 @@ napi_value TestLatin1(napi_env env, napi_callback_info info) { return output; } -napi_value TestUtf8(napi_env env, napi_callback_info info) { +static napi_value TestUtf8(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -54,7 +54,7 @@ napi_value TestUtf8(napi_env env, napi_callback_info info) { return output; } -napi_value TestUtf16(napi_env env, napi_callback_info info) { +static napi_value TestUtf16(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -80,7 +80,8 @@ napi_value TestUtf16(napi_env env, napi_callback_info info) { return output; } -napi_value TestLatin1Insufficient(napi_env env, napi_callback_info info) { +static napi_value +TestLatin1Insufficient(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -106,7 +107,7 @@ napi_value TestLatin1Insufficient(napi_env env, napi_callback_info info) { return output; } -napi_value TestUtf8Insufficient(napi_env env, napi_callback_info info) { +static napi_value TestUtf8Insufficient(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -132,7 +133,7 @@ napi_value TestUtf8Insufficient(napi_env env, napi_callback_info info) { return output; } -napi_value TestUtf16Insufficient(napi_env env, napi_callback_info info) { +static napi_value TestUtf16Insufficient(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -158,7 +159,7 @@ napi_value TestUtf16Insufficient(napi_env env, napi_callback_info info) { return output; } -napi_value Utf16Length(napi_env env, napi_callback_info info) { +static napi_value Utf16Length(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -180,7 +181,7 @@ napi_value Utf16Length(napi_env env, napi_callback_info info) { return output; } -napi_value Utf8Length(napi_env env, napi_callback_info info) { +static napi_value Utf8Length(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -202,7 +203,7 @@ napi_value Utf8Length(napi_env env, napi_callback_info info) { return output; } -napi_value TestLargeUtf8(napi_env env, napi_callback_info info) { +static napi_value TestLargeUtf8(napi_env env, napi_callback_info info) { napi_value output; if (SIZE_MAX > INT_MAX) { NAPI_CALL(env, napi_create_string_utf8(env, "", ((size_t)INT_MAX) + 1, &output)); @@ -215,7 +216,7 @@ napi_value TestLargeUtf8(napi_env env, napi_callback_info info) { return output; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor properties[] = { DECLARE_NAPI_PROPERTY("TestLatin1", TestLatin1), DECLARE_NAPI_PROPERTY("TestLatin1Insufficient", TestLatin1Insufficient), diff --git a/test/addons-napi/test_symbol/test_symbol.c b/test/addons-napi/test_symbol/test_symbol.c index c91b6ae54f4932..18cb4b405fb76d 100644 --- a/test/addons-napi/test_symbol/test_symbol.c +++ b/test/addons-napi/test_symbol/test_symbol.c @@ -1,7 +1,7 @@ #include #include "../common.h" -napi_value Test(napi_env env, napi_callback_info info) { +static napi_value Test(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -26,7 +26,7 @@ napi_value Test(napi_env env, napi_callback_info info) { return output; } -napi_value New(napi_env env, napi_callback_info info) { +static napi_value New(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -48,7 +48,7 @@ napi_value New(napi_env env, napi_callback_info info) { return symbol; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor properties[] = { DECLARE_NAPI_PROPERTY("New", New), }; diff --git a/test/addons-napi/test_typedarray/test_typedarray.c b/test/addons-napi/test_typedarray/test_typedarray.c index 2758a6f53298fe..a0ac02665864f1 100644 --- a/test/addons-napi/test_typedarray/test_typedarray.c +++ b/test/addons-napi/test_typedarray/test_typedarray.c @@ -2,7 +2,7 @@ #include #include "../common.h" -napi_value Multiply(napi_env env, napi_callback_info info) { +static napi_value Multiply(napi_env env, napi_callback_info info) { size_t argc = 2; napi_value args[2]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -73,7 +73,7 @@ napi_value Multiply(napi_env env, napi_callback_info info) { return output_array; } -napi_value External(napi_env env, napi_callback_info info) { +static napi_value External(napi_env env, napi_callback_info info) { static int8_t externalData[] = {0, 1, 2}; napi_value output_buffer; @@ -96,7 +96,7 @@ napi_value External(napi_env env, napi_callback_info info) { return output_array; } -napi_value CreateTypedArray(napi_env env, napi_callback_info info) { +static napi_value CreateTypedArray(napi_env env, napi_callback_info info) { size_t argc = 4; napi_value args[4]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -165,7 +165,7 @@ napi_value CreateTypedArray(napi_env env, napi_callback_info info) { return output_array; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor descriptors[] = { DECLARE_NAPI_PROPERTY("Multiply", Multiply), DECLARE_NAPI_PROPERTY("External", External), From b5bc6bd94bfeee46216602a7557cffa8813e6358 Mon Sep 17 00:00:00 2001 From: William Cohen Date: Thu, 19 Apr 2018 10:15:25 -0400 Subject: [PATCH 015/173] src: fix Systemtap node_gc_stop probe The process("node").mark("gc__stop") is actually process("node").mark("gc__done"). Use the proper name so that a developer can use SystemTap to determine the duration of garbage collection. PR-URL: https://github.com/nodejs/node/pull/20152 Reviewed-By: Ben Noordhuis Reviewed-By: Matheus Marchini Reviewed-By: Richard Lau --- src/node.stp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node.stp b/src/node.stp index 3369968c205146..ebc40d574fc2be 100644 --- a/src/node.stp +++ b/src/node.stp @@ -125,7 +125,7 @@ probe node_gc_start = process("node").mark("gc__start") flags); } -probe node_gc_stop = process("node").mark("gc__stop") +probe node_gc_stop = process("node").mark("gc__done") { scavenge = 1 << 0; compact = 1 << 1; From c9b202f817643d777407c86da408da703afc163d Mon Sep 17 00:00:00 2001 From: Ajido Date: Wed, 25 Apr 2018 23:46:54 +0900 Subject: [PATCH 016/173] doc: add emitter.off() to events.md PR-URL: https://github.com/nodejs/node/pull/20291 Refs: https://github.com/nodejs/node/pull/17156 Reviewed-By: Colin Ihrig Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: Vse Mozhet Byt Reviewed-By: Anna Henningsen --- doc/api/events.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/api/events.md b/doc/api/events.md index a5a45ca3de4834..35ad9eaed393b9 100644 --- a/doc/api/events.md +++ b/doc/api/events.md @@ -372,6 +372,17 @@ console.log(util.inspect(server.listeners('connection'))); // Prints: [ [Function] ] ``` +### emitter.off(eventName, listener) + + +* `eventName` {string|symbol} +* `listener` {Function} +* Returns: {EventEmitter} + +Alias for [`emitter.removeListener()`][]. + ### emitter.on(eventName, listener) +* `type` {integer} The frame type. +* `code` {integer} The error code. +* `id` {integer} The stream id (or `0` if the frame isn't associated with a + stream). + The `'frameError'` event is emitted when an error occurs while attempting to send a frame on the session. If the frame that could not be sent is associated with a specific `Http2Stream`, an attempt to emit `'frameError'` event on the `Http2Stream` is made. -When invoked, the handler function will receive three arguments: - -* An integer identifying the frame type. -* An integer identifying the error code. -* An integer identifying the stream (or 0 if the frame is not associated with - a stream). - If the `'frameError'` event is associated with a stream, the stream will be closed and destroyed immediately following the `'frameError'` event. If the event is not associated with a stream, the `Http2Session` will be shut down From 391d2f830a3b861be2ee2adf7204a0c8e660f91b Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Tue, 24 Apr 2018 08:45:35 +0200 Subject: [PATCH 018/173] crypto: simplify diffiehellman getFormat function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit aims to simplify the getFormat function in diffiehellman.js. PR-URL: https://github.com/nodejs/node/pull/20246 Reviewed-By: Tobias Nießen Reviewed-By: Trivikram Kamat Reviewed-By: Colin Ihrig Reviewed-By: James M Snell --- lib/internal/crypto/diffiehellman.js | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/lib/internal/crypto/diffiehellman.js b/lib/internal/crypto/diffiehellman.js index 329add6d4d7cd5..dad7a903b26a5e 100644 --- a/lib/internal/crypto/diffiehellman.js +++ b/lib/internal/crypto/diffiehellman.js @@ -219,21 +219,15 @@ function encode(buffer, encoding) { } function getFormat(format) { - let f; if (format) { if (format === 'compressed') - f = POINT_CONVERSION_COMPRESSED; - else if (format === 'hybrid') - f = POINT_CONVERSION_HYBRID; - // Default - else if (format === 'uncompressed') - f = POINT_CONVERSION_UNCOMPRESSED; - else + return POINT_CONVERSION_COMPRESSED; + if (format === 'hybrid') + return POINT_CONVERSION_HYBRID; + if (format !== 'uncompressed') throw new ERR_CRYPTO_ECDH_INVALID_FORMAT(format); - } else { - f = POINT_CONVERSION_UNCOMPRESSED; } - return f; + return POINT_CONVERSION_UNCOMPRESSED; } module.exports = { From e81bb9f8a368c21b9e60434eb7403739f87d448f Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Tue, 24 Apr 2018 10:47:24 +0200 Subject: [PATCH 019/173] crypto: add getIntOption function to reduce dupl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds a getIntOption function to reduce the code duplicated for getting the padding, and saltLength options. PR-URL: https://github.com/nodejs/node/pull/20247 Reviewed-By: Anna Henningsen Reviewed-By: Tobias Nießen Reviewed-By: Colin Ihrig Reviewed-By: Trivikram Kamat Reviewed-By: James M Snell Reviewed-By: Luigi Pinca --- lib/internal/crypto/sig.js | 55 ++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/lib/internal/crypto/sig.js b/lib/internal/crypto/sig.js index aed679e99b9b8f..92b42412a82e92 100644 --- a/lib/internal/crypto/sig.js +++ b/lib/internal/crypto/sig.js @@ -53,6 +53,25 @@ Sign.prototype.update = function update(data, encoding) { return this; }; +function getPadding(options) { + return getIntOption('padding', RSA_PKCS1_PADDING, options); +} + +function getSaltLength(options) { + return getIntOption('saltLength', RSA_PSS_SALTLEN_AUTO, options); +} + +function getIntOption(name, defaultValue, options) { + if (options.hasOwnProperty(name)) { + if (options[name] === options[name] >> 0) { + return options[name]; + } else { + throw new ERR_INVALID_OPT_VALUE(name, options[name]); + } + } + return defaultValue; +} + Sign.prototype.sign = function sign(options, encoding) { if (!options) throw new ERR_CRYPTO_SIGN_KEY_REQUIRED(); @@ -61,23 +80,9 @@ Sign.prototype.sign = function sign(options, encoding) { var passphrase = options.passphrase || null; // Options specific to RSA - var rsaPadding = RSA_PKCS1_PADDING; - if (options.hasOwnProperty('padding')) { - if (options.padding === options.padding >> 0) { - rsaPadding = options.padding; - } else { - throw new ERR_INVALID_OPT_VALUE('padding', options.padding); - } - } + var rsaPadding = getPadding(options); - var pssSaltLength = RSA_PSS_SALTLEN_AUTO; - if (options.hasOwnProperty('saltLength')) { - if (options.saltLength === options.saltLength >> 0) { - pssSaltLength = options.saltLength; - } else { - throw new ERR_INVALID_OPT_VALUE('saltLength', options.saltLength); - } - } + var pssSaltLength = getSaltLength(options); key = toBuf(key); if (!isArrayBufferView(key)) { @@ -119,23 +124,9 @@ Verify.prototype.verify = function verify(options, signature, sigEncoding) { sigEncoding = sigEncoding || getDefaultEncoding(); // Options specific to RSA - var rsaPadding = RSA_PKCS1_PADDING; - if (options.hasOwnProperty('padding')) { - if (options.padding === options.padding >> 0) { - rsaPadding = options.padding; - } else { - throw new ERR_INVALID_OPT_VALUE('padding', options.padding); - } - } + var rsaPadding = getPadding(options); - var pssSaltLength = RSA_PSS_SALTLEN_AUTO; - if (options.hasOwnProperty('saltLength')) { - if (options.saltLength === options.saltLength >> 0) { - pssSaltLength = options.saltLength; - } else { - throw new ERR_INVALID_OPT_VALUE('saltLength', options.saltLength); - } - } + var pssSaltLength = getSaltLength(options); key = toBuf(key); if (!isArrayBufferView(key)) { From 61e93963ce326d35de9dcecaae43c22d8c7f8c2c Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Tue, 24 Apr 2018 13:42:44 +0200 Subject: [PATCH 020/173] crypto: add checkIsArrayBufferView MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds a checkIsArrayBufferView function to avoid some code duplication in sig.js PR-URL: https://github.com/nodejs/node/pull/20251 Reviewed-By: Ben Noordhuis Reviewed-By: Joyee Cheung Reviewed-By: Tobias Nießen Reviewed-By: Colin Ihrig Reviewed-By: Trivikram Kamat Reviewed-By: James M Snell Reviewed-By: Tiancheng "Timothy" Gu --- lib/internal/crypto/sig.js | 39 ++++++------------------------------- lib/internal/crypto/util.js | 12 ++++++++++++ 2 files changed, 18 insertions(+), 33 deletions(-) diff --git a/lib/internal/crypto/sig.js b/lib/internal/crypto/sig.js index 92b42412a82e92..1073b83d720098 100644 --- a/lib/internal/crypto/sig.js +++ b/lib/internal/crypto/sig.js @@ -14,10 +14,10 @@ const { RSA_PKCS1_PADDING } = process.binding('constants').crypto; const { + checkIsArrayBufferView, getDefaultEncoding, toBuf } = require('internal/crypto/util'); -const { isArrayBufferView } = require('internal/util/types'); const { Writable } = require('stream'); const { inherits } = require('util'); @@ -41,14 +41,7 @@ Sign.prototype._write = function _write(chunk, encoding, callback) { Sign.prototype.update = function update(data, encoding) { encoding = encoding || getDefaultEncoding(); - data = toBuf(data, encoding); - if (!isArrayBufferView(data)) { - throw new ERR_INVALID_ARG_TYPE( - 'data', - ['string', 'Buffer', 'TypedArray', 'DataView'], - data - ); - } + data = checkIsArrayBufferView('data', toBuf(data, encoding)); this._handle.update(data); return this; }; @@ -84,14 +77,7 @@ Sign.prototype.sign = function sign(options, encoding) { var pssSaltLength = getSaltLength(options); - key = toBuf(key); - if (!isArrayBufferView(key)) { - throw new ERR_INVALID_ARG_TYPE( - 'key', - ['string', 'Buffer', 'TypedArray', 'DataView'], - key - ); - } + key = checkIsArrayBufferView('key', toBuf(key)); var ret = this._handle.sign(key, passphrase, rsaPadding, pssSaltLength); @@ -128,23 +114,10 @@ Verify.prototype.verify = function verify(options, signature, sigEncoding) { var pssSaltLength = getSaltLength(options); - key = toBuf(key); - if (!isArrayBufferView(key)) { - throw new ERR_INVALID_ARG_TYPE( - 'key', - ['string', 'Buffer', 'TypedArray', 'DataView'], - key - ); - } + key = checkIsArrayBufferView('key', toBuf(key)); - signature = toBuf(signature, sigEncoding); - if (!isArrayBufferView(signature)) { - throw new ERR_INVALID_ARG_TYPE( - 'signature', - ['string', 'Buffer', 'TypedArray', 'DataView'], - signature - ); - } + signature = checkIsArrayBufferView('signature', + toBuf(signature, sigEncoding)); return this._handle.verify(key, signature, rsaPadding, pssSaltLength); }; diff --git a/lib/internal/crypto/util.js b/lib/internal/crypto/util.js index 095ca0478bd99f..59a5d57a1e4f39 100644 --- a/lib/internal/crypto/util.js +++ b/lib/internal/crypto/util.js @@ -83,7 +83,19 @@ function timingSafeEqual(buf1, buf2) { return _timingSafeEqual(buf1, buf2); } +function checkIsArrayBufferView(name, buffer) { + if (!isArrayBufferView(buffer)) { + throw new ERR_INVALID_ARG_TYPE( + name, + ['string', 'Buffer', 'TypedArray', 'DataView'], + buffer + ); + } + return buffer; +} + module.exports = { + checkIsArrayBufferView, getCiphers, getCurves, getDefaultEncoding, From e17280e8c94e18740909e66081dae0801114e2f8 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Wed, 25 Apr 2018 09:11:37 +0200 Subject: [PATCH 021/173] crypto: make pbkdf2 use checkIsArrayBufferView MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit updates pbkdf2 to use checkIsArrayBufferView from internal/crypto/util. PR-URL: https://github.com/nodejs/node/pull/20251 Reviewed-By: Ben Noordhuis Reviewed-By: Joyee Cheung Reviewed-By: Tobias Nießen Reviewed-By: Colin Ihrig Reviewed-By: Trivikram Kamat Reviewed-By: James M Snell Reviewed-By: Tiancheng "Timothy" Gu --- lib/internal/crypto/pbkdf2.js | 17 +++-------------- test/parallel/test-crypto-pbkdf2.js | 3 ++- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/lib/internal/crypto/pbkdf2.js b/lib/internal/crypto/pbkdf2.js index 4a7f26b509b521..82ea9feb852649 100644 --- a/lib/internal/crypto/pbkdf2.js +++ b/lib/internal/crypto/pbkdf2.js @@ -7,10 +7,10 @@ const { ERR_OUT_OF_RANGE } = require('internal/errors').codes; const { + checkIsArrayBufferView, getDefaultEncoding, toBuf } = require('internal/crypto/util'); -const { isArrayBufferView } = require('internal/util/types'); const { PBKDF2 } = process.binding('crypto'); @@ -39,19 +39,8 @@ function _pbkdf2(password, salt, iterations, keylen, digest, callback) { if (digest !== null && typeof digest !== 'string') throw new ERR_INVALID_ARG_TYPE('digest', ['string', 'null'], digest); - password = toBuf(password); - salt = toBuf(salt); - - if (!isArrayBufferView(password)) { - throw new ERR_INVALID_ARG_TYPE('password', - ['string', 'Buffer', 'TypedArray'], - password); - } - - if (!isArrayBufferView(salt)) { - throw new ERR_INVALID_ARG_TYPE('salt', - ['string', 'Buffer', 'TypedArray'], salt); - } + password = checkIsArrayBufferView('password', toBuf(password)); + salt = checkIsArrayBufferView('salt', toBuf(salt)); if (typeof iterations !== 'number') throw new ERR_INVALID_ARG_TYPE('iterations', 'number', iterations); diff --git a/test/parallel/test-crypto-pbkdf2.js b/test/parallel/test-crypto-pbkdf2.js index b4ecd3c6061158..f65176132ae5c4 100644 --- a/test/parallel/test-crypto-pbkdf2.js +++ b/test/parallel/test-crypto-pbkdf2.js @@ -123,7 +123,8 @@ assert.throws( }); [1, {}, [], true, undefined, null].forEach((input) => { - const msgPart2 = `Buffer, or TypedArray. Received type ${typeof input}`; + const msgPart2 = 'Buffer, TypedArray, or DataView.' + + ` Received type ${typeof input}`; assert.throws( () => crypto.pbkdf2(input, 'salt', 8, 8, 'sha256', common.mustNotCall()), { From 769b6c8fd2e0a9282e64cb622cfad8b002748677 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Sun, 22 Apr 2018 22:22:25 +0200 Subject: [PATCH 022/173] test: fix flaky child-process-exec-kill-throws Kill the child process with `SIGKILL` to make sure the child process does not remain alive. Fixes: https://github.com/nodejs/node/issues/20139 PR-URL: https://github.com/nodejs/node/pull/20213 Reviewed-By: Rich Trott Reviewed-By: Luigi Pinca Reviewed-By: Trivikram Kamat Reviewed-By: Weijia Wang Reviewed-By: James M Snell --- test/parallel/test-child-process-exec-kill-throws.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/parallel/test-child-process-exec-kill-throws.js b/test/parallel/test-child-process-exec-kill-throws.js index 35e5ff8b7bce0f..d6a0d4da19eae7 100644 --- a/test/parallel/test-child-process-exec-kill-throws.js +++ b/test/parallel/test-child-process-exec-kill-throws.js @@ -19,7 +19,8 @@ if (process.argv[2] === 'child') { }; const cmd = `"${process.execPath}" "${__filename}" child`; - const options = { maxBuffer: 0 }; + const options = { maxBuffer: 0, killSignal: 'SIGKILL' }; + const child = cp.exec(cmd, options, common.mustCall((err, stdout, stderr) => { // Verify that if ChildProcess#kill() throws, the error is reported. assert.strictEqual(err.message, 'mock error', err); From 2de33434741510d73bc9d6fcf3c46d9ee9ec9d7f Mon Sep 17 00:00:00 2001 From: Gabriel Schulhof Date: Wed, 25 Apr 2018 11:49:37 -0400 Subject: [PATCH 023/173] n-api,test: make method static One non-static method remains PR-URL: https://github.com/nodejs/node/pull/20292 Reviewed-By: Colin Ihrig Reviewed-By: Trivikram Kamat --- test/addons-napi/test_reference/test_reference.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/addons-napi/test_reference/test_reference.c b/test/addons-napi/test_reference/test_reference.c index 641b1cb82ba8e1..75abc49ad3280e 100644 --- a/test/addons-napi/test_reference/test_reference.c +++ b/test/addons-napi/test_reference/test_reference.c @@ -11,7 +11,7 @@ static napi_value GetFinalizeCount(napi_env env, napi_callback_info info) { return result; } -void FinalizeExternal(napi_env env, void* data, void* hint) { +static void FinalizeExternal(napi_env env, void* data, void* hint) { int *actual_value = data; NAPI_ASSERT_RETURN_VOID(env, actual_value == &test_value, "The correct pointer was passed to the finalizer"); From 8d24b6ed348b35f7a5cb59867355faeca0b665ea Mon Sep 17 00:00:00 2001 From: Gabriel Schulhof Date: Wed, 25 Apr 2018 13:49:48 -0400 Subject: [PATCH 024/173] n-api: update cli documentation Fixes: https://github.com/nodejs/node/issues/20082 PR-URL: https://github.com/nodejs/node/pull/20301 Reviewed-By: Anna Henningsen Reviewed-By: Colin Ihrig Reviewed-By: Richard Lau Reviewed-By: Vse Mozhet Byt Reviewed-By: Trivikram Kamat --- doc/api/cli.md | 3 +-- doc/node.1 | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/doc/api/cli.md b/doc/api/cli.md index 164e370fff5e15..5de5f0ff6fafd1 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -144,8 +144,7 @@ tcp port and communicate using the [Chrome DevTools Protocol][]. added: v7.10.0 --> -Enable loading native modules compiled with the ABI-stable Node.js API (N-API) -(experimental). +This option is a no-op. It is kept for compatibility. ### `--no-deprecation` diff --git a/doc/node.1 b/doc/node.1 index 24d8260b8765ac..c3572acee7bf6b 100644 --- a/doc/node.1 +++ b/doc/node.1 @@ -122,8 +122,7 @@ V8 Inspector integration allows attaching Chrome DevTools and IDEs to Node.js in It uses the Chrome DevTools Protocol. . .It Fl -napi-modules -Enable loading native modules compiled with the ABI-stable Node.js API (N-API) -(experimental). +This option is a no-op. It is kept for compatibility. . .It Fl -no-deprecation Silence deprecation warnings. From b5c1c146f5c5ba39435cf9488488803dd401607a Mon Sep 17 00:00:00 2001 From: Gabriel Schulhof Date: Wed, 25 Apr 2018 13:15:50 -0400 Subject: [PATCH 025/173] n-api,test: remove superfluous persistent Remove a superfluos persistent from test_constructor_name.c. PR-URL: https://github.com/nodejs/node/pull/20299 Reviewed-By: Anna Henningsen Reviewed-By: Colin Ihrig --- test/addons-napi/test_constructor/test_constructor_name.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/test/addons-napi/test_constructor/test_constructor_name.c b/test/addons-napi/test_constructor/test_constructor_name.c index b30ea4333747d3..e12deb80d23af8 100644 --- a/test/addons-napi/test_constructor/test_constructor_name.c +++ b/test/addons-napi/test_constructor/test_constructor_name.c @@ -1,8 +1,6 @@ #include #include "../common.h" -napi_ref constructor_; - static napi_value New(napi_env env, napi_callback_info info) { napi_value _this; NAPI_CALL(env, napi_get_cb_info(env, info, NULL, NULL, &_this, NULL)); @@ -14,9 +12,6 @@ static napi_value Init(napi_env env, napi_value exports) { napi_value cons; NAPI_CALL(env, napi_define_class( env, "MyObject_Extra", 8, New, NULL, 0, NULL, &cons)); - - NAPI_CALL(env, - napi_create_reference(env, cons, 1, &constructor_)); return cons; } From 375994f9408fade75c7ef9dde914c9ce30086991 Mon Sep 17 00:00:00 2001 From: Eugene Ostroukhov Date: Tue, 24 Apr 2018 11:16:55 -0700 Subject: [PATCH 026/173] inspector: Use default uv_listen backlog size PR-URL: https://github.com/nodejs/node/pull/20254 Reviewed-By: Rich Trott Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: Ben Noordhuis Reviewed-By: Ali Ijaz Sheikh Reviewed-By: Trivikram Kamat --- src/inspector_socket_server.cc | 3 +- test/parallel/test-inspector-stress-http.js | 34 +++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 test/parallel/test-inspector-stress-http.js diff --git a/src/inspector_socket_server.cc b/src/inspector_socket_server.cc index 3725c19e93fb86..e69c8d768be156 100644 --- a/src/inspector_socket_server.cc +++ b/src/inspector_socket_server.cc @@ -587,7 +587,8 @@ int ServerSocket::Listen(InspectorSocketServer* inspector_server, CHECK_EQ(0, uv_tcp_init(loop, server)); int err = uv_tcp_bind(server, addr, 0); if (err == 0) { - err = uv_listen(reinterpret_cast(server), 1, + // 511 is the value used by a 'net' module by default + err = uv_listen(reinterpret_cast(server), 511, ServerSocket::SocketConnectedCallback); } if (err == 0) { diff --git a/test/parallel/test-inspector-stress-http.js b/test/parallel/test-inspector-stress-http.js new file mode 100644 index 00000000000000..4787c35e32c899 --- /dev/null +++ b/test/parallel/test-inspector-stress-http.js @@ -0,0 +1,34 @@ +// Flags: --expose-internals +'use strict'; +const common = require('../common'); + +common.skipIfInspectorDisabled(); + +const assert = require('assert'); +const { NodeInstance } = require('../common/inspector-helper.js'); + +async function testHttp(child, number) { + try { + await child.httpGet(null, '/json/list'); + return true; + } catch (e) { + console.error(`Attempt ${number} failed`, e); + return false; + } +} + +async function runTest() { + const child = new NodeInstance(undefined, ''); + + const promises = []; + for (let i = 0; i < 100; i++) { + promises.push(testHttp(child, i)); + } + const result = await Promise.all(promises); + assert(!result.some((a) => !a), 'Some attempts failed'); + return child.kill(); +} + +common.crashOnUnhandledRejection(); + +runTest(); From 1385ffcccff8c8a0bddbe9712db9e00e62208899 Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Tue, 17 Apr 2018 11:37:50 +0200 Subject: [PATCH 027/173] http: added aborted property to request PR-URL: https://github.com/nodejs/node/pull/20094 Reviewed-By: James M Snell Reviewed-By: Luigi Pinca --- doc/api/http.md | 12 +++++++++- doc/api/http2.md | 10 ++++++++ lib/_http_client.js | 6 ++++- lib/_http_incoming.js | 2 ++ lib/_http_server.js | 1 + lib/internal/http2/compat.js | 7 ++++++ test/parallel/test-http-aborted.js | 26 +++++++++++++++++++++ test/parallel/test-http2-compat-aborted.js | 27 ++++++++++++++++++++++ 8 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 test/parallel/test-http-aborted.js create mode 100644 test/parallel/test-http2-compat-aborted.js diff --git a/doc/api/http.md b/doc/api/http.md index d6f738cb81ff54..d3e495ea3df5a3 100644 --- a/doc/api/http.md +++ b/doc/api/http.md @@ -1483,7 +1483,7 @@ following additional events, methods, and properties. added: v0.3.8 --> -Emitted when the request has been aborted and the network socket has closed. +Emitted when the request has been aborted. ### Event: 'close' + +* {boolean} + +The `message.aborted` property will be `true` if the request has +been aborted. + ### message.destroy([error]) + +* {boolean} + +The `request.aborted` property will be `true` if the request has +been aborted. + #### request.destroy([error]) * Returns: {integer} The `os.uptime()` method returns the system uptime in number of seconds. -On Windows the returned value includes fractions of a second. Use `Math.floor()` -to get whole seconds. - ## os.userInfo([options]) -* `array` {Array|Object} -* `columns` {string[]} Display only selected properties of objects in the - `array`. - -This method does not display anything unless used in the inspector. Prints to -`stdout` the array `array` formatted as a table. - ### console.timeStamp([label]) -The `'goaway'` event is emitted when a `GOAWAY` frame is received. When invoked, -the handler function will receive three arguments: - * `errorCode` {number} The HTTP/2 error code specified in the `GOAWAY` frame. * `lastStreamID` {number} The ID of the last stream the remote peer successfully processed (or `0` if no ID is specified). * `opaqueData` {Buffer} If additional opaque data was included in the `GOAWAY` frame, a `Buffer` instance will be passed containing that data. +The `'goaway'` event is emitted when a `GOAWAY` frame is received. + The `Http2Session` instance will be shut down automatically when the `'goaway'` event is emitted. From 8ddbac2fd6c7506da2f66d2adf2050ac8b703149 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Wed, 25 Apr 2018 17:51:32 +0200 Subject: [PATCH 046/173] tools: add log output to crashes PR-URL: https://github.com/nodejs/node/pull/20295 Reviewed-By: Richard Lau Reviewed-By: Joyee Cheung Reviewed-By: Matheus Marchini Reviewed-By: Trivikram Kamat Reviewed-By: James M Snell Reviewed-By: Refael Ackermann --- tools/test.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tools/test.py b/tools/test.py index e652e47092c55b..a0a3121e486b3e 100755 --- a/tools/test.py +++ b/tools/test.py @@ -298,10 +298,8 @@ def HasRun(self, output): if output.HasCrashed(): self.severity = 'crashed' - exit_code = output.output.exit_code - self.traceback = "oh no!\nexit code: " + PrintCrashed(exit_code) - if output.HasTimedOut(): + elif output.HasTimedOut(): self.severity = 'fail' else: From a12d13ad06c1a1e1ae037332183dd1e4fd743d9e Mon Sep 17 00:00:00 2001 From: Vse Mozhet Byt Date: Wed, 25 Apr 2018 23:44:38 +0300 Subject: [PATCH 047/173] tools: simplify HTML generation PR-URL: https://github.com/nodejs/node/pull/20307 Reviewed-By: Anna Henningsen Reviewed-By: Ruben Bridgewater Reviewed-By: Trivikram Kamat --- Makefile | 2 +- test/doctool/test-doctool-html.js | 2 - tools/doc/generate.js | 5 +- tools/doc/html.js | 85 ++++++++----------------------- 4 files changed, 24 insertions(+), 70 deletions(-) diff --git a/Makefile b/Makefile index 6736d601685dce..b3e65cec6030a9 100644 --- a/Makefile +++ b/Makefile @@ -652,7 +652,7 @@ tools/doc/node_modules/js-yaml/package.json: gen-json = tools/doc/generate.js --format=json $< > $@ gen-html = tools/doc/generate.js --node-version=$(FULLVERSION) --format=html \ - --template=doc/template.html --analytics=$(DOCS_ANALYTICS) $< > $@ + --analytics=$(DOCS_ANALYTICS) $< > $@ out/doc/api/%.json: doc/api/%.md $(call available-node, $(gen-json)) diff --git a/test/doctool/test-doctool-html.js b/test/doctool/test-doctool-html.js index bd1c5ddecac321..91037bfd6501bc 100644 --- a/test/doctool/test-doctool-html.js +++ b/test/doctool/test-doctool-html.js @@ -10,7 +10,6 @@ try { const assert = require('assert'); const fs = require('fs'); -const path = require('path'); const fixtures = require('../common/fixtures'); const processIncludes = require('../../tools/doc/preprocess.js'); const html = require('../../tools/doc/html.js'); @@ -107,7 +106,6 @@ testData.forEach((item) => { { input: preprocessed, filename: 'foo', - template: path.resolve(__dirname, '../../doc/template.html'), nodeVersion: process.version, analytics: item.analyticsId, }, diff --git a/tools/doc/generate.js b/tools/doc/generate.js index 0da9dba4e6558f..9f217b19c7225f 100644 --- a/tools/doc/generate.js +++ b/tools/doc/generate.js @@ -29,7 +29,6 @@ const fs = require('fs'); const args = process.argv.slice(2); let format = 'json'; -let template = null; let filename = null; let nodeVersion = null; let analytics = null; @@ -39,8 +38,6 @@ args.forEach(function(arg) { filename = arg; } else if (arg.startsWith('--format=')) { format = arg.replace(/^--format=/, ''); - } else if (arg.startsWith('--template=')) { - template = arg.replace(/^--template=/, ''); } else if (arg.startsWith('--node-version=')) { nodeVersion = arg.replace(/^--node-version=/, ''); } else if (arg.startsWith('--analytics=')) { @@ -71,7 +68,7 @@ function next(er, input) { break; case 'html': - require('./html')({ input, filename, template, nodeVersion, analytics }, + require('./html')({ input, filename, nodeVersion, analytics }, (err, html) => { if (err) throw err; console.log(html); diff --git a/tools/doc/html.js b/tools/doc/html.js index ff0230309ee99a..439fc057012ca7 100644 --- a/tools/doc/html.js +++ b/tools/doc/html.js @@ -25,7 +25,6 @@ const common = require('./common.js'); const fs = require('fs'); const marked = require('marked'); const path = require('path'); -const preprocess = require('./preprocess.js'); const typeParser = require('./type-parser.js'); module.exports = toHTML; @@ -42,76 +41,36 @@ marked.setOptions({ renderer: renderer }); -// TODO(chrisdickinson): never stop vomiting / fix this. -const gtocPath = path.resolve(path.join( - __dirname, - '..', - '..', - 'doc', - 'api', - '_toc.md' -)); -var gtocLoading = null; -var gtocData = null; +const docPath = path.resolve(__dirname, '..', '..', 'doc'); + +const gtocPath = path.join(docPath, 'api', '_toc.md'); +const gtocMD = fs.readFileSync(gtocPath, 'utf8').replace(/^@\/\/.*$/gm, ''); +const gtocHTML = marked(gtocMD).replace( + / ` Date: Wed, 25 Apr 2018 14:05:39 -0500 Subject: [PATCH 048/173] doc: remove eu-strip from tarball This is been removed because of this: the source is not provided it adds 105ko of useless files It's only used in the android and fuchsia GN builds Fixes: #20280 PR-URL: https://github.com/nodejs/node/pull/20304 Fixes: https://github.com/nodejs/node/issues/20280 Reviewed-By: Ben Noordhuis Reviewed-By: Anna Henningsen Reviewed-By: Richard Lau Reviewed-By: Colin Ihrig Reviewed-By: Ruben Bridgewater Reviewed-By: Matheus Marchini Reviewed-By: Trivikram Kamat Reviewed-By: James M Snell --- .gitignore | 1 + deps/v8/third_party/eu-strip/README.v8 | 24 ---------------------- deps/v8/third_party/eu-strip/bin/eu-strip | Bin 105120 -> 0 bytes 3 files changed, 1 insertion(+), 24 deletions(-) delete mode 100644 deps/v8/third_party/eu-strip/README.v8 delete mode 100755 deps/v8/third_party/eu-strip/bin/eu-strip diff --git a/.gitignore b/.gitignore index 7be817acce2349..ebeedeac6b8fe0 100644 --- a/.gitignore +++ b/.gitignore @@ -127,3 +127,4 @@ deps/v8/src/Debug/ deps/v8/src/Release/ deps/v8/src/inspector/Debug/ deps/v8/src/inspector/Release/ +deps/v8/third_party/eu-strip/ diff --git a/deps/v8/third_party/eu-strip/README.v8 b/deps/v8/third_party/eu-strip/README.v8 deleted file mode 100644 index e84974d92b9cec..00000000000000 --- a/deps/v8/third_party/eu-strip/README.v8 +++ /dev/null @@ -1,24 +0,0 @@ -Name: eu-strip -URL: https://sourceware.org/elfutils/ -Version: 0.158 -Security Critical: no -License: LGPL 3 -License File: NOT_SHIPPED - -Description: - -Patched eu-strip from elfutils. - -Build instructions (on Trusty; note that this will build the -Ubuntu-patched version of elfutils): -$ mkdir elfutils -$ cd elfutils -$ apt-get source elfutils -$ cd elfutils-0.158 -[ Edit libelf/elf_end.c and remove the free() on line 164. ] -$ ./configure -$ make -$ gcc -std=gnu99 -Wall -Wshadow -Wunused -Wextra -fgnu89-inline - -Wformat=2 -Werror -g -O2 -Wl,-rpath-link,libelf:libdw -o eu-strip - src/strip.o libebl/libebl.a libelf/libelf.a lib/libeu.a -ldl -$ eu-strip ./eu-strip # Keep the binary small, please. diff --git a/deps/v8/third_party/eu-strip/bin/eu-strip b/deps/v8/third_party/eu-strip/bin/eu-strip deleted file mode 100755 index 994e2263b9185f77169c6c8545869d3c84cf0a8a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 105120 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 qqL|@9Ud( Date: Thu, 26 Apr 2018 02:28:08 +0300 Subject: [PATCH 049/173] tools: remove redundant RegExp flag PR-URL: https://github.com/nodejs/node/pull/20309 Reviewed-By: Ruben Bridgewater Reviewed-By: Colin Ihrig Reviewed-By: Trivikram Kamat Reviewed-By: James M Snell --- tools/doc/preprocess.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/doc/preprocess.js b/tools/doc/preprocess.js index f8d394735dd30b..554af2ccb77ae0 100644 --- a/tools/doc/preprocess.js +++ b/tools/doc/preprocess.js @@ -6,7 +6,7 @@ const path = require('path'); const fs = require('fs'); const includeExpr = /^@include\s+([\w-]+)(?:\.md)?$/gmi; -const commentExpr = /^@\/\/.*$/gmi; +const commentExpr = /^@\/\/.*$/gm; function processIncludes(inputFile, input, cb) { const includes = input.match(includeExpr); From be34388a079fd9fe3d957b4b4a7f5a1cdc1b99dc Mon Sep 17 00:00:00 2001 From: Vse Mozhet Byt Date: Thu, 26 Apr 2018 02:49:11 +0300 Subject: [PATCH 050/173] doc: unify and dedupe returned values in timers.md PR-URL: https://github.com/nodejs/node/pull/20310 Reviewed-By: Ruben Bridgewater Reviewed-By: Trivikram Kamat Reviewed-By: James M Snell Reviewed-By: Tiancheng "Timothy" Gu --- doc/api/timers.md | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/doc/api/timers.md b/doc/api/timers.md index 0cc535352a0697..e3e995004781f0 100644 --- a/doc/api/timers.md +++ b/doc/api/timers.md @@ -28,7 +28,7 @@ functions that can be used to control this default behavior. added: v9.7.0 --> -* Returns: {Immediate} +* Returns: {Immediate} a reference to `immediate` When called, requests that the Node.js event loop *not* exit so long as the `Immediate` is active. Calling `immediate.ref()` multiple times will have no @@ -37,22 +37,18 @@ effect. By default, all `Immediate` objects are "ref'ed", making it normally unnecessary to call `immediate.ref()` unless `immediate.unref()` had been called previously. -Returns a reference to the `Immediate`. - ### immediate.unref() -* Returns: {Immediate} +* Returns: {Immediate} a reference to `immediate` When called, the active `Immediate` object will not require the Node.js event loop to remain active. If there is no other activity keeping the event loop running, the process may exit before the `Immediate` object's callback is invoked. Calling `immediate.unref()` multiple times will have no effect. -Returns a reference to the `Immediate`. - ## Class: Timeout This object is created internally and is returned from [`setTimeout()`][] and @@ -70,7 +66,7 @@ control this default behavior. added: v0.9.1 --> -* Returns: {Timeout} +* Returns: {Timeout} a reference to `timeout` When called, requests that the Node.js event loop *not* exit so long as the `Timeout` is active. Calling `timeout.ref()` multiple times will have no effect. @@ -78,14 +74,12 @@ When called, requests that the Node.js event loop *not* exit so long as the By default, all `Timeout` objects are "ref'ed", making it normally unnecessary to call `timeout.ref()` unless `timeout.unref()` had been called previously. -Returns a reference to the `Timeout`. - ### timeout.unref() -* Returns: {Timeout} +* Returns: {Timeout} a reference to `timeout` When called, the active `Timeout` object will not require the Node.js event loop to remain active. If there is no other activity keeping the event loop running, @@ -96,8 +90,6 @@ Calling `timeout.unref()` creates an internal timer that will wake the Node.js event loop. Creating too many of these can adversely impact performance of the Node.js application. -Returns a reference to the `Timeout`. - ## Scheduling Timers A timer in Node.js is an internal construct that calls a given function after @@ -113,9 +105,10 @@ added: v0.9.1 * `callback` {Function} The function to call at the end of this turn of [the Node.js Event Loop] * `...args` {any} Optional arguments to pass when the `callback` is called. +* Returns: {Immediate} for use with [`clearImmediate()`][] Schedules the "immediate" execution of the `callback` after I/O events' -callbacks. Returns an `Immediate` for use with [`clearImmediate()`][]. +callbacks. When multiple calls to `setImmediate()` are made, the `callback` functions are queued for execution in the order in which they are created. The entire callback @@ -155,10 +148,9 @@ added: v0.0.1 * `delay` {number} The number of milliseconds to wait before calling the `callback`. * `...args` {any} Optional arguments to pass when the `callback` is called. -* Returns: {Timeout} +* Returns: {Timeout} for use with [`clearInterval()`][] Schedules repeated execution of `callback` every `delay` milliseconds. -Returns a `Timeout` for use with [`clearInterval()`][]. When `delay` is larger than `2147483647` or less than `1`, the `delay` will be set to `1`. @@ -174,10 +166,9 @@ added: v0.0.1 * `delay` {number} The number of milliseconds to wait before calling the `callback`. * `...args` {any} Optional arguments to pass when the `callback` is called. -* Returns: {Timeout} +* Returns: {Timeout} for use with [`clearTimeout()`][] Schedules execution of a one-time `callback` after `delay` milliseconds. -Returns a `Timeout` for use with [`clearTimeout()`][]. The `callback` will likely not be invoked in precisely `delay` milliseconds. Node.js makes no guarantees about the exact timing of when callbacks will fire, From 29bc735d42e7d821e31c4d6811b66725191ad807 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Wed, 25 Apr 2018 22:47:56 -0700 Subject: [PATCH 051/173] console: fix console.table() display edge case If the properties are not specified in `console.table()`, then we should make a best effort to determine them rather than put all values into a "Values" column. PR-URL: https://github.com/nodejs/node/pull/20323 Reviewed-By: Gus Caplan Reviewed-By: Trivikram Kamat Reviewed-By: Benjamin Gruenbaum Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: Ruben Bridgewater Reviewed-By: James M Snell --- lib/console.js | 4 +--- test/parallel/test-console-table.js | 31 +++++++++++++++++++---------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/lib/console.js b/lib/console.js index 39bcf701bf83eb..a0158ec6643782 100644 --- a/lib/console.js +++ b/lib/console.js @@ -363,9 +363,7 @@ Console.prototype.table = function(tabularData, properties) { tabularData = previewSetIterator(tabularData); const setlike = setIter || isSet(tabularData); - if (setlike || - (properties === undefined && - (isArray(tabularData) || isTypedArray(tabularData)))) { + if (setlike) { const values = []; let length = 0; for (const v of tabularData) { diff --git a/test/parallel/test-console-table.js b/test/parallel/test-console-table.js index 39e9099dd717d4..64e2533f175e1d 100644 --- a/test/parallel/test-console-table.js +++ b/test/parallel/test-console-table.js @@ -41,13 +41,13 @@ test([1, 2, 3], ` `); test([Symbol(), 5, [10]], ` -┌─────────┬──────────┐ -│ (index) │ Values │ -├─────────┼──────────┤ -│ 0 │ Symbol() │ -│ 1 │ 5 │ -│ 2 │ [ 10 ] │ -└─────────┴──────────┘ +┌─────────┬────┬──────────┐ +│ (index) │ 0 │ Values │ +├─────────┼────┼──────────┤ +│ 0 │ │ Symbol() │ +│ 1 │ │ 5 │ +│ 2 │ 10 │ │ +└─────────┴────┴──────────┘ `); test([undefined, 5], ` @@ -182,10 +182,10 @@ test({ a: undefined }, ['x'], ` `); test([], ` -┌─────────┬────────┐ -│ (index) │ Values │ -├─────────┼────────┤ -└─────────┴────────┘ +┌─────────┐ +│ (index) │ +├─────────┤ +└─────────┘ `); test(new Map(), ` @@ -194,3 +194,12 @@ test(new Map(), ` ├───────────────────┼─────┼────────┤ └───────────────────┴─────┴────────┘ `); + +test([{ a: 1, b: 'Y' }, { a: 'Z', b: 2 }], ` +┌─────────┬─────┬─────┐ +│ (index) │ a │ b │ +├─────────┼─────┼─────┤ +│ 0 │ 1 │ 'Y' │ +│ 1 │ 'Z' │ 2 │ +└─────────┴─────┴─────┘ +`); From 3962c734aeade280766d9c2f202caa4459328539 Mon Sep 17 00:00:00 2001 From: Anatoli Papirovski Date: Wed, 25 Apr 2018 00:56:35 +0200 Subject: [PATCH 052/173] util: fix isInsideNodeModules inside error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When isInsideNodeModules gets called while already processing another stack trace, V8 will not call prepareStackTrace again. This used to cause Node.js to just crash — fix it by checking for expected return type of the stack (Array). PR-URL: https://github.com/nodejs/node/pull/20266 Fixes: https://github.com/nodejs/node/issues/20258 Reviewed-By: Anna Henningsen Reviewed-By: James M Snell Reviewed-By: Trivikram Kamat --- lib/internal/util.js | 19 ++++++++++--------- ...st-buffer-constructor-deprecation-error.js | 17 +++++++++++++++++ 2 files changed, 27 insertions(+), 9 deletions(-) create mode 100644 test/parallel/test-buffer-constructor-deprecation-error.js diff --git a/lib/internal/util.js b/lib/internal/util.js index ce25317b778a3f..071563a737815b 100644 --- a/lib/internal/util.js +++ b/lib/internal/util.js @@ -356,16 +356,17 @@ function isInsideNodeModules() { // Iterate over all stack frames and look for the first one not coming // from inside Node.js itself: - for (const frame of stack) { - const filename = frame.getFileName(); - // If a filename does not start with / or contain \, - // it's likely from Node.js core. - if (!/^\/|\\/.test(filename)) - continue; - return kNodeModulesRE.test(filename); + if (Array.isArray(stack)) { + for (const frame of stack) { + const filename = frame.getFileName(); + // If a filename does not start with / or contain \, + // it's likely from Node.js core. + if (!/^\/|\\/.test(filename)) + continue; + return kNodeModulesRE.test(filename); + } } - - return false; // This should be unreachable. + return false; } diff --git a/test/parallel/test-buffer-constructor-deprecation-error.js b/test/parallel/test-buffer-constructor-deprecation-error.js new file mode 100644 index 00000000000000..46535e103b33ee --- /dev/null +++ b/test/parallel/test-buffer-constructor-deprecation-error.js @@ -0,0 +1,17 @@ +'use strict'; + +const common = require('../common'); + +const bufferWarning = 'Buffer() is deprecated due to security and usability ' + + 'issues. Please use the Buffer.alloc(), ' + + 'Buffer.allocUnsafe(), or Buffer.from() methods instead.'; + +common.expectWarning('DeprecationWarning', bufferWarning, 'DEP0005'); + +// This is used to make sure that a warning is only emitted once even though +// `new Buffer()` is called twice. +process.on('warning', common.mustCall()); + +Error.prepareStackTrace = (err, trace) => new Buffer(10); + +new Error().stack; From 31812edb2d34c97193a912eaab671f383c6b7f42 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Fri, 27 Apr 2018 15:21:17 +0200 Subject: [PATCH 053/173] src: remove unnecessary copy operations in tracing PR-URL: https://github.com/nodejs/node/pull/20356 Reviewed-By: James M Snell Reviewed-By: Colin Ihrig Reviewed-By: Anatoli Papirovski --- src/node_trace_events.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/node_trace_events.cc b/src/node_trace_events.cc index 1e02048d1f0843..f37537d54544a2 100644 --- a/src/node_trace_events.cc +++ b/src/node_trace_events.cc @@ -63,7 +63,7 @@ void NodeCategorySet::Enable(const FunctionCallbackInfo& args) { NodeCategorySet* category_set; ASSIGN_OR_RETURN_UNWRAP(&category_set, args.Holder()); CHECK_NE(category_set, nullptr); - auto categories = category_set->GetCategories(); + const auto& categories = category_set->GetCategories(); if (!category_set->enabled_ && !categories.empty()) { env->tracing_agent()->Enable(categories); category_set->enabled_ = true; @@ -75,7 +75,7 @@ void NodeCategorySet::Disable(const FunctionCallbackInfo& args) { NodeCategorySet* category_set; ASSIGN_OR_RETURN_UNWRAP(&category_set, args.Holder()); CHECK_NE(category_set, nullptr); - auto categories = category_set->GetCategories(); + const auto& categories = category_set->GetCategories(); if (category_set->enabled_ && !categories.empty()) { env->tracing_agent()->Disable(categories); category_set->enabled_ = false; From b0e6f10530e5ae2168ff7edd7fb9c6ffa8a8fbe5 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Sat, 14 Apr 2018 18:26:57 +0200 Subject: [PATCH 054/173] benchmark: add bench for zlib gzip + gunzip cycle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Originally wrote this for some work that is going to take a while longer before it’s ready to be PR’ed, so it seems fine to start with this on its own. PR-URL: https://github.com/nodejs/node/pull/20034 Reviewed-By: James M Snell Reviewed-By: Luigi Pinca Reviewed-By: Ruben Bridgewater --- benchmark/zlib/pipe.js | 39 ++++++++++++++++++++++++++++ test/parallel/test-benchmark-zlib.js | 9 +++++-- 2 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 benchmark/zlib/pipe.js diff --git a/benchmark/zlib/pipe.js b/benchmark/zlib/pipe.js new file mode 100644 index 00000000000000..9b05749bbb824d --- /dev/null +++ b/benchmark/zlib/pipe.js @@ -0,0 +1,39 @@ +'use strict'; +const common = require('../common.js'); +const fs = require('fs'); +const zlib = require('zlib'); + +const bench = common.createBenchmark(main, { + inputLen: [1024], + duration: [5], + type: ['string', 'buffer'] +}); + +function main({ inputLen, duration, type }) { + const buffer = Buffer.alloc(inputLen, fs.readFileSync(__filename)); + const chunk = type === 'buffer' ? buffer : buffer.toString('utf8'); + + const input = zlib.createGzip(); + const output = zlib.createGunzip(); + + let readFromOutput = 0; + input.pipe(output); + if (type === 'string') + output.setEncoding('utf8'); + output.on('data', (chunk) => readFromOutput += chunk.length); + + function write() { + input.write(chunk, write); + } + + bench.start(); + write(); + + setTimeout(() => { + // Give result in GBit/s, like the net benchmarks do + bench.end(readFromOutput * 8 / (1024 ** 3)); + + // Cut off writing the easy way. + input.write = () => {}; + }, duration * 1000); +} diff --git a/test/parallel/test-benchmark-zlib.js b/test/parallel/test-benchmark-zlib.js index 350d05552cda39..25b7d1a4d5f905 100644 --- a/test/parallel/test-benchmark-zlib.js +++ b/test/parallel/test-benchmark-zlib.js @@ -9,5 +9,10 @@ runBenchmark('zlib', 'method=deflate', 'n=1', 'options=true', - 'type=Deflate' - ]); + 'type=Deflate', + 'inputLen=1024', + 'duration=0.001' + ], + { + 'NODEJS_BENCHMARK_ZERO_ALLOWED': 1 + }); From fd912a37a08c5ffaa1ca022ea6ca4114cb1e6aec Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Fri, 27 Apr 2018 09:39:24 +0200 Subject: [PATCH 055/173] stream: only check options once in Duplex ctor This commit updates the Duplex constructor adding an if statement checking if options is undefined, and removes the check from the following three if statements. PR-URL: https://github.com/nodejs/node/pull/20353 Reviewed-By: Ruben Bridgewater Reviewed-By: James M Snell Reviewed-By: Anna Henningsen Reviewed-By: Luigi Pinca --- lib/_stream_duplex.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/_stream_duplex.js b/lib/_stream_duplex.js index b123cdcb4d776f..7059757dbd44b1 100644 --- a/lib/_stream_duplex.js +++ b/lib/_stream_duplex.js @@ -50,17 +50,19 @@ function Duplex(options) { Readable.call(this, options); Writable.call(this, options); + this.allowHalfOpen = true; - if (options && options.readable === false) - this.readable = false; + if (options) { + if (options.readable === false) + this.readable = false; - if (options && options.writable === false) - this.writable = false; + if (options.writable === false) + this.writable = false; - this.allowHalfOpen = true; - if (options && options.allowHalfOpen === false) { - this.allowHalfOpen = false; - this.once('end', onend); + if (options.allowHalfOpen === false) { + this.allowHalfOpen = false; + this.once('end', onend); + } } } From e45e5b809d88b2b117b110e135f689c91386a23b Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Thu, 26 Apr 2018 13:22:14 +0200 Subject: [PATCH 056/173] fs: point isFd to isUint32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit updates the isFd function to call isUint32 instead of doing the same thing. PR-URL: https://github.com/nodejs/node/pull/20330 Reviewed-By: Benjamin Gruenbaum Reviewed-By: Tobias Nießen Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: Richard Lau Reviewed-By: Joyee Cheung Reviewed-By: Ruben Bridgewater Reviewed-By: James M Snell --- lib/fs.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/fs.js b/lib/fs.js index d71e31565fbad6..2d41f17e8d1de5 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -151,9 +151,7 @@ function makeStatsCallback(cb) { }; } -function isFd(path) { - return (path >>> 0) === path; -} +const isFd = isUint32; fs.Stats = Stats; From 9b30bc4f81507ef812bbb52fd4355a8cda66a925 Mon Sep 17 00:00:00 2001 From: Shigeki Ohtsu Date: Wed, 25 Apr 2018 12:10:26 +0900 Subject: [PATCH 057/173] tls: fix getEphemeralKeyInfo to support X25519 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `EVP_PKEY_EC` only covers ANSI X9.62 curves not IETF ones(curve25519 and curve448). This fixes to add support of X25519 in `tlsSocket.getEphemeralKeyInfo()`. X448 should be added in the future upgrade to OpenSSL-1.1.1. PR-URL: https://github.com/nodejs/node/pull/20273 Fixes: https://github.com/nodejs/node/issues/20262 Reviewed-By: Daniel Bevenius Reviewed-By: Ben Noordhuis Reviewed-By: Tobias Nießen --- src/node_crypto.cc | 21 ++++++++++++++----- src/node_crypto.h | 2 ++ .../test-tls-client-getephemeralkeyinfo.js | 9 ++++++-- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/node_crypto.cc b/src/node_crypto.cc index d9af0b4fa2f1b9..34018384eeeb75 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -2096,7 +2096,8 @@ void SSLWrap::GetEphemeralKeyInfo( EVP_PKEY* key; if (SSL_get_server_tmp_key(w->ssl_, &key)) { - switch (EVP_PKEY_id(key)) { + int kid = EVP_PKEY_id(key); + switch (kid) { case EVP_PKEY_DH: info->Set(context, env->type_string(), FIXED_ONE_BYTE_STRING(env->isolate(), "DH")).FromJust(); @@ -2104,19 +2105,29 @@ void SSLWrap::GetEphemeralKeyInfo( Integer::New(env->isolate(), EVP_PKEY_bits(key))).FromJust(); break; case EVP_PKEY_EC: + // TODO(shigeki) Change this to EVP_PKEY_X25519 and add EVP_PKEY_X448 + // after upgrading to 1.1.1. + case NID_X25519: { - EC_KEY* ec = EVP_PKEY_get1_EC_KEY(key); - int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec)); - EC_KEY_free(ec); + const char* curve_name; + if (kid == EVP_PKEY_EC) { + EC_KEY* ec = EVP_PKEY_get1_EC_KEY(key); + int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec)); + curve_name = OBJ_nid2sn(nid); + EC_KEY_free(ec); + } else { + curve_name = OBJ_nid2sn(kid); + } info->Set(context, env->type_string(), FIXED_ONE_BYTE_STRING(env->isolate(), "ECDH")).FromJust(); info->Set(context, env->name_string(), OneByteString(args.GetIsolate(), - OBJ_nid2sn(nid))).FromJust(); + curve_name)).FromJust(); info->Set(context, env->size_string(), Integer::New(env->isolate(), EVP_PKEY_bits(key))).FromJust(); } + break; } EVP_PKEY_free(key); } diff --git a/src/node_crypto.h b/src/node_crypto.h index 31806b04434702..df7f47c82ab159 100644 --- a/src/node_crypto.h +++ b/src/node_crypto.h @@ -44,6 +44,8 @@ #endif // !OPENSSL_NO_ENGINE #include #include +// TODO(shigeki) Remove this after upgrading to 1.1.1 +#include #include #include #include diff --git a/test/parallel/test-tls-client-getephemeralkeyinfo.js b/test/parallel/test-tls-client-getephemeralkeyinfo.js index be6777b1ae0049..9432a277ac0fd0 100644 --- a/test/parallel/test-tls-client-getephemeralkeyinfo.js +++ b/test/parallel/test-tls-client-getephemeralkeyinfo.js @@ -82,7 +82,12 @@ function testECDHE256() { } function testECDHE512() { - test(521, 'ECDH', 'secp521r1', null); + test(521, 'ECDH', 'secp521r1', testX25519); + ntests++; +} + +function testX25519() { + test(253, 'ECDH', 'X25519', null); ntests++; } @@ -90,5 +95,5 @@ testNOT_PFS(); process.on('exit', function() { assert.strictEqual(ntests, nsuccess); - assert.strictEqual(ntests, 5); + assert.strictEqual(ntests, 6); }); From 46bd86235d483516a9c51ddf59ddeeff20145519 Mon Sep 17 00:00:00 2001 From: Anatoli Papirovski Date: Mon, 16 Apr 2018 22:03:10 +0200 Subject: [PATCH 058/173] http2: fix responses to long payload reqs When a request with a long payload is received, http2 does not allow a response that does not process all the incoming payload. Add a conditional Http2Stream.close call that runs only if the user hasn't attempted to read the stream. PR-URL: https://github.com/nodejs/node/pull/20084 Fixes: https://github.com/nodejs/node/issues/20060 Reviewed-By: Anna Henningsen Reviewed-By: James M Snell Reviewed-By: Matteo Collina --- lib/internal/http2/core.js | 181 ++++++++++-------- src/node_http2.cc | 69 +++++-- src/node_http2.h | 10 +- test/fixtures/person-large.jpg | Bin 0 -> 139837 bytes test/parallel/test-http2-client-destroy.js | 18 ++ ...t-http2-client-rststream-before-connect.js | 10 +- .../test-http2-client-upload-reject.js | 48 +++++ test/parallel/test-http2-client-upload.js | 2 +- test/parallel/test-http2-large-write-close.js | 44 +++++ test/parallel/test-http2-perf_hooks.js | 2 +- 10 files changed, 279 insertions(+), 105 deletions(-) create mode 100644 test/fixtures/person-large.jpg create mode 100644 test/parallel/test-http2-client-upload-reject.js create mode 100644 test/parallel/test-http2-large-write-close.js diff --git a/lib/internal/http2/core.js b/lib/internal/http2/core.js index 495fa60ba39ce3..be5d08a0b0a1f5 100644 --- a/lib/internal/http2/core.js +++ b/lib/internal/http2/core.js @@ -206,6 +206,7 @@ const STREAM_FLAGS_CLOSED = 0x2; const STREAM_FLAGS_HEADERS_SENT = 0x4; const STREAM_FLAGS_HEAD_REQUEST = 0x8; const STREAM_FLAGS_ABORTED = 0x10; +const STREAM_FLAGS_HAS_TRAILERS = 0x20; const SESSION_FLAGS_PENDING = 0x0; const SESSION_FLAGS_READY = 0x1; @@ -330,26 +331,13 @@ function onStreamClose(code) { if (stream.destroyed) return; - const state = stream[kState]; - debug(`Http2Stream ${stream[kID]} [Http2Session ` + `${sessionName(stream[kSession][kType])}]: closed with code ${code}`); - if (!stream.closed) { - // Clear timeout and remove timeout listeners - stream.setTimeout(0); - stream.removeAllListeners('timeout'); + if (!stream.closed) + closeStream(stream, code, false); - // Set the state flags - state.flags |= STREAM_FLAGS_CLOSED; - state.rstCode = code; - - // Close the writable side of the stream - abort(stream); - stream.end(); - } - - state.fd = -1; + stream[kState].fd = -1; // Defer destroy we actually emit end. if (stream._readableState.endEmitted || code !== NGHTTP2_NO_ERROR) { // If errored or ended, we can destroy immediately. @@ -504,7 +492,7 @@ function requestOnConnect(headers, options) { // At this point, the stream should have already been destroyed during // the session.destroy() method. Do nothing else. - if (session.destroyed) + if (session === undefined || session.destroyed) return; // If the session was closed while waiting for the connect, destroy @@ -1412,6 +1400,9 @@ class ClientHttp2Session extends Http2Session { if (options.endStream) stream.end(); + if (options.waitForTrailers) + stream[kState].flags |= STREAM_FLAGS_HAS_TRAILERS; + const onConnect = requestOnConnect.bind(stream, headersList, options); if (this.connecting) { this.on('connect', onConnect); @@ -1445,8 +1436,11 @@ function afterDoStreamWrite(status, handle) { } function streamOnResume() { - if (!this.destroyed && !this.pending) + if (!this.destroyed && !this.pending) { + if (!this[kState].didRead) + this[kState].didRead = true; this[kHandle].readStart(); + } } function streamOnPause() { @@ -1454,16 +1448,6 @@ function streamOnPause() { this[kHandle].readStop(); } -// If the writable side of the Http2Stream is still open, emit the -// 'aborted' event and set the aborted flag. -function abort(stream) { - if (!stream.aborted && - !(stream._writableState.ended || stream._writableState.ending)) { - stream[kState].flags |= STREAM_FLAGS_ABORTED; - stream.emit('aborted'); - } -} - function afterShutdown() { this.callback(); const stream = this.handle[kOwner]; @@ -1471,6 +1455,51 @@ function afterShutdown() { stream[kMaybeDestroy](); } +function closeStream(stream, code, shouldSubmitRstStream = true) { + const state = stream[kState]; + state.flags |= STREAM_FLAGS_CLOSED; + state.rstCode = code; + + // Clear timeout and remove timeout listeners + stream.setTimeout(0); + stream.removeAllListeners('timeout'); + + const { ending, finished } = stream._writableState; + + if (!ending) { + // If the writable side of the Http2Stream is still open, emit the + // 'aborted' event and set the aborted flag. + if (!stream.aborted) { + state.flags |= STREAM_FLAGS_ABORTED; + stream.emit('aborted'); + } + + // Close the writable side. + stream.end(); + } + + if (shouldSubmitRstStream) { + const finishFn = finishCloseStream.bind(stream, code); + if (!ending || finished || code !== NGHTTP2_NO_ERROR) + finishFn(); + else + stream.once('finish', finishFn); + } +} + +function finishCloseStream(code) { + const rstStreamFn = submitRstStream.bind(this, code); + // If the handle has not yet been assigned, queue up the request to + // ensure that the RST_STREAM frame is sent after the stream ID has + // been determined. + if (this.pending) { + this.push(null); + this.once('ready', rstStreamFn); + return; + } + rstStreamFn(); +} + // An Http2Stream is a Duplex stream that is backed by a // node::http2::Http2Stream handle implementing StreamBase. class Http2Stream extends Duplex { @@ -1490,6 +1519,7 @@ class Http2Stream extends Duplex { this[kTimeout] = null; this[kState] = { + didRead: false, flags: STREAM_FLAGS_PENDING, rstCode: NGHTTP2_NO_ERROR, writeQueueSize: 0, @@ -1756,6 +1786,8 @@ class Http2Stream extends Duplex { throw headersList; this[kSentTrailers] = headers; + this[kState].flags &= ~STREAM_FLAGS_HAS_TRAILERS; + const ret = this[kHandle].trailers(headersList); if (ret < 0) this.destroy(new NghttpError(ret)); @@ -1786,38 +1818,13 @@ class Http2Stream extends Duplex { if (callback !== undefined && typeof callback !== 'function') throw new ERR_INVALID_CALLBACK(); - // Clear timeout and remove timeout listeners - this.setTimeout(0); - this.removeAllListeners('timeout'); - - // Close the writable - abort(this); - this.end(); - if (this.closed) return; - const state = this[kState]; - state.flags |= STREAM_FLAGS_CLOSED; - state.rstCode = code; - - if (callback !== undefined) { + if (callback !== undefined) this.once('close', callback); - } - - if (this[kHandle] === undefined) - return; - const rstStreamFn = submitRstStream.bind(this, code); - // If the handle has not yet been assigned, queue up the request to - // ensure that the RST_STREAM frame is sent after the stream ID has - // been determined. - if (this.pending) { - this.push(null); - this.once('ready', rstStreamFn); - return; - } - rstStreamFn(); + closeStream(this, code); } // Called by this.destroy(). @@ -1832,26 +1839,19 @@ class Http2Stream extends Duplex { debug(`Http2Stream ${this[kID] || ''} [Http2Session ` + `${sessionName(session[kType])}]: destroying stream`); const state = this[kState]; - const code = state.rstCode = - err != null ? - NGHTTP2_INTERNAL_ERROR : - state.rstCode || NGHTTP2_NO_ERROR; - if (handle !== undefined) { - // If the handle exists, we need to close, then destroy the handle - this.close(code); - if (!this._readableState.ended && !this._readableState.ending) - this.push(null); + const code = err != null ? + NGHTTP2_INTERNAL_ERROR : (state.rstCode || NGHTTP2_NO_ERROR); + + const hasHandle = handle !== undefined; + + if (!this.closed) + closeStream(this, code, hasHandle); + this.push(null); + + if (hasHandle) { handle.destroy(); session[kState].streams.delete(id); } else { - // Clear timeout and remove timeout listeners - this.setTimeout(0); - this.removeAllListeners('timeout'); - - state.flags |= STREAM_FLAGS_CLOSED; - abort(this); - this.end(); - this.push(null); session[kState].pendingStreams.delete(this); } @@ -1884,13 +1884,23 @@ class Http2Stream extends Duplex { } // TODO(mcollina): remove usage of _*State properties - if (this._readableState.ended && - this._writableState.ended && - this._writableState.pendingcb === 0 && - this.closed) { - this.destroy(); - // This should return, but eslint complains. - // return + if (this._writableState.ended && this._writableState.pendingcb === 0) { + if (this._readableState.ended && this.closed) { + this.destroy(); + return; + } + + // We've submitted a response from our server session, have not attempted + // to process any incoming data, and have no trailers. This means we can + // attempt to gracefully close the session. + const state = this[kState]; + if (this.headersSent && + this[kSession][kType] === NGHTTP2_SESSION_SERVER && + !(state.flags & STREAM_FLAGS_HAS_TRAILERS) && + !state.didRead && + !this._readableState.resumeScheduled) { + this.close(); + } } } } @@ -2095,7 +2105,6 @@ function afterOpen(session, options, headers, streamOptions, err, fd) { } if (this.destroyed || this.closed) { tryClose(fd); - abort(this); return; } state.fd = fd; @@ -2224,8 +2233,10 @@ class ServerHttp2Stream extends Http2Stream { if (options.endStream) streamOptions |= STREAM_OPTION_EMPTY_PAYLOAD; - if (options.waitForTrailers) + if (options.waitForTrailers) { streamOptions |= STREAM_OPTION_GET_TRAILERS; + state.flags |= STREAM_FLAGS_HAS_TRAILERS; + } headers = processHeaders(headers); const statusCode = headers[HTTP2_HEADER_STATUS] |= 0; @@ -2285,8 +2296,10 @@ class ServerHttp2Stream extends Http2Stream { } let streamOptions = 0; - if (options.waitForTrailers) + if (options.waitForTrailers) { streamOptions |= STREAM_OPTION_GET_TRAILERS; + this[kState].flags |= STREAM_FLAGS_HAS_TRAILERS; + } if (typeof fd !== 'number') throw new ERR_INVALID_ARG_TYPE('fd', 'number', fd); @@ -2346,8 +2359,10 @@ class ServerHttp2Stream extends Http2Stream { } let streamOptions = 0; - if (options.waitForTrailers) + if (options.waitForTrailers) { streamOptions |= STREAM_OPTION_GET_TRAILERS; + this[kState].flags |= STREAM_FLAGS_HAS_TRAILERS; + } const session = this[kSession]; debug(`Http2Stream ${this[kID]} [Http2Session ` + diff --git a/src/node_http2.cc b/src/node_http2.cc index 1c5c68f09471f3..05d9243ee30ec0 100644 --- a/src/node_http2.cc +++ b/src/node_http2.cc @@ -1364,16 +1364,35 @@ void Http2Session::MaybeScheduleWrite() { // storage for data and metadata that was associated with these writes. void Http2Session::ClearOutgoing(int status) { CHECK_NE(flags_ & SESSION_STATE_SENDING, 0); - flags_ &= ~SESSION_STATE_SENDING; - for (const nghttp2_stream_write& wr : outgoing_buffers_) { - WriteWrap* wrap = wr.req_wrap; - if (wrap != nullptr) - wrap->Done(status); + if (outgoing_buffers_.size() > 0) { + outgoing_storage_.clear(); + + for (const nghttp2_stream_write& wr : outgoing_buffers_) { + WriteWrap* wrap = wr.req_wrap; + if (wrap != nullptr) + wrap->Done(status); + } + + outgoing_buffers_.clear(); } - outgoing_buffers_.clear(); - outgoing_storage_.clear(); + flags_ &= ~SESSION_STATE_SENDING; + + // Now that we've finished sending queued data, if there are any pending + // RstStreams we should try sending again and then flush them one by one. + if (pending_rst_streams_.size() > 0) { + std::vector current_pending_rst_streams; + pending_rst_streams_.swap(current_pending_rst_streams); + + SendPendingData(); + + for (int32_t stream_id : current_pending_rst_streams) { + Http2Stream* stream = FindStream(stream_id); + if (stream != nullptr) + stream->FlushRstStream(); + } + } } // Queue a given block of data for sending. This always creates a copy, @@ -1397,18 +1416,19 @@ void Http2Session::CopyDataIntoOutgoing(const uint8_t* src, size_t src_length) { // chunk out to the i/o socket to be sent. This is a particularly hot method // that will generally be called at least twice be event loop iteration. // This is a potential performance optimization target later. -void Http2Session::SendPendingData() { +// Returns non-zero value if a write is already in progress. +uint8_t Http2Session::SendPendingData() { DEBUG_HTTP2SESSION(this, "sending pending data"); // Do not attempt to send data on the socket if the destroying flag has // been set. That means everything is shutting down and the socket // will not be usable. if (IsDestroyed()) - return; + return 0; flags_ &= ~SESSION_STATE_WRITE_SCHEDULED; // SendPendingData should not be called recursively. if (flags_ & SESSION_STATE_SENDING) - return; + return 1; // This is cleared by ClearOutgoing(). flags_ |= SESSION_STATE_SENDING; @@ -1432,15 +1452,15 @@ void Http2Session::SendPendingData() { // does take care of things like closing the individual streams after // a socket has been torn down, so we still need to call it. ClearOutgoing(UV_ECANCELED); - return; + return 0; } // Part Two: Pass Data to the underlying stream size_t count = outgoing_buffers_.size(); if (count == 0) { - flags_ &= ~SESSION_STATE_SENDING; - return; + ClearOutgoing(0); + return 0; } MaybeStackBuffer bufs; bufs.AllocateSufficientStorage(count); @@ -1471,6 +1491,8 @@ void Http2Session::SendPendingData() { DEBUG_HTTP2SESSION2(this, "wants data in return? %d", nghttp2_session_want_read(session_)); + + return 0; } @@ -1830,12 +1852,25 @@ int Http2Stream::SubmitPriority(nghttp2_priority_spec* prispec, // peer. void Http2Stream::SubmitRstStream(const uint32_t code) { CHECK(!this->IsDestroyed()); + code_ = code; + // If possible, force a purge of any currently pending data here to make sure + // it is sent before closing the stream. If it returns non-zero then we need + // to wait until the current write finishes and try again to avoid nghttp2 + // behaviour where it prioritizes RstStream over everything else. + if (session_->SendPendingData() != 0) { + session_->AddPendingRstStream(id_); + return; + } + + FlushRstStream(); +} + +void Http2Stream::FlushRstStream() { + if (IsDestroyed()) + return; Http2Scope h2scope(this); - // Force a purge of any currently pending data here to make sure - // it is sent before closing the stream. - session_->SendPendingData(); CHECK_EQ(nghttp2_submit_rst_stream(**session_, NGHTTP2_FLAG_NONE, - id_, code), 0); + id_, code_), 0); } diff --git a/src/node_http2.h b/src/node_http2.h index 87c929cdea12f9..da404841450f27 100644 --- a/src/node_http2.h +++ b/src/node_http2.h @@ -591,6 +591,8 @@ class Http2Stream : public AsyncWrap, // Submits an RST_STREAM frame using the given code void SubmitRstStream(const uint32_t code); + void FlushRstStream(); + // Submits a PUSH_PROMISE frame with this stream as the parent. Http2Stream* SubmitPushPromise( nghttp2_nv* nva, @@ -797,7 +799,7 @@ class Http2Session : public AsyncWrap, public StreamListener { bool Ping(v8::Local function); - void SendPendingData(); + uint8_t SendPendingData(); // Submits a new request. If the request is a success, assigned // will be a pointer to the Http2Stream instance assigned. @@ -845,6 +847,11 @@ class Http2Session : public AsyncWrap, public StreamListener { size_t self_size() const override { return sizeof(*this); } + // Schedule an RstStream for after the current write finishes. + inline void AddPendingRstStream(int32_t stream_id) { + pending_rst_streams_.emplace_back(stream_id); + } + // Handle reads/writes from the underlying network transport. void OnStreamRead(ssize_t nread, const uv_buf_t& buf) override; void OnStreamAfterWrite(WriteWrap* w, int status) override; @@ -1049,6 +1056,7 @@ class Http2Session : public AsyncWrap, public StreamListener { std::vector outgoing_buffers_; std::vector outgoing_storage_; + std::vector pending_rst_streams_; void CopyDataIntoOutgoing(const uint8_t* src, size_t src_length); void ClearOutgoing(int status); diff --git a/test/fixtures/person-large.jpg b/test/fixtures/person-large.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3d0d0af42375c3e696731294deea165f132a5797 GIT binary patch literal 139837 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

00jHv6S|N{HyjWGAVepgZhO<Q%=L+F4!0 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%0D{5QF)fKDd}br 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 E15V*r*Z=?k literal 0 HcmV?d00001 diff --git a/test/parallel/test-http2-client-destroy.js b/test/parallel/test-http2-client-destroy.js index 09ca011c736c96..e641335e751287 100644 --- a/test/parallel/test-http2-client-destroy.js +++ b/test/parallel/test-http2-client-destroy.js @@ -124,3 +124,21 @@ const Countdown = require('../common/countdown'); req.on('error', () => {}); })); } + +// test destroy before connect +{ + const server = h2.createServer(); + server.on('stream', common.mustNotCall()); + + server.listen(0, common.mustCall(() => { + const client = h2.connect(`http://localhost:${server.address().port}`); + + server.on('connection', common.mustCall(() => { + server.close(); + client.close(); + })); + + const req = client.request(); + req.destroy(); + })); +} diff --git a/test/parallel/test-http2-client-rststream-before-connect.js b/test/parallel/test-http2-client-rststream-before-connect.js index 7bace941d1a0af..33e22130aad19b 100644 --- a/test/parallel/test-http2-client-rststream-before-connect.js +++ b/test/parallel/test-http2-client-rststream-before-connect.js @@ -63,8 +63,14 @@ server.listen(0, common.mustCall(() => { message: 'Stream closed with error code NGHTTP2_PROTOCOL_ERROR' })); - req.on('response', common.mustCall()); - req.resume(); + // The `response` event should not fire as the server should receive the + // RST_STREAM frame before it ever has a chance to reply. + req.on('response', common.mustNotCall()); + + // The `end` event should still fire as we close the readable stream by + // pushing a `null` chunk. req.on('end', common.mustCall()); + + req.resume(); req.end(); })); diff --git a/test/parallel/test-http2-client-upload-reject.js b/test/parallel/test-http2-client-upload-reject.js new file mode 100644 index 00000000000000..ece7cbdf233f1f --- /dev/null +++ b/test/parallel/test-http2-client-upload-reject.js @@ -0,0 +1,48 @@ +'use strict'; + +// Verifies that uploading data from a client works + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); +const assert = require('assert'); +const http2 = require('http2'); +const fs = require('fs'); +const fixtures = require('../common/fixtures'); + +const loc = fixtures.path('person-large.jpg'); + +assert(fs.existsSync(loc)); + +fs.readFile(loc, common.mustCall((err, data) => { + assert.ifError(err); + + const server = http2.createServer(); + + server.on('stream', common.mustCall((stream) => { + stream.on('close', common.mustCall(() => { + assert.strictEqual(stream.rstCode, 0); + })); + + stream.respond({ ':status': 400 }); + stream.end(); + })); + + server.listen(0, common.mustCall(() => { + const client = http2.connect(`http://localhost:${server.address().port}`); + + const req = client.request({ ':method': 'POST' }); + req.on('response', common.mustCall((headers) => { + assert.strictEqual(headers[':status'], 400); + })); + + req.resume(); + req.on('end', common.mustCall(() => { + server.close(); + client.close(); + })); + + const str = fs.createReadStream(loc); + str.pipe(req); + })); +})); diff --git a/test/parallel/test-http2-client-upload.js b/test/parallel/test-http2-client-upload.js index 70a8ff3ced01c6..78c6d47cbb4f44 100644 --- a/test/parallel/test-http2-client-upload.js +++ b/test/parallel/test-http2-client-upload.js @@ -11,7 +11,7 @@ const fs = require('fs'); const fixtures = require('../common/fixtures'); const Countdown = require('../common/countdown'); -const loc = fixtures.path('person.jpg'); +const loc = fixtures.path('person-large.jpg'); let fileData; assert(fs.existsSync(loc)); diff --git a/test/parallel/test-http2-large-write-close.js b/test/parallel/test-http2-large-write-close.js new file mode 100644 index 00000000000000..f9dee357d6da7b --- /dev/null +++ b/test/parallel/test-http2-large-write-close.js @@ -0,0 +1,44 @@ +'use strict'; +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); +const assert = require('assert'); +const fixtures = require('../common/fixtures'); +const http2 = require('http2'); + +const content = Buffer.alloc(1e5, 0x44); + +const server = http2.createSecureServer({ + key: fixtures.readKey('agent1-key.pem'), + cert: fixtures.readKey('agent1-cert.pem') +}); +server.on('stream', common.mustCall((stream) => { + stream.respond({ + 'Content-Type': 'application/octet-stream', + 'Content-Length': (content.length.toString() * 2), + 'Vary': 'Accept-Encoding' + }); + + stream.write(content); + stream.write(content); + stream.end(); + stream.close(); +})); + +server.listen(0, common.mustCall(() => { + const client = http2.connect(`https://localhost:${server.address().port}`, + { rejectUnauthorized: false }); + + const req = client.request({ ':path': '/' }); + req.end(); + + let receivedBufferLength = 0; + req.on('data', common.mustCallAtLeast((buf) => { + receivedBufferLength += buf.length; + }, 1)); + req.on('close', common.mustCall(() => { + assert.strictEqual(receivedBufferLength, content.length * 2); + client.close(); + server.close(); + })); +})); diff --git a/test/parallel/test-http2-perf_hooks.js b/test/parallel/test-http2-perf_hooks.js index 07d9c55ed7e0d2..5dd8ad0f6d883b 100644 --- a/test/parallel/test-http2-perf_hooks.js +++ b/test/parallel/test-http2-perf_hooks.js @@ -26,7 +26,7 @@ const obs = new PerformanceObserver(common.mustCall((items) => { switch (entry.type) { case 'server': assert.strictEqual(entry.streamCount, 1); - assert.strictEqual(entry.framesReceived, 5); + assert(entry.framesReceived >= 3); break; case 'client': assert.strictEqual(entry.streamCount, 1); From 9cf3ae5bc3770d85b1a89e4f6bcae0c3c5e814b9 Mon Sep 17 00:00:00 2001 From: Vse Mozhet Byt Date: Sun, 29 Apr 2018 01:26:30 +0300 Subject: [PATCH 059/173] doc: add missing backticks in n-api.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Codify types, variable names, and code fragments checking patterns I've managed to think of. Some nits were also fixed in passing (add missing periods, remove extra line breaks etc). PR-URL: https://github.com/nodejs/node/pull/20390 Reviewed-By: Tobias Nießen Reviewed-By: Trivikram Kamat Reviewed-By: Gabriel Schulhof Reviewed-By: Ruben Bridgewater --- doc/api/n-api.md | 415 +++++++++++++++++++++++------------------------ 1 file changed, 204 insertions(+), 211 deletions(-) diff --git a/doc/api/n-api.md b/doc/api/n-api.md index 26b5e87463948e..adb8647b399ecd 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -185,7 +185,6 @@ typedef void (*napi_finalize)(napi_env env, void* finalize_hint); ``` - #### napi_async_execute_callback Function pointer used with functions that support asynchronous operations. Callback functions must statisfy the following signature: @@ -223,7 +222,7 @@ In cases where a return value other than `napi_ok` or must be called to check if an exception is pending. See the section on exceptions for more details. -The full set of possible napi_status values is defined +The full set of possible `napi_status` values is defined in `napi_api_types.h`. The `napi_status` return value provides a VM-independent representation of @@ -282,7 +281,6 @@ logging purposes. This API can be called even if there is a pending JavaScript exception. - ### Exceptions Any N-API function call may result in a pending JavaScript exception. This is obviously the case for any function that may cause the execution of @@ -312,10 +310,10 @@ and then continue. This is only recommended in specific cases where it is known that the exception can be safely handled. In these cases [`napi_get_and_clear_last_exception`][] can be used to get and clear the exception. On success, result will contain the handle to -the last JavaScript Object thrown. If it is determined, after +the last JavaScript `Object` thrown. If it is determined, after retrieving the exception, the exception cannot be handled after all it can be re-thrown it with [`napi_throw`][] where error is the -JavaScript Error object to be thrown. +JavaScript `Error` object to be thrown. The following utility functions are also available in case native code needs to throw an exception or determine if a `napi_value` is an instance @@ -324,10 +322,10 @@ of a JavaScript `Error` object: [`napi_throw_error`][], [`napi_is_error`][]. The following utility functions are also available in case native -code needs to create an Error object: [`napi_create_error`][], -[`napi_create_type_error`][], and [`napi_create_range_error`][]. -where result is the napi_value that refers to the newly created -JavaScript Error object. +code needs to create an `Error` object: [`napi_create_error`][], +[`napi_create_type_error`][], and [`napi_create_range_error`][], +where result is the `napi_value` that refers to the newly created +JavaScript `Error` object. The Node.js project is adding error codes to all of the errors generated internally. The goal is for applications to use these @@ -346,9 +344,9 @@ the name associated with the error is also updated to be: originalName [code] ``` -where originalName is the original name associated with the error -and code is the code that was provided. For example if the code -is 'ERR_ERROR_1' and a TypeError is being created the name will be: +where `originalName` is the original name associated with the error +and `code` is the code that was provided. For example if the code +is `'ERR_ERROR_1'` and a `TypeError` is being created the name will be: ```text TypeError [ERR_ERROR_1] @@ -362,12 +360,11 @@ added: v8.0.0 NODE_EXTERN napi_status napi_throw(napi_env env, napi_value error); ``` - `[in] env`: The environment that the API is invoked under. -- `[in] error`: The `napi_value` for the Error to be thrown. +- `[in] error`: The `napi_value` for the `Error` to be thrown. Returns `napi_ok` if the API succeeded. -This API throws the JavaScript Error provided. - +This API throws the JavaScript `Error` provided. #### napi_throw_error - The `Console` class can be used to create a simple logger with configurable diff --git a/doc/api/crypto.md b/doc/api/crypto.md index 562cb20a07cc6b..0f9d3c80b5347a 100644 --- a/doc/api/crypto.md +++ b/doc/api/crypto.md @@ -2602,7 +2602,6 @@ the `crypto`, `tls`, and `https` modules and are generally specific to OpenSSL. - [`Buffer`]: buffer.html [`EVP_BytesToKey`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_BytesToKey.html [`UV_THREADPOOL_SIZE`]: cli.html#cli_uv_threadpool_size_size diff --git a/doc/api/dgram.md b/doc/api/dgram.md index 06c15ffa25c879..b6b974541bdfe7 100644 --- a/doc/api/dgram.md +++ b/doc/api/dgram.md @@ -464,7 +464,6 @@ A socket's address family's ANY address (IPv4 `'0.0.0.0'` or IPv6 `'::'`) can be used to return control of the sockets default outgoing interface to the system for future multicast packets. - ### socket.setMulticastLoopback(flag) * `str` {string} - The `querystring.unescape()` method performs decoding of URL percent-encoded characters on the given `str`. diff --git a/doc/api/readline.md b/doc/api/readline.md index c1e50ef7eee350..d3afe5d9bf5ba2 100644 --- a/doc/api/readline.md +++ b/doc/api/readline.md @@ -320,7 +320,6 @@ added: v0.7.7 The `readline.clearLine()` method clears current line of given [TTY][] stream in a specified direction identified by `dir`. - ## readline.clearScreenDown(stream) ```js @@ -1121,10 +1163,15 @@ function throwingSecond() { 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! +// The first case will not throw as it does not match for the error message +// thrown by the input function! assert.throws(throwingFirst, 'Second'); +// In the next example the message has no benefit over the message from the +// error and since it is not clear if the user intended to actually match +// against the error message, Node.js thrown an `ERR_AMBIGUOUS_ARGUMENT` error. assert.throws(throwingSecond, 'Second'); +// Throws an error: +// TypeError [ERR_AMBIGUOUS_ARGUMENT] // The string is only used (as message) in case the function does not throw: assert.throws(notThrowing, 'Second'); @@ -1134,7 +1181,7 @@ assert.throws(notThrowing, 'Second'); assert.throws(throwingSecond, /Second$/); // Does not throw because the error messages match. assert.throws(throwingFirst, /Second$/); -// Throws a error: +// Throws an error: // Error: First // at throwingFirst (repl:2:9) ``` From 5542a98aa44df622d176b1a942553e1299ca43d9 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Thu, 26 Apr 2018 02:15:59 +0200 Subject: [PATCH 065/173] doc: improve process event headers The headers should be handled as all others as well and just indicate all arguments. PR-URL: https://github.com/nodejs/node/pull/20312 Reviewed-By: Vse Mozhet Byt Reviewed-By: James M Snell Reviewed-By: Trivikram Kamat --- doc/api/net.md | 2 +- doc/api/process.md | 40 +++++++++++++++++++--------------------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/doc/api/net.md b/doc/api/net.md index 54f3c2f737a73d..6b8afce4a59121 100644 --- a/doc/api/net.md +++ b/doc/api/net.md @@ -388,7 +388,7 @@ added: v0.3.4 Creates a new socket object. * `options` {Object} Available options are: - * `fd`: {number} If specified, wrap around an existing socket with + * `fd` {number} If specified, wrap around an existing socket with the given file descriptor, otherwise a new socket will be created. * `allowHalfOpen` {boolean} Indicates whether half-opened TCP connections are allowed. See [`net.createServer()`][] and the [`'end'`][] event diff --git a/doc/api/process.md b/doc/api/process.md index ad1c997ae169f6..c973d15e12cef7 100644 --- a/doc/api/process.md +++ b/doc/api/process.md @@ -45,6 +45,8 @@ the IPC channel is closed. added: v0.1.7 --> +* `code` {integer} + The `'exit'` event is emitted when the Node.js process is about to exit as a result of either: @@ -56,7 +58,7 @@ all `'exit'` listeners have finished running the Node.js process will terminate. The listener callback function is invoked with the exit code specified either by the [`process.exitCode`][] property, or the `exitCode` argument passed to the -[`process.exit()`] method, as the only argument. +[`process.exit()`] method. ```js process.on('exit', (code) => { @@ -82,16 +84,15 @@ process.on('exit', (code) => { added: v0.5.10 --> +* `message` {Object} a parsed JSON object or primitive value. +* `sendHandle` {net.Server|net.Socket} a [`net.Server`][] or [`net.Socket`][] + object, or undefined. + If the Node.js process is spawned with an IPC channel (see the [Child Process][] and [Cluster][] documentation), the `'message'` event is emitted whenever a message sent by a parent process using [`childprocess.send()`][] is received by the child process. -The listener callback is invoked with the following arguments: -* `message` {Object} a parsed JSON object or primitive value. -* `sendHandle` {net.Server|net.Socket} a [`net.Server`][] or [`net.Socket`][] - object, or undefined. - The message goes through serialization and parsing. The resulting message might not be the same as what is originally sent. @@ -100,13 +101,12 @@ not be the same as what is originally sent. added: v1.4.1 --> +* `promise` {Promise} The late handled promise. + The `'rejectionHandled'` event is emitted whenever a `Promise` has been rejected and an error handler was attached to it (using [`promise.catch()`][], for example) later than one turn of the Node.js event loop. -The listener callback is invoked with a reference to the rejected `Promise` as -the only argument. - The `Promise` object would have previously been emitted in an `'unhandledRejection'` event, but during the course of processing gained a rejection handler. @@ -129,11 +129,11 @@ when the list of unhandled rejections shrinks. ```js const unhandledRejections = new Map(); -process.on('unhandledRejection', (reason, p) => { - unhandledRejections.set(p, reason); +process.on('unhandledRejection', (reason, promise) => { + unhandledRejections.set(promise, reason); }); -process.on('rejectionHandled', (p) => { - unhandledRejections.delete(p); +process.on('rejectionHandled', (promise) => { + unhandledRejections.delete(promise); }); ``` @@ -261,6 +261,12 @@ being emitted. Alternatively, the [`'rejectionHandled'`][] event may be used. added: v6.0.0 --> +* `warning` {Error} Key properties of the warning are: + * `name` {string} The name of the warning. **Default:** `'Warning'`. + * `message` {string} A system-provided description of the warning. + * `stack` {string} A stack trace to the location in the code where the warning + was issued. + The `'warning'` event is emitted whenever Node.js emits a process warning. A process warning is similar to an error in that it describes exceptional @@ -269,14 +275,6 @@ are not part of the normal Node.js and JavaScript error handling flow. Node.js can emit warnings whenever it detects bad coding practices that could lead to sub-optimal application performance, bugs, or security vulnerabilities. -The listener function is called with a single `warning` argument whose value is -an `Error` object. There are three key properties that describe the warning: - -* `name` {string} The name of the warning (currently `'Warning'` by default). -* `message` {string} A system-provided description of the warning. -* `stack` {string} A stack trace to the location in the code where the warning - was issued. - ```js process.on('warning', (warning) => { console.warn(warning.name); // Print the warning name From 7d9f1f3971bda6671cbf4a2255e5ceb5a4476cbf Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Thu, 26 Apr 2018 02:13:39 +0200 Subject: [PATCH 066/173] http2: fix ping callback In case there was no ack, the callback would have returned more than the error as return value. This makes sure that is not the case anymore. PR-URL: https://github.com/nodejs/node/pull/20311 Reviewed-By: James M Snell Reviewed-By: Matteo Collina Reviewed-By: Trivikram Kamat --- lib/internal/http2/core.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/internal/http2/core.js b/lib/internal/http2/core.js index be5d08a0b0a1f5..a9fdcb659544e5 100644 --- a/lib/internal/http2/core.js +++ b/lib/internal/http2/core.js @@ -704,8 +704,11 @@ const proxySocketHandler = { // data received on the PING acknowlegement. function pingCallback(cb) { return function pingCallback(ack, duration, payload) { - const err = ack ? null : new ERR_HTTP2_PING_CANCEL(); - cb(err, duration, payload); + if (ack) { + cb(null, duration, payload); + } else { + cb(new ERR_HTTP2_PING_CANCEL()); + } }; } From 645a97a44e4a7341fa73430c3112733402e02424 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Thu, 26 Apr 2018 02:14:25 +0200 Subject: [PATCH 067/173] test: verify arguments length in common.expectsError If `common.expectsError` is used as a callback, it will now also verify that there is only one argument (the expected error). PR-URL: https://github.com/nodejs/node/pull/20311 Reviewed-By: James M Snell Reviewed-By: Matteo Collina Reviewed-By: Trivikram Kamat --- test/common/index.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/common/index.js b/test/common/index.js index 95bb8dd804881f..bbd2b62d7da768 100644 --- a/test/common/index.js +++ b/test/common/index.js @@ -708,6 +708,11 @@ exports.expectsError = function expectsError(fn, settings, exact) { } function innerFn(error) { + if (arguments.length !== 1) { + // Do not use `assert.strictEqual()` to prevent `util.inspect` from + // always being called. + assert.fail(`Expected one argument, got ${util.inspect(arguments)}`); + } const descriptor = Object.getOwnPropertyDescriptor(error, 'message'); assert.strictEqual(descriptor.enumerable, false, 'The error message should be non-enumerable'); From 2b8b40f8007c4fa0bf8a45291ef2965e3e54ecb5 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Thu, 26 Apr 2018 05:44:14 +0200 Subject: [PATCH 068/173] test: fix a TODO and remove obsolete TODOs This removes outdated TODOs and adds a test for invalid input in `fs.copyFile` and solves a TODO by doing so. PR-URL: https://github.com/nodejs/node/pull/20319 Reviewed-By: Daniel Bevenius Reviewed-By: Colin Ihrig Reviewed-By: Trivikram Kamat Reviewed-By: James M Snell --- lib/url.js | 3 --- test/parallel/test-cluster-http-pipe.js | 1 - test/parallel/test-fs-error-messages.js | 23 ++++++++++---------- test/parallel/test-util-isDeepStrictEqual.js | 2 -- 4 files changed, 11 insertions(+), 18 deletions(-) diff --git a/lib/url.js b/lib/url.js index ac9879a650fce6..e4326e80b5d948 100644 --- a/lib/url.js +++ b/lib/url.js @@ -281,9 +281,6 @@ Url.prototype.parse = function parse(url, parseQueryString, slashesDenoteHost) { // http://a@b@c/ => user:a@b host:c // http://a@b?@c => user:a host:b path:/?@c - // v0.12 TODO(isaacs): This is not quite how Chrome does things. - // Review our test case against browsers more comprehensively. - var hostEnd = -1; var atSign = -1; var nonHost = -1; diff --git a/test/parallel/test-cluster-http-pipe.js b/test/parallel/test-cluster-http-pipe.js index 9e58fb297b28fe..9e039541cd26f1 100644 --- a/test/parallel/test-cluster-http-pipe.js +++ b/test/parallel/test-cluster-http-pipe.js @@ -45,7 +45,6 @@ if (cluster.isMaster) { http.createServer(common.mustCall((req, res) => { assert.strictEqual(req.connection.remoteAddress, undefined); assert.strictEqual(req.connection.localAddress, undefined); - // TODO common.PIPE? res.writeHead(200); res.end('OK'); diff --git a/test/parallel/test-fs-error-messages.js b/test/parallel/test-fs-error-messages.js index 61e51585a028c2..28141f33f62965 100644 --- a/test/parallel/test-fs-error-messages.js +++ b/test/parallel/test-fs-error-messages.js @@ -636,22 +636,21 @@ if (!common.isAIX) { ); } -// copyFile with invalid flags +// Check copyFile with invalid flags. { - const validateError = (err) => { - assert.strictEqual(err.message, - 'EINVAL: invalid argument, copyfile ' + - `'${existingFile}' -> '${nonexistentFile}'`); - assert.strictEqual(err.errno, uv.UV_EINVAL); - assert.strictEqual(err.code, 'EINVAL'); - assert.strictEqual(err.syscall, 'copyfile'); - return true; + const validateError = { + // TODO: Make sure the error message always also contains the src. + message: `EINVAL: invalid argument, copyfile -> '${nonexistentFile}'`, + errno: uv.UV_EINVAL, + code: 'EINVAL', + syscall: 'copyfile' }; - // TODO(joyeecheung): test fs.copyFile() when uv_fs_copyfile does not - // keep the loop open when the flags are invalid. - // See https://github.com/libuv/libuv/pull/1747 + fs.copyFile(existingFile, nonexistentFile, -1, + common.expectsError(validateError)); + validateError.message = 'EINVAL: invalid argument, copyfile ' + + `'${existingFile}' -> '${nonexistentFile}'`; assert.throws( () => fs.copyFileSync(existingFile, nonexistentFile, -1), validateError diff --git a/test/parallel/test-util-isDeepStrictEqual.js b/test/parallel/test-util-isDeepStrictEqual.js index 356a9a71324971..938781a43084a5 100644 --- a/test/parallel/test-util-isDeepStrictEqual.js +++ b/test/parallel/test-util-isDeepStrictEqual.js @@ -419,8 +419,6 @@ notUtilIsDeepStrict([1, , , 3], [1, , , 3, , , ]); const err3 = new TypeError('foo1'); notUtilIsDeepStrict(err1, err2, assert.AssertionError); notUtilIsDeepStrict(err1, err3, assert.AssertionError); - // TODO: evaluate if this should throw or not. The same applies for RegExp - // Date and any object that has the same keys but not the same prototype. notUtilIsDeepStrict(err1, {}, assert.AssertionError); } From 348d391a7106d6dbc5ecad4246a9c353b221fece Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 26 Apr 2018 09:03:26 +0200 Subject: [PATCH 069/173] build: remove --xcode configure switch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `./configure --xcode` ostensibly let you built with the Xcode IDE but it has never been tested regularly since its introduction in 2012 and probably has been broken for years. Remove it. PR-URL: https://github.com/nodejs/node/pull/20328 Fixes: https://github.com/nodejs/node/issues/20324 Reviewed-By: Benjamin Gruenbaum Reviewed-By: Gibson Fahnestock Reviewed-By: Michaël Zasso Reviewed-By: Beth Griggs Reviewed-By: Daniel Bevenius Reviewed-By: Joyee Cheung Reviewed-By: Colin Ihrig Reviewed-By: James M Snell Reviewed-By: Gus Caplan --- configure | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/configure b/configure index c1170f9a132a16..17e13a48d47e5a 100755 --- a/configure +++ b/configure @@ -501,11 +501,6 @@ parser.add_option('--without-node-options', dest='without_node_options', help='build without NODE_OPTIONS support') -parser.add_option('--xcode', - action='store_true', - dest='use_xcode', - help='generate build files for use with xcode') - parser.add_option('--ninja', action='store_true', dest='use_ninja', @@ -1005,9 +1000,6 @@ def configure_node(o): o['variables']['asan'] = int(options.enable_asan or 0) - if options.use_xcode and options.use_ninja: - raise Exception('--xcode and --ninja cannot be used together.') - if options.coverage: o['variables']['coverage'] = 'true' else: @@ -1530,7 +1522,6 @@ write('config.gypi', do_not_edit + config = { 'BUILDTYPE': 'Debug' if options.debug else 'Release', - 'USE_XCODE': str(int(options.use_xcode or 0)), 'PYTHON': sys.executable, 'NODE_TARGET_TYPE': variables['node_target_type'], } @@ -1549,9 +1540,7 @@ write('config.mk', do_not_edit + config) gyp_args = ['--no-parallel'] -if options.use_xcode: - gyp_args += ['-f', 'xcode'] -elif options.use_ninja: +if options.use_ninja: gyp_args += ['-f', 'ninja'] elif flavor == 'win' and sys.platform != 'msys': gyp_args += ['-f', 'msvs', '-G', 'msvs_version=auto'] From 05b7b8d50659491bd9f151828dfdb4e66f7f4fb9 Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Thu, 26 Apr 2018 11:53:23 +0200 Subject: [PATCH 070/173] stream: fix error handling with async iteration Fix an issue when an error was emitted by the stream before `iterator.next()` is called. PR-URL: https://github.com/nodejs/node/pull/20329 Reviewed-By: Benjamin Gruenbaum Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: James M Snell Reviewed-By: Colin Ihrig Reviewed-By: Anatoli Papirovski --- lib/internal/streams/async_iterator.js | 2 +- .../parallel/test-stream-readable-async-iterators.js | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/internal/streams/async_iterator.js b/lib/internal/streams/async_iterator.js index 9ca8e5ebe23b15..0e34573d877aee 100644 --- a/lib/internal/streams/async_iterator.js +++ b/lib/internal/streams/async_iterator.js @@ -58,7 +58,7 @@ function onError(iter, err) { iter[kLastReject] = null; reject(err); } - iter.error = err; + iter[kError] = err; } function wrapForNext(lastPromise, iter) { diff --git a/test/parallel/test-stream-readable-async-iterators.js b/test/parallel/test-stream-readable-async-iterators.js index b1801a1db3e580..39761b413260f1 100644 --- a/test/parallel/test-stream-readable-async-iterators.js +++ b/test/parallel/test-stream-readable-async-iterators.js @@ -115,6 +115,18 @@ async function tests() { readable.destroy(new Error('kaboom')); })(); + await (async function() { + console.log('call next() after error'); + const readable = new Readable({ + read() {} + }); + const iterator = readable[Symbol.asyncIterator](); + + const err = new Error('kaboom'); + readable.destroy(new Error('kaboom')); + await assert.rejects(iterator.next.bind(iterator), err); + })(); + await (async function() { console.log('read object mode'); const max = 42; From de9d1f15deb4306dbd9402b02eb39497a578296d Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sat, 28 Apr 2018 22:38:43 -0700 Subject: [PATCH 071/173] doc: remove parenthetical in onboarding-extras MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove "(I prefer the former)" from onboarding-extras. Without any explanation as to why one might prefer A over B, it probably raises more questions than it answers. PR-URL: https://github.com/nodejs/node/pull/20393 Reviewed-By: Vse Mozhet Byt Reviewed-By: Tobias Nießen Reviewed-By: Richard Lau Reviewed-By: Ruben Bridgewater Reviewed-By: Trivikram Kamat --- doc/onboarding-extras.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/onboarding-extras.md b/doc/onboarding-extras.md index 080918049f66c0..ffc316d7a670b6 100644 --- a/doc/onboarding-extras.md +++ b/doc/onboarding-extras.md @@ -91,7 +91,7 @@ need to be attached anymore, as only important bugfixes will be included. to update from nodejs/node: * `git checkout master` -* `git remote update -p` OR `git fetch --all` (I prefer the former) +* `git remote update -p` OR `git fetch --all` * `git merge --ff-only upstream/master` (or `REMOTENAME/BRANCH`) ## Best practices From 58be6efd299dc95dc9841c98b605de50be459960 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Sat, 28 Apr 2018 20:50:19 +0200 Subject: [PATCH 072/173] src: avoid `std::make_unique` Work around https://github.com/nodejs/build/issues/1254, which effectively breaks stress test CI and CITGM, by avoiding `std::make_unique` for now. This workaround should be reverted once that issue is resolved. Refs: https://github.com/nodejs/build/issues/1254 PR-URL: https://github.com/nodejs/node/pull/20386 Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: Matheus Marchini --- src/inspector_agent.cc | 8 +++++--- src/inspector_io.cc | 4 ++-- src/inspector_js_api.cc | 4 ++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/inspector_agent.cc b/src/inspector_agent.cc index 1530b206456bb5..4e0c04a7b95527 100644 --- a/src/inspector_agent.cc +++ b/src/inspector_agent.cc @@ -367,8 +367,9 @@ class NodeInspectorClient : public V8InspectorClient { int connectFrontend(std::unique_ptr delegate) { events_dispatched_ = true; int session_id = next_session_id_++; - channels_[session_id] = - std::make_unique(client_, std::move(delegate)); + // TODO(addaleax): Revert back to using make_unique once we get issues + // with CI resolved (i.e. revert the patch that added this comment). + channels_[session_id].reset(new ChannelImpl(client_, std::move(delegate))); return session_id; } @@ -569,7 +570,8 @@ void Agent::Stop() { std::unique_ptr Agent::Connect( std::unique_ptr delegate) { int session_id = client_->connectFrontend(std::move(delegate)); - return std::make_unique(session_id, client_); + return std::unique_ptr( + new InspectorSession(session_id, client_)); } void Agent::WaitForDisconnect() { diff --git a/src/inspector_io.cc b/src/inspector_io.cc index 5e0d29d3caf2cd..38d88d7ab890c9 100644 --- a/src/inspector_io.cc +++ b/src/inspector_io.cc @@ -357,8 +357,8 @@ std::vector InspectorIo::GetTargetIds() const { TransportAction InspectorIo::Attach(int session_id) { Agent* agent = parent_env_->inspector_agent(); fprintf(stderr, "Debugger attached.\n"); - sessions_[session_id] = - agent->Connect(std::make_unique(this, session_id)); + sessions_[session_id] = agent->Connect(std::unique_ptr( + new IoSessionDelegate(this, session_id))); return TransportAction::kAcceptSession; } diff --git a/src/inspector_js_api.cc b/src/inspector_js_api.cc index 3d05b2f6feafff..37cdcecd61dabb 100644 --- a/src/inspector_js_api.cc +++ b/src/inspector_js_api.cc @@ -66,8 +66,8 @@ class JSBindingsConnection : public AsyncWrap { callback_(env->isolate(), callback) { Wrap(wrap, this); Agent* inspector = env->inspector_agent(); - session_ = inspector->Connect( - std::make_unique(env, this)); + session_ = inspector->Connect(std::unique_ptr( + new JSBindingsSessionDelegate(env, this))); } void OnMessage(Local value) { From b89d8178b4783271e0db0ef73c795fa0f5eac26a Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Thu, 26 Apr 2018 19:12:47 +0200 Subject: [PATCH 073/173] errors: minor (SystemError) refactoring This removes the former default values and the spread arguments usage. That was unnecessary and now it does only what is necessary. The `message` function got renamed to `getMessage` to outline that it is actually a function and a helper function was inlined into the SystemError constructor as it was only used there. PR-URL: https://github.com/nodejs/node/pull/20337 Reviewed-By: Anna Henningsen Reviewed-By: James M Snell --- lib/internal/errors.js | 34 +++++++-------- test/parallel/test-buffer-fill.js | 8 ++-- test/parallel/test-errors-systemerror.js | 8 ++-- test/parallel/test-internal-errors.js | 53 +++++++++++------------- 4 files changed, 46 insertions(+), 57 deletions(-) diff --git a/lib/internal/errors.js b/lib/internal/errors.js index eb64b46337321c..cc4c955cba1588 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -79,16 +79,6 @@ function inspectValue(val) { ).split('\n'); } -function sysErrorMessage(prefix, ctx) { - let message = `${prefix}: ${ctx.syscall} returned ` + - `${ctx.code} (${ctx.message})`; - if (ctx.path !== undefined) - message += ` ${ctx.path}`; - if (ctx.dest !== undefined) - message += ` => ${ctx.dest}`; - return message; -} - // A specialized Error that includes an additional info property with // additional information about the error condition. // It has the properties present in a UVException but with a custom error @@ -98,9 +88,17 @@ function sysErrorMessage(prefix, ctx) { // The context passed into this error must have .code, .syscall and .message, // and may have .path and .dest. class SystemError extends Error { - constructor(key, context = {}) { - context = context || {}; - super(sysErrorMessage(message(key), context)); + constructor(key, context) { + const prefix = getMessage(key, []); + let message = `${prefix}: ${context.syscall} returned ` + + `${context.code} (${context.message})`; + + if (context.path !== undefined) + message += ` ${context.path}`; + if (context.dest !== undefined) + message += ` => ${context.dest}`; + + super(message); Object.defineProperty(this, kInfo, { configurable: false, enumerable: false, @@ -183,8 +181,8 @@ class SystemError extends Error { function makeSystemErrorWithCode(key) { return class NodeError extends SystemError { - constructor(...args) { - super(key, ...args); + constructor(ctx) { + super(key, ctx); } }; } @@ -192,7 +190,7 @@ function makeSystemErrorWithCode(key) { function makeNodeErrorWithCode(Base, key) { return class NodeError extends Base { constructor(...args) { - super(message(key, args)); + super(getMessage(key, args)); } get name() { @@ -485,7 +483,7 @@ function internalAssert(condition, message) { } } -function message(key, args = []) { +function getMessage(key, args) { const msg = messages.get(key); if (util === undefined) util = require('util'); @@ -694,7 +692,7 @@ module.exports = { exceptionWithHostPort, uvException, isStackOverflowError, - message, + getMessage, AssertionError, SystemError, codes, diff --git a/test/parallel/test-buffer-fill.js b/test/parallel/test-buffer-fill.js index b2f14c3e428e55..4eef0edefcbb22 100644 --- a/test/parallel/test-buffer-fill.js +++ b/test/parallel/test-buffer-fill.js @@ -2,7 +2,7 @@ 'use strict'; const common = require('../common'); const assert = require('assert'); -const errors = require('internal/errors'); +const { codes: { ERR_INDEX_OUT_OF_RANGE } } = require('internal/errors'); const SIZE = 28; const buf1 = Buffer.allocUnsafe(SIZE); @@ -214,13 +214,11 @@ function genBuffer(size, args) { return b.fill(0).fill.apply(b, args); } - function bufReset() { buf1.fill(0); buf2.fill(0); } - // This is mostly accurate. Except write() won't write partial bytes to the // string while fill() blindly copies bytes into memory. To account for that an // error will be thrown if not all the data can be written, and the SIZE has @@ -237,8 +235,9 @@ function writeToFill(string, offset, end, encoding) { end = buf2.length; } + // Should never be reached. if (offset < 0 || end > buf2.length) - throw new errors.RangeError('ERR_INDEX_OUT_OF_RANGE'); + throw new ERR_INDEX_OUT_OF_RANGE(); if (end <= offset) return buf2; @@ -266,7 +265,6 @@ function writeToFill(string, offset, end, encoding) { return buf2; } - function testBufs(string, offset, length, encoding) { bufReset(); buf1.fill.apply(buf1, arguments); diff --git a/test/parallel/test-errors-systemerror.js b/test/parallel/test-errors-systemerror.js index a74d7b3846f59d..957a0dd7b22196 100644 --- a/test/parallel/test-errors-systemerror.js +++ b/test/parallel/test-errors-systemerror.js @@ -3,12 +3,10 @@ require('../common'); const assert = require('assert'); -const errors = require('internal/errors'); - -const { E, SystemError } = errors; +const { E, SystemError, codes } = require('internal/errors'); assert.throws( - () => { throw new errors.SystemError(); }, + () => { throw new SystemError(); }, { name: 'TypeError', message: 'Cannot read property \'match\' of undefined' @@ -16,7 +14,7 @@ assert.throws( ); E('ERR_TEST', 'custom message', SystemError); -const { ERR_TEST } = errors.codes; +const { ERR_TEST } = codes; { const ctx = { diff --git a/test/parallel/test-internal-errors.js b/test/parallel/test-internal-errors.js index cd2028c0f29b95..8fda4b25f2f5e2 100644 --- a/test/parallel/test-internal-errors.js +++ b/test/parallel/test-internal-errors.js @@ -93,20 +93,22 @@ common.expectsError(() => { }); // Test ERR_INVALID_FD_TYPE -assert.strictEqual(errors.message('ERR_INVALID_FD_TYPE', ['a']), +assert.strictEqual(errors.getMessage('ERR_INVALID_FD_TYPE', ['a']), 'Unsupported fd type: a'); // Test ERR_INVALID_URL_SCHEME -assert.strictEqual(errors.message('ERR_INVALID_URL_SCHEME', ['file']), +assert.strictEqual(errors.getMessage('ERR_INVALID_URL_SCHEME', ['file']), 'The URL must be of scheme file'); -assert.strictEqual(errors.message('ERR_INVALID_URL_SCHEME', [['file']]), +assert.strictEqual(errors.getMessage('ERR_INVALID_URL_SCHEME', [['file']]), 'The URL must be of scheme file'); -assert.strictEqual(errors.message('ERR_INVALID_URL_SCHEME', [['http', 'ftp']]), +assert.strictEqual(errors.getMessage('ERR_INVALID_URL_SCHEME', + [['http', 'ftp']]), 'The URL must be one of scheme http or ftp'); -assert.strictEqual(errors.message('ERR_INVALID_URL_SCHEME', [['a', 'b', 'c']]), +assert.strictEqual(errors.getMessage('ERR_INVALID_URL_SCHEME', + [['a', 'b', 'c']]), 'The URL must be one of scheme a, b, or c'); common.expectsError( - () => errors.message('ERR_INVALID_URL_SCHEME', [[]]), + () => errors.getMessage('ERR_INVALID_URL_SCHEME', [[]]), { code: 'ERR_ASSERTION', type: assert.AssertionError, @@ -114,79 +116,72 @@ common.expectsError( }); // Test ERR_MISSING_ARGS -assert.strictEqual(errors.message('ERR_MISSING_ARGS', ['name']), +assert.strictEqual(errors.getMessage('ERR_MISSING_ARGS', ['name']), 'The "name" argument must be specified'); -assert.strictEqual(errors.message('ERR_MISSING_ARGS', ['name', 'value']), +assert.strictEqual(errors.getMessage('ERR_MISSING_ARGS', ['name', 'value']), 'The "name" and "value" arguments must be specified'); -assert.strictEqual(errors.message('ERR_MISSING_ARGS', ['a', 'b', 'c']), +assert.strictEqual(errors.getMessage('ERR_MISSING_ARGS', ['a', 'b', 'c']), 'The "a", "b", and "c" arguments must be specified'); -common.expectsError( - () => errors.message('ERR_MISSING_ARGS'), - { - code: 'ERR_ASSERTION', - type: assert.AssertionError, - message: /^At least one arg needs to be specified$/ - }); // Test ERR_SOCKET_BAD_PORT assert.strictEqual( - errors.message('ERR_SOCKET_BAD_PORT', [0]), + errors.getMessage('ERR_SOCKET_BAD_PORT', [0]), 'Port should be > 0 and < 65536. Received 0.'); // Test ERR_TLS_CERT_ALTNAME_INVALID assert.strictEqual( - errors.message('ERR_TLS_CERT_ALTNAME_INVALID', ['altname']), + errors.getMessage('ERR_TLS_CERT_ALTNAME_INVALID', ['altname']), 'Hostname/IP does not match certificate\'s altnames: altname'); assert.strictEqual( - errors.message('ERR_INVALID_PROTOCOL', ['bad protocol', 'http']), + errors.getMessage('ERR_INVALID_PROTOCOL', ['bad protocol', 'http']), 'Protocol "bad protocol" not supported. Expected "http"' ); assert.strictEqual( - errors.message('ERR_HTTP_HEADERS_SENT', ['render']), + errors.getMessage('ERR_HTTP_HEADERS_SENT', ['render']), 'Cannot render headers after they are sent to the client' ); assert.strictEqual( - errors.message('ERR_INVALID_DOMAIN_NAME'), + errors.getMessage('ERR_INVALID_DOMAIN_NAME', []), 'Unable to determine the domain name' ); assert.strictEqual( - errors.message('ERR_INVALID_HTTP_TOKEN', ['Method', 'foo']), + errors.getMessage('ERR_INVALID_HTTP_TOKEN', ['Method', 'foo']), 'Method must be a valid HTTP token ["foo"]' ); assert.strictEqual( - errors.message('ERR_OUT_OF_RANGE', ['A', 'some values', 'B']), + errors.getMessage('ERR_OUT_OF_RANGE', ['A', 'some values', 'B']), 'The value of "A" is out of range. It must be some values. Received B' ); assert.strictEqual( - errors.message('ERR_UNESCAPED_CHARACTERS', ['Request path']), + errors.getMessage('ERR_UNESCAPED_CHARACTERS', ['Request path']), 'Request path contains unescaped characters' ); // Test ERR_DNS_SET_SERVERS_FAILED assert.strictEqual( - errors.message('ERR_DNS_SET_SERVERS_FAILED', ['err', 'servers']), + errors.getMessage('ERR_DNS_SET_SERVERS_FAILED', ['err', 'servers']), 'c-ares failed to set servers: "err" [servers]'); // Test ERR_ENCODING_NOT_SUPPORTED assert.strictEqual( - errors.message('ERR_ENCODING_NOT_SUPPORTED', ['enc']), + errors.getMessage('ERR_ENCODING_NOT_SUPPORTED', ['enc']), 'The "enc" encoding is not supported'); // Test error messages for async_hooks assert.strictEqual( - errors.message('ERR_ASYNC_CALLBACK', ['init']), + errors.getMessage('ERR_ASYNC_CALLBACK', ['init']), 'init must be a function'); assert.strictEqual( - errors.message('ERR_ASYNC_TYPE', [{}]), + errors.getMessage('ERR_ASYNC_TYPE', [{}]), 'Invalid name for async "type": [object Object]'); assert.strictEqual( - errors.message('ERR_INVALID_ASYNC_ID', ['asyncId', undefined]), + errors.getMessage('ERR_INVALID_ASYNC_ID', ['asyncId', undefined]), 'Invalid asyncId value: undefined'); { From dfcf20f5fd76fe5448115c7d448878868d8e7567 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Nie=C3=9Fen?= Date: Thu, 26 Apr 2018 21:05:18 +0200 Subject: [PATCH 074/173] crypto: use new OpenSSL constants in CipherBase This change replaces some constants with better alternatives which were unavailable in OpenSSL 1.0.2. PR-URL: https://github.com/nodejs/node/pull/20339 Refs: https://github.com/nodejs/node/pull/19794 Refs: https://github.com/nodejs/node/pull/18138 Reviewed-By: Ben Noordhuis Reviewed-By: Daniel Bevenius Reviewed-By: Colin Ihrig Reviewed-By: James M Snell --- src/node_crypto.cc | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 34018384eeeb75..c195868033f968 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -2791,10 +2791,7 @@ bool CipherBase::InitAuthenticated(const char *cipher_type, int iv_len, int auth_tag_len) { CHECK(IsAuthenticatedMode()); - // TODO(tniessen) Use EVP_CTRL_AEAD_SET_IVLEN when migrating to OpenSSL 1.1.0 - static_assert(EVP_CTRL_CCM_SET_IVLEN == EVP_CTRL_GCM_SET_IVLEN, - "OpenSSL constants differ between GCM and CCM"); - if (!EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_GCM_SET_IVLEN, iv_len, nullptr)) { + if (!EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_AEAD_SET_IVLEN, iv_len, nullptr)) { env()->ThrowError("Invalid IV length"); return false; } @@ -3085,10 +3082,8 @@ bool CipherBase::Final(unsigned char** out, int *out_len) { // must be specified in advance. if (mode == EVP_CIPH_GCM_MODE) auth_tag_len_ = sizeof(auth_tag_); - // TOOD(tniessen) Use EVP_CTRL_AEAP_GET_TAG in OpenSSL 1.1.0 - static_assert(EVP_CTRL_CCM_GET_TAG == EVP_CTRL_GCM_GET_TAG, - "OpenSSL constants differ between GCM and CCM"); - CHECK_EQ(1, EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_GCM_GET_TAG, auth_tag_len_, + CHECK_EQ(1, EVP_CIPHER_CTX_ctrl(ctx_, EVP_CTRL_AEAD_GET_TAG, + auth_tag_len_, reinterpret_cast(auth_tag_))); } } From b61ae7fe09ffa25fcbfa7c45ab5e5a4ef2d1cf47 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sun, 29 Apr 2018 20:26:29 -0700 Subject: [PATCH 075/173] doc: remove "has been known" tentativeness Remove unnecessary "has been known to" tentativeness from COLLABORATOR_GUIDE.md. "has been known to" is an awkward replacement for "can" or "might" or "sometimes does" or "does". Pick the right one and use it. PR-URL: https://github.com/nodejs/node/pull/20412 Reviewed-By: Vse Mozhet Byt Reviewed-By: Luigi Pinca Reviewed-By: Trivikram Kamat Reviewed-By: Colin Ihrig Reviewed-By: Ruben Bridgewater --- COLLABORATOR_GUIDE.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/COLLABORATOR_GUIDE.md b/COLLABORATOR_GUIDE.md index a7b1e68d7276a9..89c532e9d025f5 100644 --- a/COLLABORATOR_GUIDE.md +++ b/COLLABORATOR_GUIDE.md @@ -489,8 +489,7 @@ The TSC should serve as the final arbiter where required. 1. Never use GitHub's green ["Merge Pull Request"][] button. Reasons for not using the web interface button: * The merge method will add an unnecessary merge commit. - * The squash & merge method has been known to add metadata to the commit - title (the PR #). + * The squash & merge method can add metadata (the PR #) to the commit title. * If more than one author has contributed to the PR, keep the most recent author when squashing. 1. Make sure the CI is done and the result is green. If the CI is not green, From d7557e111e5d94443aa88d8e2a35a896bea5dc03 Mon Sep 17 00:00:00 2001 From: Gabriel Schulhof Date: Sat, 28 Apr 2018 21:54:21 -0400 Subject: [PATCH 076/173] doc: refine napi_get_property_names() doc Document that only enumerable, string-keyed properties are returned. Fixes: https://github.com/nodejs/abi-stable-node/issues/307 PR-URL: https://github.com/nodejs/node/pull/20427 Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: Michael Dawson Reviewed-By: Vse Mozhet Byt --- doc/api/n-api.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/api/n-api.md b/doc/api/n-api.md index adb8647b399ecd..92340cf834e3f0 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -2520,7 +2520,9 @@ and [`napi_get_element`][]. Returns `napi_ok` if the API succeeded. -This API returns the array of properties for the `Object` passed in. +This API returns the names of the enumerable properties of `object` as an array +of strings. The properties of `object` whose key is a symbol will not be +included. #### napi_set_property +* `settings` {HTTP/2 Settings Object} A copy of the `SETTINGS` frame received. + The `'localSettings'` event is emitted when an acknowledgment `SETTINGS` frame -has been received. When invoked, the handler function will receive a copy of -the local settings. +has been received. When using `http2session.settings()` to submit new settings, the modified settings do not take effect until the `'localSettings'` event is emitted. @@ -215,9 +216,10 @@ session.on('localSettings', (settings) => { added: v8.4.0 --> +* `settings` {HTTP/2 Settings Object} A copy of the `SETTINGS` frame received. + The `'remoteSettings'` event is emitted when a new `SETTINGS` frame is received -from the connected peer. When invoked, the handler function will receive a copy -of the remote settings. +from the connected peer. ```js session.on('remoteSettings', (settings) => { From f36a5e3ba5fdb45c97bf41f77a56d46d0292078b Mon Sep 17 00:00:00 2001 From: Ayush Gupta Date: Sun, 29 Apr 2018 12:29:23 +0530 Subject: [PATCH 080/173] doc: remove redundant table of contents for N-API Since the table of contents is built dynamically when building the documentation, the additional table of contents is redundant and an extra overhead to maintain. PR-URL: https://github.com/nodejs/node/pull/20395 Reviewed-By: Rich Trott Reviewed-By: Trivikram Kamat Reviewed-By: Vse Mozhet Byt Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: Gus Caplan Reviewed-By: Colin Ihrig --- doc/api/n-api.md | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/doc/api/n-api.md b/doc/api/n-api.md index 1ad9312b199cd2..77d71e28440910 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -33,22 +33,6 @@ properties: using `napi_get_last_error_info`. More information can be found in the error handling section [Error Handling][]. -The documentation for N-API is structured as follows: - -* [Basic N-API Data Types][] -* [Error Handling][] -* [Object Lifetime Management][] -* [Module Registration][] -* [Working with JavaScript Values][] -* [Working with JavaScript Values - Abstract Operations][] -* [Working with JavaScript Properties][] -* [Working with JavaScript Functions][] -* [Object Wrap][] -* [Simple Asynchronous Operations][] -* [Custom Asynchronous Operations][] -* [Promises][] -* [Script Execution][] - The N-API is a C API that ensures ABI stability across Node.js versions and different compiler levels. However, we also understand that a C++ API can be easier to use in many cases. To support these cases we expect @@ -3795,17 +3779,11 @@ NAPI_EXTERN napi_status napi_get_uv_event_loop(napi_env env, - `[in] env`: The environment that the API is invoked under. - `[out] loop`: The current libuv loop instance. -[Promises]: #n_api_promises -[Simple Asynchronous Operations]: #n_api_simple_asynchronous_operations -[Custom Asynchronous Operations]: #n_api_custom_asynchronous_operations -[Basic N-API Data Types]: #n_api_basic_n_api_data_types [ECMAScript Language Specification]: https://tc39.github.io/ecma262/ [Error Handling]: #n_api_error_handling -[Module Registration]: #n_api_module_registration [Native Abstractions for Node.js]: https://github.com/nodejs/nan [Object Lifetime Management]: #n_api_object_lifetime_management [Object Wrap]: #n_api_object_wrap -[Script Execution]: #n_api_script_execution [Section 6.1.4]: https://tc39.github.io/ecma262/#sec-ecmascript-language-types-string-type [Section 6.1.6]: https://tc39.github.io/ecma262/#sec-ecmascript-language-types-number-type [Section 6.1.7.1]: https://tc39.github.io/ecma262/#table-2 From 459c20c0b8c2188c1bec7cd7be678d3a29d88ce3 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Mon, 30 Apr 2018 21:50:35 -0700 Subject: [PATCH 081/173] doc: edit fs.createReadStream() highWaterMark MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shorten the text about the `highWaterMark` value for the stream returned by `fs.createReadStream()`. PR-URL: https://github.com/nodejs/node/pull/20450 Reviewed-By: Luigi Pinca Reviewed-By: Vse Mozhet Byt Reviewed-By: Colin Ihrig Reviewed-By: Tobias Nießen Reviewed-By: Trivikram Kamat Reviewed-By: James M Snell --- doc/api/fs.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/doc/api/fs.md b/doc/api/fs.md index 283ed7e2dd8e3d..61a587dc42ad1c 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -1316,9 +1316,8 @@ changes: * `highWaterMark` {integer} **Default:** `64 * 1024` * Returns: {fs.ReadStream} See [Readable Streams][]. -Be aware that, unlike the default value set for `highWaterMark` on a -readable stream (16 kb), the stream returned by this method has a -default value of 64 kb for the same parameter. +Unlike the 16 kb default `highWaterMark` for a readable stream, the stream +returned by this method has a default `highWaterMark` of 64 kb. `options` can include `start` and `end` values to read a range of bytes from the file instead of the entire file. Both `start` and `end` are inclusive and From 5a839b99118d3c8c53ee3694d625882cd27cfa11 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Mon, 30 Apr 2018 21:52:05 -0700 Subject: [PATCH 082/173] doc: remove unclear text from fs.write() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is a paragraph explaining that `fs.write()` cannot write a substring of the provided string. It's not clear what `buffer` refers to in that paragraph or even what the purpose of the paragraph is. There's no suggestion elsewhere that `fs.write()` should be expected to have a substring feature. Remove the paragraph. PR-URL: https://github.com/nodejs/node/pull/20450 Reviewed-By: Luigi Pinca Reviewed-By: Vse Mozhet Byt Reviewed-By: Colin Ihrig Reviewed-By: Tobias Nießen Reviewed-By: Trivikram Kamat Reviewed-By: James M Snell --- doc/api/fs.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/doc/api/fs.md b/doc/api/fs.md index 61a587dc42ad1c..98b3c0cea26d24 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -3233,10 +3233,6 @@ The callback will receive the arguments `(err, written, string)` where `written` specifies how many _bytes_ the passed string required to be written. Note that bytes written is not the same as string characters. See [`Buffer.byteLength`][]. -Unlike when writing `buffer`, the entire string must be written. No substring -may be specified. This is because the byte offset of the resulting data may not -be the same as the string offset. - Note that it is unsafe to use `fs.write` multiple times on the same file without waiting for the callback. For this scenario, `fs.createWriteStream` is strongly recommended. From fcc5492df2d64a5cfefd7a453a5e90f18953260c Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Mon, 30 Apr 2018 21:56:46 -0700 Subject: [PATCH 083/173] doc: clarify FileHandle text MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is a paragraph about why the promise-based API uses `FileHandle` rather than a numeric `fd`. Unfortunately, the paragraph is a bit of word-salad. Edit it for clarity, grammar, and style. PR-URL: https://github.com/nodejs/node/pull/20450 Reviewed-By: Luigi Pinca Reviewed-By: Vse Mozhet Byt Reviewed-By: Colin Ihrig Reviewed-By: Tobias Nießen Reviewed-By: Trivikram Kamat Reviewed-By: James M Snell --- doc/api/fs.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/api/fs.md b/doc/api/fs.md index 98b3c0cea26d24..ee541b78e48224 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -3378,11 +3378,11 @@ and will emit a process warning, thereby helping to prevent memory leaks. Instances of the `FileHandle` object are created internally by the `fsPromises.open()` method. -Unlike callback-based such as `fs.fstat()`, `fs.fchown()`, `fs.fchmod()`, -`fs.ftruncate()`, `fs.read()`, and `fs.write()`, operations — all of which -use a simple numeric file descriptor, all `fsPromises.*` variations use the -`FileHandle` class in order to help protect against accidental leaking of -unclosed file descriptors after a `Promise` is resolved or rejected. +Unlike the callback-based API (`fs.fstat()`, `fs.fchown()`, `fs.fchmod()`, and +so on), a numeric file descriptor is not used by the promise-based API. Instead, +the promise-based API uses the `FileHandle` class in order to help avoid +accidental leaking of unclosed file descriptors after a `Promise` is resolved or +rejected. #### filehandle.appendFile(data, options) -* `message` {Object} a parsed JSON object or primitive value. +* `message` { Object | boolean | number | string | null } a parsed JSON object + or a serializable primitive value. * `sendHandle` {net.Server|net.Socket} a [`net.Server`][] or [`net.Socket`][] object, or undefined. From 261776d6b48d4d853f7a7da07abba48e2996dd1a Mon Sep 17 00:00:00 2001 From: Vse Mozhet Byt Date: Mon, 30 Apr 2018 00:39:20 +0300 Subject: [PATCH 086/173] doc: mitigate `marked` bug PR-URL: https://github.com/nodejs/node/pull/20411 Reviewed-By: Trivikram Kamat Reviewed-By: Luigi Pinca Reviewed-By: Colin Ihrig --- doc/api/net.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/api/net.md b/doc/api/net.md index 6b8afce4a59121..041e8e88b46438 100644 --- a/doc/api/net.md +++ b/doc/api/net.md @@ -192,7 +192,8 @@ Possible signatures: * [`server.listen(options[, callback])`][`server.listen(options)`] * [`server.listen(path[, backlog][, callback])`][`server.listen(path)`] for [IPC][] servers -* [`server.listen([port[, host[, backlog]]][, callback])`][`server.listen(port, host)`] +* + server.listen([port[, host[, backlog]]][, callback]) for TCP servers This function is asynchronous. When the server starts listening, the @@ -264,7 +265,8 @@ added: v0.11.14 * Returns: {net.Server} If `port` is specified, it behaves the same as -[`server.listen([port[, host[, backlog]]][, callback])`][`server.listen(port, host)`]. + +server.listen([port[, host[, backlog]]][, callback]). Otherwise, if `path` is specified, it behaves the same as [`server.listen(path[, backlog][, callback])`][`server.listen(path)`]. If none of them is specified, an error will be thrown. @@ -1136,7 +1138,6 @@ Returns `true` if input is a version 6 IP address, otherwise returns `false`. [`server.listen(handle)`]: #net_server_listen_handle_backlog_callback [`server.listen(options)`]: #net_server_listen_options_callback [`server.listen(path)`]: #net_server_listen_path_backlog_callback -[`server.listen(port, host)`]: #net_server_listen_port_host_backlog_callback [`socket.connect()`]: #net_socket_connect [`socket.connect(options)`]: #net_socket_connect_options_connectlistener [`socket.connect(path)`]: #net_socket_connect_path_connectlistener From abf11550b28cb45fa75b17265f7a9272aeac2a59 Mon Sep 17 00:00:00 2001 From: Vse Mozhet Byt Date: Sun, 29 Apr 2018 14:16:44 +0300 Subject: [PATCH 087/173] doc: add missing periods or colons Some other formatting nits were fixed and some superfluous descriptions were simplified in passing. PR-URL: https://github.com/nodejs/node/pull/20401 Reviewed-By: Ruben Bridgewater Reviewed-By: Gireesh Punathil Reviewed-By: Trivikram Kamat Reviewed-By: Colin Ihrig --- doc/api/buffer.md | 2 +- doc/api/child_process.md | 6 +++--- doc/api/cli.md | 10 +++++----- doc/api/cluster.md | 6 +++--- doc/api/console.md | 2 +- doc/api/deprecations.md | 2 +- doc/api/dgram.md | 16 ++++++++-------- doc/api/errors.md | 2 +- doc/api/fs.md | 19 ++++++++++--------- doc/api/http.md | 6 +++--- doc/api/http2.md | 2 +- doc/api/https.md | 2 +- doc/api/modules.md | 4 ++-- doc/api/n-api.md | 6 +++--- doc/api/net.md | 22 ++++++++++------------ doc/api/os.md | 2 +- doc/api/process.md | 2 +- doc/api/readline.md | 2 +- doc/api/repl.md | 9 +++++---- doc/api/stream.md | 2 -- doc/api/synopsis.md | 6 +++--- doc/api/tls.md | 16 +++++++--------- doc/api/url.md | 22 +++++++++++----------- doc/api/util.md | 25 +++++++++++++------------ doc/api/vm.md | 2 +- doc/api/zlib.md | 2 +- 26 files changed, 97 insertions(+), 100 deletions(-) diff --git a/doc/api/buffer.md b/doc/api/buffer.md index 0195c1cd2651d8..312b4f7c17f8a3 100644 --- a/doc/api/buffer.md +++ b/doc/api/buffer.md @@ -2458,7 +2458,7 @@ added: v3.0.0 * {integer} The largest size allowed for a single `Buffer` instance. -An alias for [`buffer.constants.MAX_LENGTH`][] +An alias for [`buffer.constants.MAX_LENGTH`][]. Note that this is a property on the `buffer` module returned by `require('buffer')`, not on the `Buffer` global or a `Buffer` instance. diff --git a/doc/api/child_process.md b/doc/api/child_process.md index 62b2355ee38803..47d68928e46ab2 100644 --- a/doc/api/child_process.md +++ b/doc/api/child_process.md @@ -652,7 +652,7 @@ child registers an event handler for the [`'disconnect'`][] event or the [`'message'`][] event. This allows the child to exit normally without the process being held open by the open IPC channel.* -See also: [`child_process.exec()`][] and [`child_process.fork()`][] +See also: [`child_process.exec()`][] and [`child_process.fork()`][]. ## Synchronous Process Creation @@ -776,7 +776,7 @@ process has exited.* If the process times out or has a non-zero exit code, this method ***will*** throw. The [`Error`][] object will contain the entire result from -[`child_process.spawnSync()`][] +[`child_process.spawnSync()`][]. **Never pass unsanitized user input to this function. Any input containing shell metacharacters may be used to trigger arbitrary command execution.** @@ -1056,7 +1056,7 @@ does not indicate that the child process has been terminated. added: v0.1.90 --> -* {number} Integer +* {integer} Returns the process identifier (PID) of the child process. diff --git a/doc/api/cli.md b/doc/api/cli.md index 817f49142cb4c6..5bc673f5975d6f 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -58,7 +58,7 @@ added: v6.0.0 --> Enable FIPS-compliant crypto at startup. (Requires Node.js to be built with -`./configure --openssl-fips`) +`./configure --openssl-fips`.) ### `--experimental-modules` Force FIPS-compliant crypto on startup. (Cannot be disabled from script code.) -(Same requirements as `--enable-fips`) +(Same requirements as `--enable-fips`.) ### `--icu-data-dir=file` -Specify ICU data load path. (overrides `NODE_ICU_DATA`) +Specify ICU data load path. (Overrides `NODE_ICU_DATA`.) ### `--inspect-brk[=[host:]port]` -Specify an alternative default TLS cipher list. (Requires Node.js to be built -with crypto support. (Default)) +Specify an alternative default TLS cipher list. Requires Node.js to be built +with crypto support (default). ### `--trace-deprecation` -* `settings` {Object} see [`cluster.settings`][] +* `settings` {Object} See [`cluster.settings`][]. `setupMaster` is used to change the default 'fork' behavior. Once called, the settings will be present in `cluster.settings`. diff --git a/doc/api/console.md b/doc/api/console.md index 6a88d4049531e5..bc8c8f01d658eb 100644 --- a/doc/api/console.md +++ b/doc/api/console.md @@ -99,7 +99,7 @@ changes: Setting to `true` enables coloring while inspecting values, setting to `'auto'` will make color support depend on the value of the `isTTY` property and the value returned by `getColorDepth()` on the respective stream. - **Default:** `'auto'` + **Default:** `'auto'`. Creates a new `Console` with one or two writable stream instances. `stdout` is a writable stream to print log or info output. `stderr` is used for warning or diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md index 74bd980af989c7..e799d06eba6604 100644 --- a/doc/api/deprecations.md +++ b/doc/api/deprecations.md @@ -170,7 +170,7 @@ explicitly via error event handlers set on the domain instead. Type: End-of-Life Calling an asynchronous function without a callback throws a `TypeError` -v10.0.0 onwards. Refer: [PR 12562](https://github.com/nodejs/node/pull/12562) +v10.0.0 onwards. Refer: [PR 12562](https://github.com/nodejs/node/pull/12562). ### DEP0014: fs.read legacy String interface diff --git a/doc/api/dgram.md b/doc/api/dgram.md index b6b974541bdfe7..31eeed43953bb1 100644 --- a/doc/api/dgram.md +++ b/doc/api/dgram.md @@ -111,7 +111,7 @@ properties. added: v0.1.99 --> -* `port` {number} Integer. +* `port` {integer} * `address` {string} * `callback` {Function} with no parameters. Called when binding is complete. @@ -279,9 +279,9 @@ changes: --> * `msg` {Buffer|Uint8Array|string|Array} Message to be sent. -* `offset` {number} Integer. Offset in the buffer where the message starts. -* `length` {number} Integer. Number of bytes in the message. -* `port` {number} Integer. Destination port. +* `offset` {integer} Offset in the buffer where the message starts. +* `length` {integer} Number of bytes in the message. +* `port` {integer} Destination port. * `address` {string} Destination hostname or IP address. * `callback` {Function} Called when the message has been sent. @@ -479,7 +479,7 @@ multicast packets will also be received on the local interface. added: v0.3.8 --> -* `ttl` {number} Integer. +* `ttl` {integer} Sets the `IP_MULTICAST_TTL` socket option. While TTL generally stands for "Time to Live", in this context it specifies the number of IP hops that a @@ -495,7 +495,7 @@ between 0 and 255. The default on most systems is `1` but can vary. added: v8.7.0 --> -* `size` {number} Integer +* `size` {integer} Sets the `SO_RCVBUF` socket option. Sets the maximum socket receive buffer in bytes. @@ -505,7 +505,7 @@ in bytes. added: v8.7.0 --> -* `size` {number} Integer +* `size` {integer} Sets the `SO_SNDBUF` socket option. Sets the maximum socket send buffer in bytes. @@ -515,7 +515,7 @@ in bytes. added: v0.1.101 --> -* `ttl` {number} Integer. +* `ttl` {integer} Sets the `IP_TTL` socket option. While TTL generally stands for "Time to Live", in this context it specifies the number of IP hops that a packet is allowed to diff --git a/doc/api/errors.md b/doc/api/errors.md index c626df298f6734..b434dc3c610f8a 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -1656,7 +1656,7 @@ entry types were found. ### ERR_VALUE_OUT_OF_RANGE -Superseded by `ERR_OUT_OF_RANGE` +Superseded by `ERR_OUT_OF_RANGE`. ### ERR_VM_MODULE_ALREADY_LINKED diff --git a/doc/api/fs.md b/doc/api/fs.md index ee541b78e48224..6e3628c8fbb2a0 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -500,7 +500,7 @@ added: v0.1.10 Returns `true` if the `fs.Stats` object describes a symbolic link. -This method is only valid when using [`fs.lstat()`][] +This method is only valid when using [`fs.lstat()`][]. ### stats.dev @@ -1038,7 +1038,7 @@ changes: Asynchronously changes the permissions of a file. No arguments other than a possible exception are given to the completion callback. -See also: chmod(2) +See also: chmod(2). ### File modes @@ -1097,7 +1097,7 @@ changes: Synchronously changes the permissions of a file. Returns `undefined`. This is the synchronous version of [`fs.chmod()`][]. -See also: chmod(2) +See also: chmod(2). ## fs.chown(path, uid, gid, callback) ```js diff --git a/doc/api/process.md b/doc/api/process.md index fdea86bf2d9039..9c0c26162e8bc1 100644 --- a/doc/api/process.md +++ b/doc/api/process.md @@ -289,7 +289,7 @@ command-line option can be used to suppress the default console output but the `'warning'` event will still be emitted by the `process` object. The following example illustrates the warning that is printed to `stderr` when -too many listeners have been added to an event +too many listeners have been added to an event: ```txt $ node diff --git a/doc/api/readline.md b/doc/api/readline.md index d3afe5d9bf5ba2..ead469e97c9f27 100644 --- a/doc/api/readline.md +++ b/doc/api/readline.md @@ -90,7 +90,7 @@ The `'pause'` event is emitted when one of the following occur: * The `input` stream is paused. * The `input` stream is not paused and receives the `'SIGCONT'` event. (See - events [`'SIGTSTP'`][] and [`'SIGCONT'`][]) + events [`'SIGTSTP'`][] and [`'SIGCONT'`][].) The listener function is called without passing any arguments. diff --git a/doc/api/repl.md b/doc/api/repl.md index 22312328276f5a..995dabaa5d863d 100644 --- a/doc/api/repl.md +++ b/doc/api/repl.md @@ -40,7 +40,7 @@ The following special commands are supported by all REPL instances: `> .save ./file/to/save.js` * `.load` - Load a file into the current REPL session. `> .load ./file/to/load.js` -* `.editor` - Enter editor mode (`-D` to finish, `-C` to cancel) +* `.editor` - Enter editor mode (`-D` to finish, `-C` to cancel). ```js @@ -607,10 +607,11 @@ By starting a REPL from a Unix socket-based server instead of stdin, it is possible to connect to a long-running Node.js process without restarting it. For an example of running a "full-featured" (`terminal`) REPL over -a `net.Server` and `net.Socket` instance, see: https://gist.github.com/2209310 +a `net.Server` and `net.Socket` instance, see: +[https://gist.github.com/2209310](https://gist.github.com/2209310). -For an example of running a REPL instance over [curl(1)][], -see: https://gist.github.com/2053342 +For an example of running a REPL instance over [curl(1)][], see: +[https://gist.github.com/2053342](https://gist.github.com/2053342). [`--experimental-repl-await`]: cli.html#cli_experimental_repl_await [`readline.InterfaceCompleter`]: readline.html#readline_use_of_the_completer_function diff --git a/doc/api/stream.md b/doc/api/stream.md index 8c80816d79eec2..8af12d12bf07bd 100644 --- a/doc/api/stream.md +++ b/doc/api/stream.md @@ -2407,14 +2407,12 @@ The workaround in this situation is to call the ```js // Workaround net.createServer((socket) => { - socket.on('end', () => { socket.end('The message was received but was not processed.\n'); }); // start the flow of data, discarding it. socket.resume(); - }).listen(1337); ``` diff --git a/doc/api/synopsis.md b/doc/api/synopsis.md index 508dde1ff483f8..ad14fae7b8d791 100644 --- a/doc/api/synopsis.md +++ b/doc/api/synopsis.md @@ -88,9 +88,9 @@ $ node hello-world.js An output like this should appear in the terminal to indicate Node.js server is running: - ```console - Server running at http://127.0.0.1:3000/ - ```` +```console +Server running at http://127.0.0.1:3000/ +``` Now, open any preferred web browser and visit `http://127.0.0.1:3000`. diff --git a/doc/api/tls.md b/doc/api/tls.md index beb2ec679e9f11..bdda8bd7343873 100644 --- a/doc/api/tls.md +++ b/doc/api/tls.md @@ -404,7 +404,7 @@ added: v3.0.0 * Returns: {Buffer} Returns a `Buffer` instance holding the keys currently used for -encryption/decryption of the [TLS Session Tickets][] +encryption/decryption of the [TLS Session Tickets][]. ### server.listen() @@ -516,10 +516,9 @@ added: v0.11.4 * Returns: {Object} -Returns the bound address, the address family name, and port of the -underlying socket as reported by the operating system. Returns an -object with three properties, e.g. -`{ port: 12346, family: 'IPv4', address: '127.0.0.1' }` +Returns the bound `address`, the address `family` name, and `port` of the +underlying socket as reported by the operating system: +`{ port: 12346, family: 'IPv4', address: '127.0.0.1' }`. ### tlsSocket.authorizationError ```js @@ -519,7 +519,7 @@ assert.doesNotThrow( /Wrong value/, 'Whoops' ); -// Throws: AssertionError: Got unwanted exception (TypeError). Whoops +// Throws: AssertionError: Got unwanted exception: Whoops ``` ## assert.equal(actual, expected[, message]) @@ -656,7 +656,7 @@ changes: - version: v10.0.0 pr-url: https://github.com/nodejs/node/pull/18247 description: Instead of throwing the original error it is now wrapped into - a AssertionError that contains the full stack trace. + an `AssertionError` that contains the full stack trace. - version: v10.0.0 pr-url: https://github.com/nodejs/node/pull/18247 description: Value may now only be `undefined` or `null`. Before any truthy @@ -701,10 +701,10 @@ added: v0.1.21 changes: - version: v9.0.0 pr-url: https://github.com/nodejs/node/pull/15001 - description: Error names and messages are now properly compared + description: The `Error` names and messages are now properly compared - version: v8.0.0 pr-url: https://github.com/nodejs/node/pull/12142 - description: Set and Map content is also compared + description: The `Set` and `Map` content is also compared - version: v6.4.0, v4.7.1 pr-url: https://github.com/nodejs/node/pull/8002 description: Typed array slices are handled correctly now. @@ -774,18 +774,18 @@ added: v1.2.0 changes: - version: v9.0.0 pr-url: https://github.com/nodejs/node/pull/15398 - description: -0 and +0 are not considered equal anymore. + description: The `-0` and `+0` are not considered equal anymore. - version: v9.0.0 pr-url: https://github.com/nodejs/node/pull/15036 - description: NaN is now compared using the + description: The `NaN` is now compared using the [SameValueZero](https://tc39.github.io/ecma262/#sec-samevaluezero) comparison. - version: v9.0.0 pr-url: https://github.com/nodejs/node/pull/15001 - description: Error names and messages are now properly compared + description: The `Error` names and messages are now properly compared - version: v8.0.0 pr-url: https://github.com/nodejs/node/pull/12142 - description: Set and Map content is also compared + description: The `Set` and `Map` content is also compared - version: v6.4.0, v4.7.1 pr-url: https://github.com/nodejs/node/pull/8002 description: Typed array slices are handled correctly now. @@ -893,7 +893,8 @@ added: v0.1.21 changes: - version: v10.0.0 pr-url: https://github.com/nodejs/node/pull/18319 - description: assert.ok() (no arguments) will now use a predefined error msg. + description: The `assert.ok()` (no arguments) will now use a predefined + error message. --> * `value` {any} * `message` {any} @@ -907,7 +908,7 @@ 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`. If no arguments are passed in at all `message` will be set to the string: -"No value argument passed to assert.ok". +``'No value argument passed to `assert.ok()`'``. Be aware that in the `repl` the error message will be different to the one thrown in a file! See below for further details. @@ -966,9 +967,9 @@ function and awaits the returned promise to complete. It will then check that the promise is rejected. If `block` is a function and it throws an error synchronously, -`assert.rejects()` will return a rejected Promise with that error. If the +`assert.rejects()` will return a rejected `Promise` with that error. If the function does not return a promise, `assert.rejects()` will return a rejected -Promise with an [`ERR_INVALID_RETURN_VALUE`][] error. In both cases the error +`Promise` with an [`ERR_INVALID_RETURN_VALUE`][] error. In both cases the error handler is skipped. Besides the async nature to await the completion behaves identically to diff --git a/doc/api/async_hooks.md b/doc/api/async_hooks.md index 601dad93e75a57..b97bc73304a4d7 100644 --- a/doc/api/async_hooks.md +++ b/doc/api/async_hooks.md @@ -17,8 +17,8 @@ const async_hooks = require('async_hooks'); An asynchronous resource represents an object with an associated callback. This callback may be called multiple times, for example, the `'connection'` event in `net.createServer()`, or just a single time like in `fs.open()`. -A resource can also be closed before the callback is called. AsyncHook does not -explicitly distinguish between these different cases but will represent them +A resource can also be closed before the callback is called. `AsyncHook` does +not explicitly distinguish between these different cases but will represent them as the abstract concept that is a resource. ## Public API @@ -188,7 +188,7 @@ const hook = async_hooks.createHook(callbacks).enable(); * Returns: {AsyncHook} A reference to `asyncHook`. Disable the callbacks for a given `AsyncHook` instance from the global pool of -AsyncHook callbacks to be executed. Once a hook has been disabled it will not +`AsyncHook` callbacks to be executed. Once a hook has been disabled it will not be called again until enabled. For API consistency `disable()` also returns the `AsyncHook` instance. @@ -299,10 +299,10 @@ and document their own resource objects. For example, such a resource object could contain the SQL query being executed. In the case of Promises, the `resource` object will have `promise` property -that refers to the Promise that is being initialized, and a `isChainedPromise` -property, set to `true` if the promise has a parent promise, and `false` -otherwise. For example, in the case of `b = a.then(handler)`, `a` is considered -a parent Promise of `b`. Here, `b` is considered a chained promise. +that refers to the `Promise` that is being initialized, and an +`isChainedPromise` property, set to `true` if the promise has a parent promise, +and `false` otherwise. For example, in the case of `b = a.then(handler)`, `a` is +considered a parent `Promise` of `b`. Here, `b` is considered a chained promise. In some cases the resource object is reused for performance reasons, it is thus not safe to use it as a key in a `WeakMap` or add properties to it. @@ -466,7 +466,7 @@ added: v8.1.0 changes: - version: v8.2.0 pr-url: https://github.com/nodejs/node/pull/13490 - description: Renamed from currentId + description: Renamed from `currentId` --> * Returns: {number} The `asyncId` of the current execution context. Useful to @@ -498,7 +498,7 @@ const server = net.createServer(function onConnection(conn) { }); ``` -Note that promise contexts may not get precise executionAsyncIds by default. +Note that promise contexts may not get precise `executionAsyncIds` by default. See the section on [promise execution tracking][]. #### async_hooks.triggerAsyncId() @@ -521,12 +521,12 @@ const server = net.createServer((conn) => { }); ``` -Note that promise contexts may not get valid triggerAsyncIds by default. See +Note that promise contexts may not get valid `triggerAsyncId`s by default. See the section on [promise execution tracking][]. ## Promise execution tracking -By default, promise executions are not assigned asyncIds due to the relatively +By default, promise executions are not assigned `asyncId`s due to the relatively expensive nature of the [promise introspection API][PromiseHooks] provided by V8. This means that programs using promises or `async`/`await` will not get correct execution and trigger ids for promise callback contexts by default. @@ -542,10 +542,10 @@ Promise.resolve(1729).then(() => { // eid 1 tid 0 ``` -Observe that the `then` callback claims to have executed in the context of the +Observe that the `then()` callback claims to have executed in the context of the outer scope even though there was an asynchronous hop involved. Also note that -the triggerAsyncId value is 0, which means that we are missing context about the -resource that caused (triggered) the `then` callback to be executed. +the `triggerAsyncId` value is `0`, which means that we are missing context about +the resource that caused (triggered) the `then()` callback to be executed. Installing async hooks via `async_hooks.createHook` enables promise execution tracking. Example: @@ -562,15 +562,16 @@ Promise.resolve(1729).then(() => { In this example, adding any actual hook function enabled the tracking of promises. There are two promises in the example above; the promise created by -`Promise.resolve()` and the promise returned by the call to `then`. In the -example above, the first promise got the asyncId 6 and the latter got asyncId 7. -During the execution of the `then` callback, we are executing in the context of -promise with asyncId 7. This promise was triggered by async resource 6. +`Promise.resolve()` and the promise returned by the call to `then()`. In the +example above, the first promise got the `asyncId` `6` and the latter got +`asyncId` `7`. During the execution of the `then()` callback, we are executing +in the context of promise with `asyncId` `7`. This promise was triggered by +async resource `6`. Another subtlety with promises is that `before` and `after` callbacks are run -only on chained promises. That means promises not created by `then`/`catch` will -not have the `before` and `after` callbacks fired on them. For more details see -the details of the V8 [PromiseHooks][] API. +only on chained promises. That means promises not created by `then()`/`catch()` +will not have the `before` and `after` callbacks fired on them. For more details +see the details of the V8 [PromiseHooks][] API. ## JavaScript Embedder API @@ -632,8 +633,9 @@ asyncResource.emitAfter(); async event. **Default:** `executionAsyncId()`. * `requireManualDestroy` {boolean} Disables automatic `emitDestroy` when the object is garbage collected. This usually does not need to be set (even if - `emitDestroy` is called manually), unless the resource's asyncId is retrieved - and the sensitive API's `emitDestroy` is called with it. **Default:** `false`. + `emitDestroy` is called manually), unless the resource's `asyncId` is + retrieved and the sensitive API's `emitDestroy` is called with it. + **Default:** `false`. Example usage: diff --git a/doc/api/buffer.md b/doc/api/buffer.md index 312b4f7c17f8a3..c219f00e4a1f48 100644 --- a/doc/api/buffer.md +++ b/doc/api/buffer.md @@ -221,7 +221,7 @@ elements, and not as a byte array of the target type. That is, `[0x1020304]` or `[0x4030201]`. It is possible to create a new `Buffer` that shares the same allocated memory as -a [`TypedArray`] instance by using the TypeArray object's `.buffer` property. +a [`TypedArray`] instance by using the `TypeArray` object's `.buffer` property. ```js const arr = new Uint16Array(2); @@ -427,7 +427,8 @@ changes: run from code outside the `node_modules` directory. - version: v8.0.0 pr-url: https://github.com/nodejs/node/pull/12141 - description: new Buffer(size) will return zero-filled memory by default. + description: The `new Buffer(size)` will return zero-filled memory by + default. - version: v7.2.1 pr-url: https://github.com/nodejs/node/pull/9529 description: Calling this constructor no longer emits a deprecation warning. @@ -980,8 +981,8 @@ console.log(buf.toString('ascii')); ### buf.buffer -The `buffer` property references the underlying `ArrayBuffer` object based on -which this Buffer object is created. +* {ArrayBuffer} The underlying `ArrayBuffer` object based on + which this `Buffer` object is created. ```js const arrayBuffer = new ArrayBuffer(16); @@ -1507,8 +1508,8 @@ added: v0.11.15 changes: - version: v10.0.0 pr-url: https://github.com/nodejs/node/pull/18395 - description: Removed noAssert and no implicit coercion of the offset to - uint32 anymore. + description: Removed `noAssert` and no implicit coercion of the offset + to `uint32` anymore. --> * `offset` {integer} Number of bytes to skip before starting to read. Must @@ -1537,8 +1538,8 @@ added: v0.11.15 changes: - version: v10.0.0 pr-url: https://github.com/nodejs/node/pull/18395 - description: Removed noAssert and no implicit coercion of the offset to - uint32 anymore. + description: Removed `noAssert` and no implicit coercion of the offset + to `uint32` anymore. --> * `offset` {integer} Number of bytes to skip before starting to read. Must @@ -1566,8 +1567,8 @@ added: v0.5.0 changes: - version: v10.0.0 pr-url: https://github.com/nodejs/node/pull/18395 - description: Removed noAssert and no implicit coercion of the offset to - uint32 anymore. + description: Removed `noAssert` and no implicit coercion of the offset + to `uint32` anymore. --> * `offset` {integer} Number of bytes to skip before starting to read. Must @@ -1596,8 +1597,8 @@ added: v0.5.5 changes: - version: v10.0.0 pr-url: https://github.com/nodejs/node/pull/18395 - description: Removed noAssert and no implicit coercion of the offset to - uint32 anymore. + description: Removed `noAssert` and no implicit coercion of the offset + to `uint32` anymore. --> * `offset` {integer} Number of bytes to skip before starting to read. Must @@ -1628,8 +1629,8 @@ added: v0.5.5 changes: - version: v10.0.0 pr-url: https://github.com/nodejs/node/pull/18395 - description: Removed noAssert and no implicit coercion of the offset to - uint32 anymore. + description: Removed `noAssert` and no implicit coercion of the offset + to `uint32` anymore. --> * `offset` {integer} Number of bytes to skip before starting to read. Must @@ -1660,8 +1661,8 @@ added: v0.11.15 changes: - version: v10.0.0 pr-url: https://github.com/nodejs/node/pull/18395 - description: Removed noAssert and no implicit coercion of the offset and - byteLength to uint32 anymore. + description: Removed `noAssert` and no implicit coercion of the offset + and `byteLength` to `uint32` anymore. --> * `offset` {integer} Number of bytes to skip before starting to read. Must @@ -1693,8 +1694,8 @@ added: v0.5.0 changes: - version: v10.0.0 pr-url: https://github.com/nodejs/node/pull/18395 - description: Removed noAssert and no implicit coercion of the offset to - uint32 anymore. + description: Removed `noAssert` and no implicit coercion of the offset + to `uint32` anymore. --> * `offset` {integer} Number of bytes to skip before starting to read. Must @@ -1721,8 +1722,8 @@ added: v0.5.5 changes: - version: v10.0.0 pr-url: https://github.com/nodejs/node/pull/18395 - description: Removed noAssert and no implicit coercion of the offset to - uint32 anymore. + description: Removed `noAssert` and no implicit coercion of the offset + to `uint32` anymore. --> * `offset` {integer} Number of bytes to skip before starting to read. Must @@ -1755,8 +1756,8 @@ added: v0.5.5 changes: - version: v10.0.0 pr-url: https://github.com/nodejs/node/pull/18395 - description: Removed noAssert and no implicit coercion of the offset to - uint32 anymore. + description: Removed `noAssert` and no implicit coercion of the offset + to `uint32` anymore. --> * `offset` {integer} Number of bytes to skip before starting to read. Must @@ -1785,8 +1786,8 @@ added: v0.11.15 changes: - version: v10.0.0 pr-url: https://github.com/nodejs/node/pull/18395 - description: Removed noAssert and no implicit coercion of the offset and - byteLength to uint32 anymore. + description: Removed `noAssert` and no implicit coercion of the offset + and `byteLength` to `uint32` anymore. --> * `offset` {integer} Number of bytes to skip before starting to read. Must @@ -2102,8 +2103,8 @@ added: v0.11.15 changes: - version: v10.0.0 pr-url: https://github.com/nodejs/node/pull/18395 - description: Removed noAssert and no implicit coercion of the offset to - uint32 anymore. + description: Removed `noAssert` and no implicit coercion of the offset + to `uint32` anymore. --> * `value` {number} Number to be written to `buf`. @@ -2137,8 +2138,8 @@ added: v0.11.15 changes: - version: v10.0.0 pr-url: https://github.com/nodejs/node/pull/18395 - description: Removed noAssert and no implicit coercion of the offset to - uint32 anymore. + description: Removed `noAssert` and no implicit coercion of the offset + to `uint32` anymore. --> * `value` {number} Number to be written to `buf`. @@ -2171,8 +2172,8 @@ added: v0.5.0 changes: - version: v10.0.0 pr-url: https://github.com/nodejs/node/pull/18395 - description: Removed noAssert and no implicit coercion of the offset to - uint32 anymore. + description: Removed `noAssert` and no implicit coercion of the offset + to `uint32` anymore. --> * `value` {integer} Number to be written to `buf`. @@ -2203,8 +2204,8 @@ added: v0.5.5 changes: - version: v10.0.0 pr-url: https://github.com/nodejs/node/pull/18395 - description: Removed noAssert and no implicit coercion of the offset to - uint32 anymore. + description: Removed `noAssert` and no implicit coercion of the offset + to `uint32` anymore. --> * `value` {integer} Number to be written to `buf`. @@ -2236,8 +2237,8 @@ added: v0.5.5 changes: - version: v10.0.0 pr-url: https://github.com/nodejs/node/pull/18395 - description: Removed noAssert and no implicit coercion of the offset to - uint32 anymore. + description: Removed `noAssert` and no implicit coercion of the offset + to `uint32` anymore. --> * `value` {integer} Number to be written to `buf`. @@ -2269,8 +2270,8 @@ added: v0.11.15 changes: - version: v10.0.0 pr-url: https://github.com/nodejs/node/pull/18395 - description: Removed noAssert and no implicit coercion of the offset and - byteLength to uint32 anymore. + description: Removed `noAssert` and no implicit coercion of the offset + and `byteLength` to `uint32` anymore. --> * `value` {integer} Number to be written to `buf`. @@ -2304,8 +2305,8 @@ added: v0.5.0 changes: - version: v10.0.0 pr-url: https://github.com/nodejs/node/pull/18395 - description: Removed noAssert and no implicit coercion of the offset to - uint32 anymore. + description: Removed `noAssert` and no implicit coercion of the offset + to `uint32` anymore. --> * `value` {integer} Number to be written to `buf`. @@ -2336,8 +2337,8 @@ added: v0.5.5 changes: - version: v10.0.0 pr-url: https://github.com/nodejs/node/pull/18395 - description: Removed noAssert and no implicit coercion of the offset to - uint32 anymore. + description: Removed `noAssert` and no implicit coercion of the offset + to `uint32` anymore. --> * `value` {integer} Number to be written to `buf`. @@ -2373,8 +2374,8 @@ added: v0.5.5 changes: - version: v10.0.0 pr-url: https://github.com/nodejs/node/pull/18395 - description: Removed noAssert and no implicit coercion of the offset to - uint32 anymore. + description: Removed `noAssert` and no implicit coercion of the offset + to `uint32` anymore. --> * `value` {integer} Number to be written to `buf`. @@ -2408,8 +2409,8 @@ added: v0.5.5 changes: - version: v10.0.0 pr-url: https://github.com/nodejs/node/pull/18395 - description: Removed noAssert and no implicit coercion of the offset and - byteLength to uint32 anymore. + description: Removed `noAssert` and no implicit coercion of the offset + and `byteLength` to `uint32` anymore. --> * `value` {integer} Number to be written to `buf`. diff --git a/doc/api/child_process.md b/doc/api/child_process.md index 47d68928e46ab2..1fc2855e4f65f5 100644 --- a/doc/api/child_process.md +++ b/doc/api/child_process.md @@ -211,7 +211,7 @@ Unlike the exec(3) POSIX system call, `child_process.exec()` does not replace the existing process and uses a shell to execute the command. If this method is invoked as its [`util.promisify()`][]ed version, it returns -a Promise for an object with `stdout` and `stderr` properties. In case of an +a `Promise` for an `Object` with `stdout` and `stderr` properties. In case of an error (including any error resulting in an exit code other than 0), a rejected promise is returned, with the same `error` object given in the callback, but with an additional two properties `stdout` and `stderr`. @@ -290,7 +290,7 @@ stderr output. If `encoding` is `'buffer'`, or an unrecognized character encoding, `Buffer` objects will be passed to the callback instead. If this method is invoked as its [`util.promisify()`][]ed version, it returns -a Promise for an object with `stdout` and `stderr` properties. In case of an +a `Promise` for an `Object` with `stdout` and `stderr` properties. In case of an error (including any error resulting in an exit code other than 0), a rejected promise is returned, with the same `error` object given in the callback, but with an additional two properties `stdout` and `stderr`. diff --git a/doc/api/cli.md b/doc/api/cli.md index 5bc673f5975d6f..6d055d9d03a6dd 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -101,25 +101,25 @@ Specify ICU data load path. (Overrides `NODE_ICU_DATA`.) added: v7.6.0 --> -Activate inspector on host:port and break at start of user script. -Default host:port is 127.0.0.1:9229. +Activate inspector on `host:port` and break at start of user script. +Default `host:port` is `127.0.0.1:9229`. ### `--inspect-port=[host:]port` -Set the host:port to be used when the inspector is activated. +Set the `host:port` to be used when the inspector is activated. Useful when activating the inspector by sending the `SIGUSR1` signal. -Default host is 127.0.0.1. +Default host is `127.0.0.1`. ### `--inspect[=[host:]port]` -Activate inspector on host:port. Default is 127.0.0.1:9229. +Activate inspector on `host:port`. Default is `127.0.0.1:9229`. V8 inspector integration allows tools such as Chrome DevTools and IDEs to debug and profile Node.js instances. The tools attach to Node.js instances via a @@ -461,7 +461,7 @@ options property is explicitly specified for a TLS or HTTPS client or server. added: v0.11.15 --> -Data path for ICU (Intl object) data. Will extend linked-in data when compiled +Data path for ICU (`Intl` object) data. Will extend linked-in data when compiled with small-icu support. ### `NODE_NO_WARNINGS=1` diff --git a/doc/api/cluster.md b/doc/api/cluster.md index 7c0baa36ff5491..b420645bb4dcc4 100644 --- a/doc/api/cluster.md +++ b/doc/api/cluster.md @@ -117,7 +117,7 @@ also be used for other use cases requiring worker processes. added: v0.7.0 --> -A Worker object contains all public information and method about a worker. +A `Worker` object contains all public information and method about a worker. In the master it can be obtained using `cluster.workers`. In a worker it can be obtained using `cluster.worker`. @@ -497,7 +497,7 @@ cluster.on('exit', (worker, code, signal) => { }); ``` -See [child_process event: `'exit'`][]. +See [`child_process` event: `'exit'`][]. ## Event: 'fork' -If domains are in use, then all **new** EventEmitter objects (including +If domains are in use, then all **new** `EventEmitter` objects (including Stream objects, requests, responses, etc.) will be implicitly bound to the active domain at the time of their creation. Additionally, callbacks passed to lowlevel event loop requests (such as -to fs.open, or other callback-taking methods) will automatically be +to `fs.open()`, or other callback-taking methods) will automatically be bound to the active domain. If they throw, then the domain will catch the error. -In order to prevent excessive memory usage, Domain objects themselves +In order to prevent excessive memory usage, `Domain` objects themselves are not implicitly added as children of the active domain. If they were, then it would be too easy to prevent request and response objects from being properly garbage collected. -To nest Domain objects as children of a parent Domain they must be explicitly -added. +To nest `Domain` objects as children of a parent `Domain` they must be +explicitly added. Implicit binding routes thrown errors and `'error'` events to the -Domain's `'error'` event, but does not register the EventEmitter on the -Domain. +`Domain`'s `'error'` event, but does not register the `EventEmitter` on the +`Domain`. Implicit binding only takes care of thrown errors and `'error'` events. ## Explicit Binding @@ -271,14 +271,12 @@ serverDomain.run(() => { * Returns: {Domain} -Returns a new Domain object. - ## Class: Domain -The Domain class encapsulates the functionality of routing errors and -uncaught exceptions to the active Domain object. +The `Domain` class encapsulates the functionality of routing errors and +uncaught exceptions to the active `Domain` object. -Domain is a child class of [`EventEmitter`][]. To handle the errors that it +`Domain` is a child class of [`EventEmitter`][]. To handle the errors that it catches, listen to its `'error'` event. ### domain.members @@ -301,7 +299,7 @@ This also works with timers that are returned from [`setInterval()`][] and [`setTimeout()`][]. If their callback function throws, it will be caught by the domain `'error'` handler. -If the Timer or EventEmitter was already bound to a domain, it is removed +If the Timer or `EventEmitter` was already bound to a domain, it is removed from that one, and bound to this one instead. ### domain.bind(callback) @@ -444,7 +442,7 @@ than crashing the program. ## Domains and Promises As of Node.js 8.0.0, the handlers of Promises are run inside the domain in -which the call to `.then` or `.catch` itself was made: +which the call to `.then()` or `.catch()` itself was made: ```js const d1 = domain.create(); @@ -481,7 +479,7 @@ d2.run(() => { ``` Note that domains will not interfere with the error handling mechanisms for -Promises, i.e. no `'error'` event will be emitted for unhandled Promise +Promises, i.e. no `'error'` event will be emitted for unhandled `Promise` rejections. [`Error`]: errors.html#errors_class_error diff --git a/doc/api/errors.md b/doc/api/errors.md index b434dc3c610f8a..a2489c6ac2e7e7 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -18,7 +18,7 @@ errors: as attempting to open a file that does not exist, attempting to send data over a closed socket, etc; - And User-specified errors triggered by application code. -- Assertion Errors are a special class of error that can be triggered whenever +- `AssertionError`s are a special class of error that can be triggered whenever Node.js detects an exceptional logic violation that should never occur. These are raised typically by the `assert` module. @@ -32,7 +32,7 @@ to provide *at least* the properties available on that class. Node.js supports several mechanisms for propagating and handling errors that occur while an application is running. How these errors are reported and -handled depends entirely on the type of Error and the style of the API that is +handled depends entirely on the type of `Error` and the style of the API that is called. All JavaScript errors are handled as exceptions that *immediately* generate @@ -137,7 +137,7 @@ pattern referred to as an _error-first callback_ (sometimes referred to as a _Node.js style callback_). With this pattern, a callback function is passed to the method as an argument. When the operation either completes or an error is raised, the callback function is called with -the Error object (if any) passed as the first argument. If no error was +the `Error` object (if any) passed as the first argument. If no error was raised, the first argument will be passed as `null`. ```js @@ -422,7 +422,7 @@ they may only be caught by other contexts. A subclass of `Error` that indicates that a provided argument is not an allowable type. For example, passing a function to a parameter which expects a -string would be considered a TypeError. +string would be considered a `TypeError`. ```js require('url').parse(() => { }); @@ -440,7 +440,7 @@ A JavaScript exception is a value that is thrown as a result of an invalid operation or as the target of a `throw` statement. While it is not required that these values are instances of `Error` or classes which inherit from `Error`, all exceptions thrown by Node.js or the JavaScript runtime *will* be -instances of Error. +instances of `Error`. Some exceptions are *unrecoverable* at the JavaScript layer. Such exceptions will *always* cause the Node.js process to crash. Examples include `assert()` @@ -492,7 +492,7 @@ typically `E` followed by a sequence of capital letters. The `error.errno` property is a number or a string. The number is a **negative** value which corresponds to the error code defined -in [`libuv Error handling`]. See uv-errno.h header file +in [`libuv Error handling`]. See `uv-errno.h` header file (`deps/uv/include/uv-errno.h` in the Node.js source tree) for details. In case of a string, it is the same as `error.code`. @@ -1081,7 +1081,7 @@ An invalid or unsupported value was passed for a given argument. ### ERR_INVALID_ARRAY_LENGTH -An Array was not of the expected length or in a valid range. +An array was not of the expected length or in a valid range. ### ERR_INVALID_ASYNC_ID @@ -1516,7 +1516,7 @@ length. ### ERR_TLS_CERT_ALTNAME_INVALID While using TLS, the hostname/IP of the peer did not match any of the -subjectAltNames in its certificate. +`subjectAltNames` in its certificate. ### ERR_TLS_DH_PARAM_SIZE @@ -1570,12 +1570,12 @@ the `--without-v8-platform` flag. ### ERR_TRANSFORM_ALREADY_TRANSFORMING -A Transform stream finished while it was still transforming. +A `Transform` stream finished while it was still transforming. ### ERR_TRANSFORM_WITH_LENGTH_0 -A Transform stream finished with data still in the write buffer. +A `Transform` stream finished with data still in the write buffer. ### ERR_TTY_INIT_FAILED @@ -1645,7 +1645,7 @@ itself, although it is possible for user code to trigger it. ### ERR_V8BREAKITERATOR -The V8 BreakIterator API was used but the full ICU data set is not installed. +The V8 `BreakIterator` API was used but the full ICU data set is not installed. ### ERR_VALID_PERFORMANCE_ENTRY_TYPE diff --git a/doc/api/esm.md b/doc/api/esm.md index 4090e545fdb54b..a1e3cb149ab7d8 100644 --- a/doc/api/esm.md +++ b/doc/api/esm.md @@ -134,8 +134,8 @@ export async function resolve(specifier, } ``` -The parentURL is provided as `undefined` when performing main Node.js load -itself. +The `parentModuleURL` is provided as `undefined` when performing main Node.js +load itself. The default Node.js ES module resolution function is provided as a third argument to the resolver for easy compatibility workflows. diff --git a/doc/api/events.md b/doc/api/events.md index e5ae1e3fe7bf11..536a87d1b46e0f 100644 --- a/doc/api/events.md +++ b/doc/api/events.md @@ -8,7 +8,7 @@ Much of the Node.js core API is built around an idiomatic asynchronous event-driven architecture in which certain kinds of objects (called "emitters") -periodically emit named events that cause Function objects ("listeners") to be +periodically emit named events that cause `Function` objects ("listeners") to be called. For instance: a [`net.Server`][] object emits an event each time a peer @@ -167,7 +167,7 @@ The `EventEmitter` class is defined and exposed by the `events` module: const EventEmitter = require('events'); ``` -All EventEmitters emit the event `'newListener'` when new listeners are +All `EventEmitter`s emit the event `'newListener'` when new listeners are added and `'removeListener'` when existing listeners are removed. ### Event: 'newListener' @@ -314,7 +314,7 @@ added: v6.0.0 - Returns: {Array} Returns an array listing the events for which the emitter has registered -listeners. The values in the array will be strings or Symbols. +listeners. The values in the array will be strings or `Symbol`s. ```js const EventEmitter = require('events'); @@ -589,7 +589,7 @@ added: v0.3.5 - `n` {integer} - Returns: {EventEmitter} -By default EventEmitters will print a warning if more than `10` listeners are +By default `EventEmitter`s will print a warning if more than `10` listeners are added for a particular event. This is a useful default that helps finding memory leaks. Obviously, not all events should be limited to just 10 listeners. The `emitter.setMaxListeners()` method allows the limit to be modified for this diff --git a/doc/api/fs.md b/doc/api/fs.md index 6e3628c8fbb2a0..8ac0cf4833cc45 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -177,7 +177,7 @@ Using WHATWG [`URL`][] objects might introduce platform-specific behaviors. On Windows, `file:` URLs with a hostname convert to UNC paths, while `file:` URLs with drive letters convert to local absolute paths. `file:` URLs without a -hostname nor a drive letter will result in a throw : +hostname nor a drive letter will result in a throw: ```js // On Windows : @@ -1730,7 +1730,7 @@ fs.ftruncate(fd, 4, (err) => { ``` If the file previously was shorter than `len` bytes, it is extended, and the -extended part is filled with null bytes ('\0'). For example, +extended part is filled with null bytes (`'\0'`). For example, ```js console.log(fs.readFileSync('temp.txt', 'utf8')); @@ -1748,7 +1748,7 @@ fs.ftruncate(fd, 10, (err) => { // ('Node.js\0\0\0' in UTF8) ``` -The last three bytes are null bytes ('\0'), to compensate the over-truncation. +The last three bytes are null bytes (`'\0'`), to compensate the over-truncation. ## fs.ftruncateSync(fd[, len]) * `atime` {number|string|Date} -* `mtime` {number|string|Date}` +* `mtime` {number|string|Date} * Returns: {Promise} Change the file system timestamps of the object referenced by the `FileHandle` @@ -3878,7 +3878,7 @@ doTruncate().catch(console.error); ``` If the file previously was shorter than `len` bytes, it is extended, and the -extended part is filled with null bytes ('\0'). For example, +extended part is filled with null bytes (`'\0'`). For example, ```js console.log(fs.readFileSync('temp.txt', 'utf8')); @@ -3893,7 +3893,7 @@ async function doTruncate() { doTruncate().catch(console.error); ``` -The last three bytes are null bytes ('\0'), to compensate the over-truncation. +The last three bytes are null bytes (`'\0'`), to compensate the over-truncation. ### fsPromises.futimes(filehandle, atime, mtime) @@ -924,10 +924,7 @@ This method is identical to [`server.listen()`][] from [`net.Server`][]. added: v5.7.0 --> -* {boolean} - -A Boolean indicating whether or not the server is listening for -connections. +* {boolean} Indicates whether or not the server is listening for connections. ### server.maxHeadersCount - `options` {Object} - * `IncomingMessage` {http.IncomingMessage} Specifies the IncomingMessage class - to be used. Useful for extending the original `IncomingMessage`. + * `IncomingMessage` {http.IncomingMessage} Specifies the `IncomingMessage` + class to be used. Useful for extending the original `IncomingMessage`. **Default:** `IncomingMessage`. - * `ServerResponse` {http.ServerResponse} Specifies the ServerResponse class to - be used. Useful for extending the original `ServerResponse`. **Default:** + * `ServerResponse` {http.ServerResponse} Specifies the `ServerResponse` class + to be used. Useful for extending the original `ServerResponse`. **Default:** `ServerResponse`. - `requestListener` {Function} @@ -1868,8 +1865,8 @@ changes: v6 will be used. * `port` {number} Port of remote server. **Default:** `80`. * `localAddress` {string} Local interface to bind for network connections. - * `socketPath` {string} Unix Domain Socket (use one of host:port or - socketPath). + * `socketPath` {string} Unix Domain Socket (use one of `host:port` or + `socketPath`). * `method` {string} A string specifying the HTTP request method. **Default:** `'GET'`. * `path` {string} Request path. Should include query string if any. @@ -2072,7 +2069,7 @@ not abort the request or do anything besides add a `'timeout'` event. [`socket.setKeepAlive()`]: net.html#net_socket_setkeepalive_enable_initialdelay [`socket.setNoDelay()`]: net.html#net_socket_setnodelay_nodelay [`socket.setTimeout()`]: net.html#net_socket_settimeout_timeout_callback +[`socket.unref()`]: net.html#net_socket_unref [`url.parse()`]: url.html#url_url_parse_urlstring_parsequerystring_slashesdenotehost [Readable Stream]: stream.html#stream_class_stream_readable [Writable Stream]: stream.html#stream_class_stream_writable -[socket.unref()]: net.html#net_socket_unref diff --git a/doc/api/http2.md b/doc/api/http2.md index b3aac4741eeeca..566cdc065e171d 100644 --- a/doc/api/http2.md +++ b/doc/api/http2.md @@ -108,7 +108,7 @@ have occasion to work with the `Http2Session` object directly, with most actions typically taken through interactions with either the `Http2Server` or `Http2Stream` objects. -#### Http2Session and Sockets +#### `Http2Session` and Sockets Every `Http2Session` instance is associated with exactly one [`net.Socket`][] or [`tls.TLSSocket`][] when it is created. When either the `Socket` or the @@ -410,7 +410,7 @@ added: v9.4.0 * {string[]|undefined} If the `Http2Session` is connected to a `TLSSocket`, the `originSet` property -will return an Array of origins for which the `Http2Session` may be +will return an `Array` of origins for which the `Http2Session` may be considered authoritative. #### http2session.pendingSettingsAck @@ -500,12 +500,12 @@ added: v8.4.0 * {net.Socket|tls.TLSSocket} -Returns a Proxy object that acts as a `net.Socket` (or `tls.TLSSocket`) but +Returns a `Proxy` object that acts as a `net.Socket` (or `tls.TLSSocket`) but limits available methods to ones safe to use with HTTP/2. `destroy`, `emit`, `end`, `pause`, `read`, `resume`, and `write` will throw an error with code `ERR_HTTP2_NO_SOCKET_MANIPULATION`. See -[Http2Session and Sockets][] for more information. +[`Http2Session` and Sockets][] for more information. `setTimeout` method will be called on this `Http2Session`. @@ -592,8 +592,9 @@ added: v9.4.0 * `alt` {string} A description of the alternative service configuration as defined by [RFC 7838][]. * `originOrStream` {number|string|URL|Object} Either a URL string specifying - the origin (or an Object with an `origin` property) or the numeric identifier - of an active `Http2Stream` as given by the `http2stream.id` property. + the origin (or an `Object` with an `origin` property) or the numeric + identifier of an active `Http2Stream` as given by the `http2stream.id` + property. Submits an `ALTSVC` frame (as defined by [RFC 7838][]) to the connected client. @@ -1041,7 +1042,7 @@ Provides miscellaneous information about the current state of the * `localWindowSize` {number} The number of bytes the connected peer may send for this `Http2Stream` without receiving a `WINDOW_UPDATE`. * `state` {number} A flag indicating the low-level current state of the - `Http2Stream` as determined by nghttp2. + `Http2Stream` as determined by `nghttp2`. * `localClose` {number} `true` if this `Http2Stream` has been closed locally. * `remoteClose` {number} `true` if this `Http2Stream` has been closed remotely. @@ -1140,7 +1141,7 @@ added: v8.4.0 The `'response'` event is emitted when a response `HEADERS` frame has been received for this stream from the connected HTTP/2 server. The listener is -invoked with two arguments: an Object containing the received +invoked with two arguments: an `Object` containing the received [HTTP/2 Headers Object][], and flags associated with the headers. ```js @@ -1180,7 +1181,7 @@ added: v8.4.0 * {boolean} -Boolean (read-only). True if headers were sent, false otherwise. +True if headers were sent, false otherwise (read-only). #### http2stream.pushAllowed -* {Object} Module object +* {module} The module that first required this one. diff --git a/doc/api/n-api.md b/doc/api/n-api.md index fcbd4decb3538a..3ba902f1df5e57 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -43,7 +43,7 @@ part of N-API, nor will they be maintained as part of Node.js. One such example is: [node-api](https://github.com/nodejs/node-api). In order to use the N-API functions, include the file -[node_api.h](https://github.com/nodejs/node/blob/master/src/node_api.h) +[`node_api.h`](https://github.com/nodejs/node/blob/master/src/node_api.h) which is located in the src directory in the node development tree: ```C @@ -434,7 +434,7 @@ NODE_EXTERN napi_status napi_create_error(napi_env env, ``` - `[in] env`: The environment that the API is invoked under. - `[in] code`: Optional `napi_value` with the string for the error code to - be associated with the error. +be associated with the error. - `[in] msg`: `napi_value` that references a JavaScript `String` to be used as the message for the `Error`. - `[out] result`: `napi_value` representing the error created. @@ -455,7 +455,7 @@ NODE_EXTERN napi_status napi_create_type_error(napi_env env, ``` - `[in] env`: The environment that the API is invoked under. - `[in] code`: Optional `napi_value` with the string for the error code to - be associated with the error. +be associated with the error. - `[in] msg`: `napi_value` that references a JavaScript `String` to be used as the message for the `Error`. - `[out] result`: `napi_value` representing the error created. @@ -476,7 +476,7 @@ NODE_EXTERN napi_status napi_create_range_error(napi_env env, ``` - `[in] env`: The environment that the API is invoked under. - `[in] code`: Optional `napi_value` with the string for the error code to - be associated with the error. +be associated with the error. - `[in] msg`: `napi_value` that references a JavaScript `String` to be used as the message for the `Error`. - `[out] result`: `napi_value` representing the error created. @@ -1275,7 +1275,7 @@ This API allocates a `node::Buffer` object and initializes it with data backed by the passed in buffer. While this is still a fully-supported data structure, in most cases using a `TypedArray` will suffice. -For Node.js >=4 `Buffers` are Uint8Arrays. +For Node.js >=4 `Buffers` are `Uint8Array`s. #### napi_create_function -A Boolean indicating whether or not the server is listening for -connections. +* {boolean} Indicates whether or not the server is listening for connections. ### server.maxConnections @@ -234,7 +234,7 @@ process.on('unhandledRejection', (reason, p) => { somePromise.then((res) => { return reportToUser(JSON.pasre(res)); // note the typo (`pasre`) -}); // no `.catch` or `.then` +}); // no `.catch()` or `.then()` ``` The following will also trigger the `'unhandledRejection'` event to be @@ -524,7 +524,7 @@ added: v0.7.7 * {Object} -The `process.config` property returns an Object containing the JavaScript +The `process.config` property returns an `Object` containing the JavaScript representation of the configure options used to compile the current Node.js executable. This is the same as the `config.gypi` file that was produced when running the `./configure` script. @@ -699,10 +699,10 @@ added: v8.0.0 * `warning` {string|Error} The warning to emit. * `options` {Object} - * `type` {string} When `warning` is a String, `type` is the name to use + * `type` {string} When `warning` is a `String`, `type` is the name to use for the *type* of warning being emitted. **Default:** `'Warning'`. * `code` {string} A unique identifier for the warning instance being emitted. - * `ctor` {Function} When `warning` is a String, `ctor` is an optional + * `ctor` {Function} When `warning` is a `String`, `ctor` is an optional function used to limit the generated stack trace. **Default:** `process.emitWarning`. * `detail` {string} Additional text to include with the error. @@ -744,10 +744,10 @@ added: v6.0.0 --> * `warning` {string|Error} The warning to emit. -* `type` {string} When `warning` is a String, `type` is the name to use +* `type` {string} When `warning` is a `String`, `type` is the name to use for the *type* of warning being emitted. **Default:** `'Warning'`. * `code` {string} A unique identifier for the warning instance being emitted. -* `ctor` {Function} When `warning` is a String, `ctor` is an optional +* `ctor` {Function} When `warning` is a `String`, `ctor` is an optional function used to limit the generated stack trace. **Default:** `process.emitWarning`. @@ -1151,12 +1151,12 @@ added: v0.7.6 * Returns: {integer[]} The `process.hrtime()` method returns the current high-resolution real time -in a `[seconds, nanoseconds]` tuple Array, where `nanoseconds` is the +in a `[seconds, nanoseconds]` tuple `Array`, where `nanoseconds` is the remaining part of the real time that can't be represented in second precision. `time` is an optional parameter that must be the result of a previous `process.hrtime()` call to diff with the current time. If the parameter -passed in is not a tuple Array, a `TypeError` will be thrown. Passing in a +passed in is not a tuple `Array`, a `TypeError` will be thrown. Passing in a user-defined array instead of the result of a previous call to `process.hrtime()` will lead to undefined behavior. @@ -1401,7 +1401,7 @@ function definitelyAsync(arg, cb) { The next tick queue is completely drained on each pass of the event loop **before** additional I/O is processed. As a result, recursively setting -nextTick callbacks will block any I/O from happening, just like a +`nextTick()` callbacks will block any I/O from happening, just like a `while(true);` loop. ## process.noDeprecation @@ -1482,8 +1482,8 @@ changes: * {Object} -The `process.release` property returns an Object containing metadata related to -the current release, including URLs for the source tarball and headers-only +The `process.release` property returns an `Object` containing metadata related +to the current release, including URLs for the source tarball and headers-only tarball. `process.release` contains the following properties: @@ -1741,7 +1741,7 @@ The `process.stdout` property returns a stream connected to stream) unless fd `1` refers to a file, in which case it is a [Writable][] stream. -For example, to copy process.stdin to process.stdout: +For example, to copy `process.stdin` to `process.stdout`: ```js process.stdin.pipe(process.stdout); @@ -1961,7 +1961,7 @@ cases: * `7` **Internal Exception Handler Run-Time Failure** - There was an uncaught exception, and the internal fatal exception handler function itself threw an error while attempting to handle it. This - can happen, for example, if a [`'uncaughtException'`][] or + can happen, for example, if an [`'uncaughtException'`][] or `domain.on('error')` handler throws an error. * `8` - Unused. In previous versions of Node.js, exit code 8 sometimes indicated an uncaught exception. diff --git a/doc/api/readline.md b/doc/api/readline.md index ead469e97c9f27..a2a4adf3093a9a 100644 --- a/doc/api/readline.md +++ b/doc/api/readline.md @@ -303,7 +303,7 @@ rl.write('Delete this!'); rl.write(null, { ctrl: true, name: 'u' }); ``` -The `rl.write()` method will write the data to the `readline` Interface's +The `rl.write()` method will write the data to the `readline` `Interface`'s `input` *as if it were provided by the user*. ## readline.clearLine(stream, dir) @@ -401,9 +401,9 @@ a `'resize'` event on the `output` if or when the columns ever change ### Use of the `completer` Function The `completer` function takes the current line entered by the user -as an argument, and returns an Array with 2 entries: +as an argument, and returns an `Array` with 2 entries: -* An Array with matching entries for the completion. +* An `Array` with matching entries for the completion. * The substring that was used for the matching. For instance: `[[substr1, substr2, ...], originalsubstring]`. @@ -447,7 +447,7 @@ added: v0.7.7 * `interface` {readline.Interface} The `readline.emitKeypressEvents()` method causes the given [Readable][] -`stream` to begin emitting `'keypress'` events corresponding to received input. +stream to begin emitting `'keypress'` events corresponding to received input. Optionally, `interface` specifies a `readline.Interface` instance for which autocompletion is disabled when copy-pasted input is detected. diff --git a/doc/api/repl.md b/doc/api/repl.md index 995dabaa5d863d..b751472049a672 100644 --- a/doc/api/repl.md +++ b/doc/api/repl.md @@ -63,7 +63,7 @@ The following key combinations in the REPL have these special effects: When pressed twice on a blank line, has the same effect as the `.exit` command. * `-D` - Has the same effect as the `.exit` command. -* `` - When pressed on a blank line, displays global and local(scope) +* `` - When pressed on a blank line, displays global and local (scope) variables. When pressed while entering other input, displays relevant autocompletion options. @@ -251,7 +251,7 @@ function isRecoverableError(error) { ### Customizing REPL Output By default, `repl.REPLServer` instances format output using the -[`util.inspect()`][] method before writing the output to the provided Writable +[`util.inspect()`][] method before writing the output to the provided `Writable` stream (`process.stdout` by default). The `useColors` boolean option can be specified at construction to instruct the default writer to use ANSI style codes to colorize the output from the `util.inspect()` method. @@ -356,7 +356,7 @@ added: v0.3.0 The `replServer.defineCommand()` method is used to add new `.`-prefixed commands to the REPL instance. Such commands are invoked by typing a `.` followed by the -`keyword`. The `cmd` is either a Function or an object with the following +`keyword`. The `cmd` is either a `Function` or an `Object` with the following properties: * `help` {string} Help text to be displayed when `.help` is entered (Optional). @@ -443,7 +443,7 @@ added: v0.1.91 changes: - version: v10.0.0 pr-url: https://github.com/nodejs/node/pull/v10.0.0 - description: The `REPL_MAGIC_MODE` replMode was removed. + description: The `REPL_MAGIC_MODE` `replMode` was removed. - version: v5.8.0 pr-url: https://github.com/nodejs/node/pull/5388 description: The `options` parameter is optional now. @@ -452,10 +452,10 @@ changes: * `options` {Object|string} * `prompt` {string} The input prompt to display. **Default:** `'> '` (with a trailing space). - * `input` {stream.Readable} The Readable stream from which REPL input will be - read. **Default:** `process.stdin`. - * `output` {stream.Writable} The Writable stream to which REPL output will be - written. **Default:** `process.stdout`. + * `input` {stream.Readable} The `Readable` stream from which REPL input will + be read. **Default:** `process.stdin`. + * `output` {stream.Writable} The `Writable` stream to which REPL output will + be written. **Default:** `process.stdout`. * `terminal` {boolean} If `true`, specifies that the `output` should be treated as a TTY terminal, and have ANSI/VT100 escape codes written to it. **Default:** checking the value of the `isTTY` property on the `output` diff --git a/doc/api/stream.md b/doc/api/stream.md index 8af12d12bf07bd..483aec1b700fb6 100644 --- a/doc/api/stream.md +++ b/doc/api/stream.md @@ -37,13 +37,13 @@ the elements of the API that are required to *implement* new types of streams. There are four fundamental stream types within Node.js: -* [Readable][] - streams from which data can be read (for example +* [`Readable`][] - streams from which data can be read (for example [`fs.createReadStream()`][]). -* [Writable][] - streams to which data can be written (for example +* [`Writable`][] - streams to which data can be written (for example [`fs.createWriteStream()`][]). -* [Duplex][] - streams that are both Readable and Writable (for example +* [`Duplex`][] - streams that are both `Readable` and `Writable` (for example [`net.Socket`][]). -* [Transform][] - Duplex streams that can modify or transform the data as it +* [`Transform`][] - `Duplex` streams that can modify or transform the data as it is written and read (for example [`zlib.createDeflate()`][]). Additionally this module includes the utility functions [pipeline][] and @@ -65,7 +65,7 @@ object mode is not safe. -Both [Writable][] and [Readable][] streams will store data in an internal +Both [`Writable`][] and [`Readable`][] streams will store data in an internal buffer that can be retrieved using `writable.writableBuffer` or `readable.readableBuffer`, respectively. @@ -74,7 +74,7 @@ passed into the streams constructor. For normal streams, the `highWaterMark` option specifies a [total number of bytes][hwm-gotcha]. For streams operating in object mode, the `highWaterMark` specifies a total number of objects. -Data is buffered in Readable streams when the implementation calls +Data is buffered in `Readable` streams when the implementation calls [`stream.push(chunk)`][stream-push]. If the consumer of the Stream does not call [`stream.read()`][stream-read], the data will sit in the internal queue until it is consumed. @@ -85,7 +85,7 @@ underlying resource until the data currently buffered can be consumed (that is, the stream will stop calling the internal `readable._read()` method that is used to fill the read buffer). -Data is buffered in Writable streams when the +Data is buffered in `Writable` streams when the [`writable.write(chunk)`][stream-write] method is called repeatedly. While the total size of the internal write buffer is below the threshold set by `highWaterMark`, calls to `writable.write()` will return `true`. Once @@ -96,15 +96,15 @@ A key goal of the `stream` API, particularly the [`stream.pipe()`] method, is to limit the buffering of data to acceptable levels such that sources and destinations of differing speeds will not overwhelm the available memory. -Because [Duplex][] and [Transform][] streams are both Readable and Writable, -each maintain *two* separate internal buffers used for reading and writing, -allowing each side to operate independently of the other while maintaining an -appropriate and efficient flow of data. For example, [`net.Socket`][] instances -are [Duplex][] streams whose Readable side allows consumption of data received -*from* the socket and whose Writable side allows writing data *to* the socket. -Because data may be written to the socket at a faster or slower rate than data -is received, it is important for each side to operate (and buffer) independently -of the other. +Because [`Duplex`][] and [`Transform`][] streams are both `Readable` and +`Writable`, each maintain *two* separate internal buffers used for reading and +writing, allowing each side to operate independently of the other while +maintaining an appropriate and efficient flow of data. For example, +[`net.Socket`][] instances are [`Duplex`][] streams whose `Readable` side allows +consumption of data received *from* the socket and whose `Writable` side allows +writing data *to* the socket. Because data may be written to the socket at a +faster or slower rate than data is received, it is important for each side to +operate (and buffer) independently of the other. ## API for Stream Consumers @@ -156,17 +156,18 @@ server.listen(1337); // error: Unexpected token o in JSON at position 1 ``` -[Writable][] streams (such as `res` in the example) expose methods such as +[`Writable`][] streams (such as `res` in the example) expose methods such as `write()` and `end()` that are used to write data onto the stream. -[Readable][] streams use the [`EventEmitter`][] API for notifying application +[`Readable`][] streams use the [`EventEmitter`][] API for notifying application code when data is available to be read off the stream. That available data can be read from the stream in multiple ways. -Both [Writable][] and [Readable][] streams use the [`EventEmitter`][] API in +Both [`Writable`][] and [`Readable`][] streams use the [`EventEmitter`][] API in various ways to communicate the current state of the stream. -[Duplex][] and [Transform][] streams are both [Writable][] and [Readable][]. +[`Duplex`][] and [`Transform`][] streams are both [`Writable`][] and +[`Readable`][]. Applications that are either writing data to or consuming data from a stream are not required to implement the stream interfaces directly and will generally @@ -180,7 +181,7 @@ section [API for Stream Implementers][]. Writable streams are an abstraction for a *destination* to which data is written. -Examples of [Writable][] streams include: +Examples of [`Writable`][] streams include: * [HTTP requests, on the client][] * [HTTP responses, on the server][] @@ -191,14 +192,14 @@ Examples of [Writable][] streams include: * [child process stdin][] * [`process.stdout`][], [`process.stderr`][] -Some of these examples are actually [Duplex][] streams that implement the -[Writable][] interface. +Some of these examples are actually [`Duplex`][] streams that implement the +[`Writable`][] interface. -All [Writable][] streams implement the interface defined by the +All [`Writable`][] streams implement the interface defined by the `stream.Writable` class. -While specific instances of [Writable][] streams may differ in various ways, -all Writable streams follow the same fundamental usage pattern as illustrated +While specific instances of [`Writable`][] streams may differ in various ways, +all `Writable` streams follow the same fundamental usage pattern as illustrated in the example below: ```js @@ -224,7 +225,7 @@ The `'close'` event is emitted when the stream and any of its underlying resources (a file descriptor, for example) have been closed. The event indicates that no more events will be emitted, and no further computation will occur. -Not all Writable streams will emit the `'close'` event. +Not all `Writable` streams will emit the `'close'` event. ##### Event: 'drain' -Duplex streams are streams that implement both the [Readable][] and -[Writable][] interfaces. +Duplex streams are streams that implement both the [`Readable`][] and +[`Writable`][] interfaces. -Examples of Duplex streams include: +Examples of `Duplex` streams include: * [TCP sockets][] * [zlib streams][zlib] @@ -1270,11 +1272,11 @@ added: v0.9.4 -Transform streams are [Duplex][] streams where the output is in some way -related to the input. Like all [Duplex][] streams, Transform streams -implement both the [Readable][] and [Writable][] interfaces. +Transform streams are [`Duplex`][] streams where the output is in some way +related to the input. Like all [`Duplex`][] streams, `Transform` streams +implement both the [`Readable`][] and [`Writable`][] interfaces. -Examples of Transform streams include: +Examples of `Transform` streams include: * [zlib streams][zlib] * [crypto streams][crypto] @@ -1436,7 +1438,7 @@ on the type of stream being created, as detailed in the chart below:

Reading only

-

[Readable](#stream_class_stream_readable)

+

[`Readable`](#stream_class_stream_readable)

[_read][stream-_read]

@@ -1447,7 +1449,7 @@ on the type of stream being created, as detailed in the chart below:

Writing only

-

[Writable](#stream_class_stream_writable)

+

[`Writable`](#stream_class_stream_writable)

@@ -1462,7 +1464,7 @@ on the type of stream being created, as detailed in the chart below:

Reading and writing

-

[Duplex](#stream_class_stream_duplex)

+

[`Duplex`](#stream_class_stream_duplex)

@@ -1477,7 +1479,7 @@ on the type of stream being created, as detailed in the chart below:

Operate on written data, then read the result

-

[Transform](#stream_class_stream_transform)

+

[`Transform`](#stream_class_stream_transform)

@@ -1516,9 +1518,9 @@ const myWritable = new Writable({ ### Implementing a Writable Stream -The `stream.Writable` class is extended to implement a [Writable][] stream. +The `stream.Writable` class is extended to implement a [`Writable`][] stream. -Custom Writable streams *must* call the `new stream.Writable([options])` +Custom `Writable` streams *must* call the `new stream.Writable([options])` constructor and implement the `writable._write()` method. The `writable._writev()` method *may* also be implemented. @@ -1536,7 +1538,7 @@ changes: [`stream.write()`][stream-write] starts returning `false`. **Default:** `16384` (16kb), or `16` for `objectMode` streams. * `decodeStrings` {boolean} Whether or not to decode strings into - Buffers before passing them to [`stream._write()`][stream-_write]. + `Buffer`s before passing them to [`stream._write()`][stream-_write]. **Default:** `true`. * `objectMode` {boolean} Whether or not the [`stream.write(anyObj)`][stream-write] is a valid operation. When set, @@ -1606,16 +1608,16 @@ const myWritable = new Writable({ * `callback` {Function} Call this function (optionally with an error argument) when processing is complete for the supplied chunk. -All Writable stream implementations must provide a +All `Writable` stream implementations must provide a [`writable._write()`][stream-_write] method to send data to the underlying resource. -[Transform][] streams provide their own implementation of the +[`Transform`][] streams provide their own implementation of the [`writable._write()`][stream-_write]. This function MUST NOT be called by application code directly. It should be -implemented by child classes, and called by the internal Writable class methods -only. +implemented by child classes, and called by the internal `Writable` class +methods only. The `callback` method must be called to signal either that the write completed successfully or failed with an error. The first argument passed to the @@ -1647,8 +1649,8 @@ user programs. argument) to be invoked when processing is complete for the supplied chunks. This function MUST NOT be called by application code directly. It should be -implemented by child classes, and called by the internal Writable class methods -only. +implemented by child classes, and called by the internal `Writable` class +methods only. The `writable._writev()` method may be implemented in addition to `writable._write()` in stream implementations that are capable of processing @@ -1680,7 +1682,7 @@ added: v8.0.0 argument) when finished writing any remaining data. The `_final()` method **must not** be called directly. It may be implemented -by child classes, and if so, will be called by the internal Writable +by child classes, and if so, will be called by the internal `Writable` class methods only. This optional function will be called before the stream closes, delaying the @@ -1692,13 +1694,13 @@ or write buffered data before a stream ends. It is recommended that errors occurring during the processing of the `writable._write()` and `writable._writev()` methods are reported by invoking the callback and passing the error as the first argument. This will cause an -`'error'` event to be emitted by the Writable. Throwing an Error from within +`'error'` event to be emitted by the `Writable`. Throwing an `Error` from within `writable._write()` can result in unexpected and inconsistent behavior depending on how the stream is being used. Using the callback ensures consistent and predictable handling of errors. -If a Readable stream pipes into a Writable stream when Writable emits an -error, the Readable stream will be unpiped. +If a `Readable` stream pipes into a `Writable` stream when `Writable` emits an +error, the `Readable` stream will be unpiped. ```js const { Writable } = require('stream'); @@ -1717,9 +1719,9 @@ const myWritable = new Writable({ #### An Example Writable Stream The following illustrates a rather simplistic (and somewhat pointless) custom -Writable stream implementation. While this specific Writable stream instance +`Writable` stream implementation. While this specific `Writable` stream instance is not of any real particular usefulness, the example illustrates each of the -required elements of a custom [Writable][] stream instance: +required elements of a custom [`Writable`][] stream instance: ```js const { Writable } = require('stream'); @@ -1745,7 +1747,7 @@ class MyWritable extends Writable { Decoding buffers is a common task, for instance, when using transformers whose input is a string. This is not a trivial process when using multi-byte characters encoding, such as UTF-8. The following example shows how to decode -multi-byte strings using `StringDecoder` and [Writable][]. +multi-byte strings using `StringDecoder` and [`Writable`][]. ```js const { Writable } = require('stream'); @@ -1782,9 +1784,9 @@ console.log(w.data); // currency: € ### Implementing a Readable Stream -The `stream.Readable` class is extended to implement a [Readable][] stream. +The `stream.Readable` class is extended to implement a [`Readable`][] stream. -Custom Readable streams *must* call the `new stream.Readable([options])` +Custom `Readable` streams *must* call the `new stream.Readable([options])` constructor and implement the `readable._read()` method. #### new stream.Readable([options]) @@ -1797,7 +1799,7 @@ constructor and implement the `readable._read()` method. strings using the specified encoding. **Default:** `null`. * `objectMode` {boolean} Whether this stream should behave as a stream of objects. Meaning that [`stream.read(n)`][stream-read] returns - a single value instead of a Buffer of size n. **Default:** `false`. + a single value instead of a `Buffer` of size `n`. **Default:** `false`. * `read` {Function} Implementation for the [`stream._read()`][stream-_read] method. * `destroy` {Function} Implementation for the @@ -1847,16 +1849,16 @@ added: v0.9.4 changes: - version: v10.0.0 pr-url: https://github.com/nodejs/node/pull/17979 - description: call _read() only once per microtick + description: call `_read()` only once per microtick --> * `size` {number} Number of bytes to read asynchronously This function MUST NOT be called by application code directly. It should be -implemented by child classes, and called by the internal Readable class methods -only. +implemented by child classes, and called by the internal `Readable` class +methods only. -All Readable stream implementations must provide an implementation of the +All `Readable` stream implementations must provide an implementation of the `readable._read()` method to fetch data from the underlying resource. When `readable._read()` is called, if data is available from the resource, the @@ -1906,7 +1908,7 @@ changes: string, `Buffer` or `Uint8Array`. For object mode streams, `chunk` may be any JavaScript value. * `encoding` {string} Encoding of string chunks. Must be a valid - Buffer encoding, such as `'utf8'` or `'ascii'` + `Buffer` encoding, such as `'utf8'` or `'ascii'`. * Returns: {boolean} `true` if additional chunks of data may continued to be pushed; `false` otherwise. @@ -1915,18 +1917,18 @@ be added to the internal queue for users of the stream to consume. Passing `chunk` as `null` signals the end of the stream (EOF), after which no more data can be written. -When the Readable is operating in paused mode, the data added with +When the `Readable` is operating in paused mode, the data added with `readable.push()` can be read out by calling the [`readable.read()`][stream-read] method when the [`'readable'`][] event is emitted. -When the Readable is operating in flowing mode, the data added with +When the `Readable` is operating in flowing mode, the data added with `readable.push()` will be delivered by emitting a `'data'` event. The `readable.push()` method is designed to be as flexible as possible. For example, when wrapping a lower-level source that provides some form of pause/resume mechanism, and a data callback, the low-level source can be wrapped -by the custom Readable instance as illustrated in the following example: +by the custom `Readable` instance as illustrated in the following example: ```js // source is an object with readStop() and readStart() methods, @@ -1959,8 +1961,8 @@ class SourceWrapper extends Readable { } ``` -The `readable.push()` method is intended be called only by Readable -Implementers, and only from within the `readable._read()` method. +The `readable.push()` method is intended be called only by `Readable` +implementers, and only from within the `readable._read()` method. For streams not operating in object mode, if the `chunk` parameter of `readable.push()` is `undefined`, it will be treated as empty string or @@ -1970,7 +1972,7 @@ buffer. See [`readable.push('')`][] for more information. It is recommended that errors occurring during the processing of the `readable._read()` method are emitted using the `'error'` event rather than -being thrown. Throwing an Error from within `readable._read()` can result in +being thrown. Throwing an `Error` from within `readable._read()` can result in unexpected and inconsistent behavior depending on whether the stream is operating in flowing or paused mode. Using the `'error'` event ensures consistent and predictable handling of errors. @@ -1994,7 +1996,7 @@ const myReadable = new Readable({ -The following is a basic example of a Readable stream that emits the numerals +The following is a basic example of a `Readable` stream that emits the numerals from 1 to 1,000,000 in ascending order, and then ends. ```js @@ -2022,11 +2024,11 @@ class Counter extends Readable { ### Implementing a Duplex Stream -A [Duplex][] stream is one that implements both [Readable][] and [Writable][], -such as a TCP socket connection. +A [`Duplex`][] stream is one that implements both [`Readable`][] and +[`Writable`][], such as a TCP socket connection. Because JavaScript does not have support for multiple inheritance, the -`stream.Duplex` class is extended to implement a [Duplex][] stream (as opposed +`stream.Duplex` class is extended to implement a [`Duplex`][] stream (as opposed to extending the `stream.Readable` *and* `stream.Writable` classes). The `stream.Duplex` class prototypically inherits from `stream.Readable` and @@ -2034,7 +2036,7 @@ parasitically from `stream.Writable`, but `instanceof` will work properly for both base classes due to overriding [`Symbol.hasInstance`][] on `stream.Writable`. -Custom Duplex streams *must* call the `new stream.Duplex([options])` +Custom `Duplex` streams *must* call the `new stream.Duplex([options])` constructor and implement *both* the `readable._read()` and `writable._write()` methods. @@ -2047,7 +2049,7 @@ changes: are supported now. --> -* `options` {Object} Passed to both Writable and Readable +* `options` {Object} Passed to both `Writable` and `Readable` constructors. Also has the following fields: * `allowHalfOpen` {boolean} If set to `false`, then the stream will automatically end the writable side when the readable side ends. @@ -2103,13 +2105,13 @@ const myDuplex = new Duplex({ #### An Example Duplex Stream -The following illustrates a simple example of a Duplex stream that wraps a +The following illustrates a simple example of a `Duplex` stream that wraps a hypothetical lower-level source object to which data can be written, and from which data can be read, albeit using an API that is not compatible with Node.js streams. -The following illustrates a simple example of a Duplex stream that buffers -incoming written data via the [Writable][] interface that is read back out -via the [Readable][] interface. +The following illustrates a simple example of a `Duplex` stream that buffers +incoming written data via the [`Writable`][] interface that is read back out +via the [`Readable`][] interface. ```js const { Duplex } = require('stream'); @@ -2137,20 +2139,20 @@ class MyDuplex extends Duplex { } ``` -The most important aspect of a Duplex stream is that the Readable and Writable -sides operate independently of one another despite co-existing within a single -object instance. +The most important aspect of a `Duplex` stream is that the `Readable` and +`Writable` sides operate independently of one another despite co-existing within +a single object instance. #### Object Mode Duplex Streams -For Duplex streams, `objectMode` can be set exclusively for either the Readable -or Writable side using the `readableObjectMode` and `writableObjectMode` options -respectively. +For `Duplex` streams, `objectMode` can be set exclusively for either the +`Readable` or `Writable` side using the `readableObjectMode` and +`writableObjectMode` options respectively. -In the following example, for instance, a new Transform stream (which is a -type of [Duplex][] stream) is created that has an object mode Writable side +In the following example, for instance, a new `Transform` stream (which is a +type of [`Duplex`][] stream) is created that has an object mode `Writable` side that accepts JavaScript numbers that are converted to hexadecimal strings on -the Readable side. +the `Readable` side. ```js const { Transform } = require('stream'); @@ -2184,31 +2186,31 @@ myTransform.write(100); ### Implementing a Transform Stream -A [Transform][] stream is a [Duplex][] stream where the output is computed +A [`Transform`][] stream is a [`Duplex`][] stream where the output is computed in some way from the input. Examples include [zlib][] streams or [crypto][] streams that compress, encrypt, or decrypt data. There is no requirement that the output be the same size as the input, the same -number of chunks, or arrive at the same time. For example, a Hash stream will +number of chunks, or arrive at the same time. For example, a `Hash` stream will only ever have a single chunk of output which is provided when the input is ended. A `zlib` stream will produce output that is either much smaller or much larger than its input. -The `stream.Transform` class is extended to implement a [Transform][] stream. +The `stream.Transform` class is extended to implement a [`Transform`][] stream. The `stream.Transform` class prototypically inherits from `stream.Duplex` and implements its own versions of the `writable._write()` and `readable._read()` -methods. Custom Transform implementations *must* implement the +methods. Custom `Transform` implementations *must* implement the [`transform._transform()`][stream-_transform] method and *may* also implement the [`transform._flush()`][stream-_flush] method. -Care must be taken when using Transform streams in that data written to the -stream can cause the Writable side of the stream to become paused if the output -on the Readable side is not consumed. +Care must be taken when using `Transform` streams in that data written to the +stream can cause the `Writable` side of the stream to become paused if the +output on the `Readable` side is not consumed. #### new stream.Transform([options]) -* `options` {Object} Passed to both Writable and Readable +* `options` {Object} Passed to both `Writable` and `Readable` constructors. Also has the following fields: * `transform` {Function} Implementation for the [`stream._transform()`][stream-_transform] method. @@ -2267,8 +2269,8 @@ after all data has been output, which occurs after the callback in argument and data) to be called when remaining data has been flushed. This function MUST NOT be called by application code directly. It should be -implemented by child classes, and called by the internal Readable class methods -only. +implemented by child classes, and called by the internal `Readable` class +methods only. In some cases, a transform operation may need to emit an additional bit of data at the end of the stream. For example, a `zlib` compression stream will @@ -2276,10 +2278,10 @@ store an amount of internal state used to optimally compress the output. When the stream ends, however, that additional data needs to be flushed so that the compressed data will be complete. -Custom [Transform][] implementations *may* implement the `transform._flush()` +Custom [`Transform`][] implementations *may* implement the `transform._flush()` method. This will be called when there is no more written data to be consumed, but before the [`'end'`][] event is emitted signaling the end of the -[Readable][] stream. +[`Readable`][] stream. Within the `transform._flush()` implementation, the `readable.push()` method may be called zero or more times, as appropriate. The `callback` function must @@ -2302,10 +2304,10 @@ user programs. processed. This function MUST NOT be called by application code directly. It should be -implemented by child classes, and called by the internal Readable class methods -only. +implemented by child classes, and called by the internal `Readable` class +methods only. -All Transform stream implementations must provide a `_transform()` +All `Transform` stream implementations must provide a `_transform()` method to accept input and produce output. The `transform._transform()` implementation handles the bytes being written, computes an output, then passes that output off to the readable portion using the `readable.push()` method. @@ -2343,7 +2345,7 @@ called, either synchronously or asynchronously. #### Class: stream.PassThrough -The `stream.PassThrough` class is a trivial implementation of a [Transform][] +The `stream.PassThrough` class is a trivial implementation of a [`Transform`][] stream that simply passes the input bytes across to the output. Its purpose is primarily for examples and testing, but there are some use cases where `stream.PassThrough` is useful as a building block for novel sorts of streams. @@ -2356,7 +2358,7 @@ primarily for examples and testing, but there are some use cases where -In versions of Node.js prior to v0.10, the Readable stream interface was +In versions of Node.js prior to v0.10, the `Readable` stream interface was simpler, but also less powerful and less useful. * Rather than waiting for calls the [`stream.read()`][stream-read] method, @@ -2367,9 +2369,9 @@ simpler, but also less powerful and less useful. guaranteed. This meant that it was still necessary to be prepared to receive [`'data'`][] events *even when the stream was in a paused state*. -In Node.js v0.10, the [Readable][] class was added. For backwards compatibility -with older Node.js programs, Readable streams switch into "flowing mode" when a -[`'data'`][] event handler is added, or when the +In Node.js v0.10, the [`Readable`][] class was added. For backwards +compatibility with older Node.js programs, `Readable` streams switch into +"flowing mode" when a [`'data'`][] event handler is added, or when the [`stream.resume()`][stream-resume] method is called. The effect is that, even when not using the new [`stream.read()`][stream-read] method and [`'readable'`][] event, it is no longer necessary to worry about losing @@ -2416,8 +2418,8 @@ net.createServer((socket) => { }).listen(1337); ``` -In addition to new Readable streams switching into flowing mode, -pre-v0.10 style streams can be wrapped in a Readable class using the +In addition to new `Readable` streams switching into flowing mode, +pre-v0.10 style streams can be wrapped in a `Readable` class using the [`readable.wrap()`][`stream.wrap()`] method. ### `readable.read(0)` @@ -2433,7 +2435,7 @@ a low-level [`stream._read()`][stream-_read] call. While most applications will almost never need to do this, there are situations within Node.js where this is done, particularly in the -Readable stream class internals. +`Readable` stream class internals. ### `readable.push('')` @@ -2483,13 +2485,13 @@ contain multi-byte characters. [API for Stream Consumers]: #stream_api_for_stream_consumers [API for Stream Implementers]: #stream_api_for_stream_implementers [Compatibility]: #stream_compatibility_with_older_node_js_versions -[Duplex]: #stream_class_stream_duplex +[`Duplex`]: #stream_class_stream_duplex [HTTP requests, on the client]: http.html#http_class_http_clientrequest [HTTP responses, on the server]: http.html#http_class_http_serverresponse -[Readable]: #stream_class_stream_readable +[`Readable`]: #stream_class_stream_readable [TCP sockets]: net.html#net_class_net_socket -[Transform]: #stream_class_stream_transform -[Writable]: #stream_class_stream_writable +[`Transform`]: #stream_class_stream_transform +[`Writable`]: #stream_class_stream_writable [child process stdin]: child_process.html#child_process_subprocess_stdin [child process stdout and stderr]: child_process.html#child_process_subprocess_stdout [crypto]: crypto.html diff --git a/doc/api/tls.md b/doc/api/tls.md index bdda8bd7343873..e22286adb45ad3 100644 --- a/doc/api/tls.md +++ b/doc/api/tls.md @@ -422,8 +422,7 @@ added: v3.0.0 Updates the keys for encryption/decryption of the [TLS Session Tickets][]. The key's `Buffer` should be 48 bytes long. See `ticketKeys` option in -[tls.createServer](#tls_tls_createserver_options_secureconnectionlistener) for -more information on how it is used. +[`tls.createServer()`] for more information on how it is used. Changes to the ticket keys are effective only for future server connections. Existing or currently pending server connections will use the previous keys. @@ -582,7 +581,7 @@ an ephemeral key exchange in [Perfect Forward Secrecy][] on a client connection. It returns an empty object when the key exchange is not ephemeral. As this is only supported on a client socket; `null` is returned if called on a server socket. The supported types are `'DH'` and `'ECDH'`. The -`name` property is available only when type is 'ECDH'. +`name` property is available only when type is `'ECDH'`. For example: `{ type: 'ECDH', name: 'prime256v1', size: 256 }`. @@ -615,7 +614,7 @@ added: v0.11.4 Returns an object representing the peer's certificate. The returned object has some properties corresponding to the fields of the certificate. -If the full certificate chain was requested, each certificate will include a +If the full certificate chain was requested, each certificate will include an `issuerCertificate` property containing an object representing its issuer's certificate. @@ -637,7 +636,7 @@ For example: OU: 'Test TLS Certificate', CN: 'localhost' }, issuerCertificate: - { ... another certificate, possibly with a .issuerCertificate ... }, + { ... another certificate, possibly with an .issuerCertificate ... }, raw: < RAW DER buffer >, pubkey: < RAW DER buffer >, valid_from: 'Nov 11 09:52:22 2009 GMT', @@ -1016,7 +1015,7 @@ changes: - version: v7.3.0 pr-url: https://github.com/nodejs/node/pull/10294 description: If the `key` option is an array, individual entries do not - need a `passphrase` property anymore. Array entries can also + need a `passphrase` property anymore. `Array` entries can also just be `string`s or `Buffer`s now. - version: v5.2.0 pr-url: https://github.com/nodejs/node/pull/4099 @@ -1056,9 +1055,9 @@ changes: * `ca` {string|string[]|Buffer|Buffer[]} Optionally override the trusted CA certificates. Default is to trust the well-known CAs curated by Mozilla. Mozilla's CAs are completely replaced when CAs are explicitly specified - using this option. The value can be a string or Buffer, or an Array of - strings and/or Buffers. Any string or Buffer can contain multiple PEM CAs - concatenated together. The peer's certificate must be chainable to a CA + using this option. The value can be a string or `Buffer`, or an `Array` of + strings and/or `Buffer`s. Any string or `Buffer` can contain multiple PEM + CAs concatenated together. The peer's certificate must be chainable to a CA trusted by the server for the connection to be authenticated. When using certificates that are not chainable to a well-known CA, the certificate's CA must be explicitly specified as a trusted or the connection will fail to @@ -1156,12 +1155,12 @@ changes: * `SNICallback(servername, cb)` {Function} A function that will be called if the client supports SNI TLS extension. Two arguments will be passed when called: `servername` and `cb`. `SNICallback` should invoke `cb(null, ctx)`, - where `ctx` is a SecureContext instance. (`tls.createSecureContext(...)` can - be used to get a proper SecureContext.) If `SNICallback` wasn't provided the - default callback with high-level API will be used (see below). + where `ctx` is a `SecureContext` instance. (`tls.createSecureContext(...)` + can be used to get a proper `SecureContext`.) If `SNICallback` wasn't + provided the default callback with high-level API will be used (see below). * `sessionTimeout` {number} An integer specifying the number of seconds after which the TLS session identifiers and TLS session tickets created by the - server will time out. See [SSL_CTX_set_timeout] for more details. + server will time out. See [`SSL_CTX_set_timeout`] for more details. * `ticketKeys`: A 48-byte `Buffer` instance consisting of a 16-byte prefix, a 16-byte HMAC key, and a 16-byte AES key. This can be used to accept TLS session tickets on multiple instances of the TLS server. @@ -1169,7 +1168,7 @@ changes: servers, the identity options (`pfx` or `key`/`cert`) are usually required. * `secureConnectionListener` {Function} -Creates a new [tls.Server][]. The `secureConnectionListener`, if provided, is +Creates a new [`tls.Server`][]. The `secureConnectionListener`, if provided, is automatically set as a listener for the [`'secureConnection'`][] event. The `ticketKeys` options is automatically shared between `cluster` module @@ -1371,13 +1370,16 @@ where `secureSocket` has the same API as `pair.cleartext`. [`'secureConnect'`]: #tls_event_secureconnect [`'secureConnection'`]: #tls_event_secureconnection +[`SSL_CTX_set_timeout`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_timeout.html [`crypto.getCurves()`]: crypto.html#crypto_crypto_getcurves +[`dns.lookup()`]: dns.html#dns_dns_lookup_hostname_options_callback [`net.Server.address()`]: net.html#net_server_address [`net.Server`]: net.html#net_class_net_server [`net.Socket`]: net.html#net_class_net_socket [`server.getConnections()`]: net.html#net_server_getconnections_callback [`server.listen()`]: net.html#net_server_listen [`tls.DEFAULT_ECDH_CURVE`]: #tls_tls_default_ecdh_curve +[`tls.Server`]: #tls_class_tls_server [`tls.TLSSocket.getPeerCertificate()`]: #tls_tlssocket_getpeercertificate_detailed [`tls.TLSSocket`]: #tls_class_tls_tlssocket [`tls.connect()`]: #tls_tls_connect_options_callback @@ -1392,7 +1394,7 @@ where `secureSocket` has the same API as `pair.cleartext`. [OpenSSL Options]: crypto.html#crypto_openssl_options [OpenSSL cipher list format documentation]: https://www.openssl.org/docs/man1.1.0/apps/ciphers.html#CIPHER-LIST-FORMAT [Perfect Forward Secrecy]: #tls_perfect_forward_secrecy -[SSL_CTX_set_timeout]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_timeout.html +[RFC 5929]: https://tools.ietf.org/html/rfc5929 [SSL_METHODS]: https://www.openssl.org/docs/man1.1.0/ssl/ssl.html#Dealing-with-Protocol-Methods [Stream]: stream.html#stream_stream [TLS Session Tickets]: https://www.ietf.org/rfc/rfc5077.txt @@ -1400,6 +1402,3 @@ where `secureSocket` has the same API as `pair.cleartext`. [asn1.js]: https://npmjs.org/package/asn1.js [modifying the default cipher suite]: #tls_modifying_the_default_tls_cipher_suite [specific attacks affecting larger AES key sizes]: https://www.schneier.com/blog/archives/2009/07/another_new_aes.html -[tls.Server]: #tls_class_tls_server -[`dns.lookup()`]: dns.html#dns_dns_lookup_hostname_options_callback -[RFC 5929]: https://tools.ietf.org/html/rfc5929 diff --git a/doc/api/tracing.md b/doc/api/tracing.md index f83e808dc89220..7b30672ecce6af 100644 --- a/doc/api/tracing.md +++ b/doc/api/tracing.md @@ -8,14 +8,14 @@ Trace Event provides a mechanism to centralize tracing information generated by V8, Node.js core, and userspace code. Tracing can be enabled with the `--trace-event-categories` command-line flag -or by using the trace_events module. The `--trace-event-categories` flag accepts -a list of comma-separated category names. +or by using the `trace_events` module. The `--trace-event-categories` flag +accepts a list of comma-separated category names. The available categories are: * `node` - An empty placeholder. -* `node.async_hooks` - Enables capture of detailed [async_hooks] trace data. - The [async_hooks] events have a unique `asyncId` and a special triggerId +* `node.async_hooks` - Enables capture of detailed [`async_hooks`] trace data. + The [`async_hooks`] events have a unique `asyncId` and a special `triggerId` `triggerAsyncId` property. * `node.bootstrap` - Enables capture of Node.js bootstrap milestones. * `node.perf` - Enables capture of [Performance API] measurements. @@ -196,4 +196,4 @@ console.log(trace_events.getEnabledCategories()); [Performance API]: perf_hooks.html [V8]: v8.html -[async_hooks]: async_hooks.html +[`async_hooks`]: async_hooks.html diff --git a/doc/api/tty.md b/doc/api/tty.md index f8bc4feec3e86d..91bca8284d9378 100644 --- a/doc/api/tty.md +++ b/doc/api/tty.md @@ -126,15 +126,15 @@ is updated whenever the `'resize'` event is emitted. added: v9.9.0 --> -* `env` {Object} A object containing the environment variables to check. +* `env` {Object} An object containing the environment variables to check. **Default:** `process.env`. * Returns: {number} Returns: -* 1 for 2, -* 4 for 16, -* 8 for 256, -* 24 for 16,777,216 +* `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 diff --git a/doc/api/url.md b/doc/api/url.md index a7add464e8b983..64b7b444c54ffd 100644 --- a/doc/api/url.md +++ b/doc/api/url.md @@ -86,8 +86,8 @@ The `URL` class is also available on the global object. In accordance with browser conventions, all properties of `URL` objects are implemented as getters and setters on the class prototype, rather than as -data properties on the object itself. Thus, unlike [legacy urlObject][]s, using -the `delete` keyword on any properties of `URL` objects (e.g. `delete +data properties on the object itself. Thus, unlike [legacy `urlObject`][]s, +using the `delete` keyword on any properties of `URL` objects (e.g. `delete myURL.protocol`, `delete myURL.pathname`, etc) has no effect but will still return `true`. @@ -346,7 +346,7 @@ console.log(myURL.port); // Prints 1234 ``` -The port value may be set as either a number or as a String containing a number +The port value may be set as either a number or as a string containing a number in the range `0` to `65535` (inclusive). Setting the value to the default port of the `URL` objects given `protocol` will result in the `port` value becoming the empty string (`''`). @@ -581,7 +581,7 @@ added: v7.10.0 * `iterable` {Iterable} An iterable object whose elements are key-value pairs Instantiate a new `URLSearchParams` object with an iterable map in a way that -is similar to [`Map`][]'s constructor. `iterable` can be an Array or any +is similar to [`Map`][]'s constructor. `iterable` can be an `Array` or any iterable object. That means `iterable` can be another `URLSearchParams`, in which case the constructor will simply create a clone of the provided `URLSearchParams`. Elements of `iterable` are key-value pairs, and can @@ -644,16 +644,16 @@ Remove all name-value pairs whose name is `name`. * Returns: {Iterator} -Returns an ES6 Iterator over each of the name-value pairs in the query. -Each item of the iterator is a JavaScript Array. The first item of the Array -is the `name`, the second item of the Array is the `value`. +Returns an ES6 `Iterator` over each of the name-value pairs in the query. +Each item of the iterator is a JavaScript `Array`. The first item of the `Array` +is the `name`, the second item of the `Array` is the `value`. Alias for [`urlSearchParams[@@iterator]()`][`urlSearchParams@@iterator()`]. #### urlSearchParams.forEach(fn[, thisArg]) -* `fn` {Function} Function invoked for each name-value pair in the query. -* `thisArg` {Object} Object to be used as `this` value for when `fn` is called +* `fn` {Function} Invoked for each name-value pair in the query +* `thisArg` {Object} To be used as `this` value for when `fn` is called Iterates over each name-value pair in the query and invokes the given function. @@ -695,7 +695,7 @@ Returns `true` if there is at least one name-value pair whose name is `name`. * Returns: {Iterator} -Returns an ES6 Iterator over the names of each name-value pair. +Returns an ES6 `Iterator` over the names of each name-value pair. ```js const params = new URLSearchParams('foo=bar&foo=baz'); @@ -760,15 +760,15 @@ percent-encoded where necessary. * Returns: {Iterator} -Returns an ES6 Iterator over the values of each name-value pair. +Returns an ES6 `Iterator` over the values of each name-value pair. #### urlSearchParams\[Symbol.iterator\]() * Returns: {Iterator} -Returns an ES6 Iterator over each of the name-value pairs in the query string. -Each item of the iterator is a JavaScript Array. The first item of the Array -is the `name`, the second item of the Array is the `value`. +Returns an ES6 `Iterator` over each of the name-value pairs in the query string. +Each item of the iterator is a JavaScript `Array`. The first item of the `Array` +is the `name`, the second item of the `Array` is the `value`. Alias for [`urlSearchParams.entries()`][]. @@ -846,7 +846,7 @@ added: v7.6.0 Punycode encoded. **Default:** `false`. * Returns: {string} -Returns a customizable serialization of a URL String representation of a +Returns a customizable serialization of a URL `String` representation of a [WHATWG URL][] object. The URL object has both a `toString()` method and `href` property that return @@ -871,9 +871,9 @@ console.log(url.format(myURL, { fragment: false, unicode: true, auth: false })); ## Legacy URL API -### Legacy urlObject +### Legacy `urlObject` -The legacy urlObject (`require('url').Url`) is created and returned by the +The legacy `urlObject` (`require('url').Url`) is created and returned by the `url.parse()` function. #### urlObject.auth @@ -1039,7 +1039,7 @@ The formatting process operates as follows: `urlObject.host` is coerced to a string and appended to `result`. * If the `urlObject.pathname` property is a string that is not an empty string: * If the `urlObject.pathname` *does not start* with an ASCII forward slash - (`/`), then the literal string '/' is appended to `result`. + (`/`), then the literal string `'/'` is appended to `result`. * The value of `urlObject.pathname` is appended to `result`. * Otherwise, if `urlObject.pathname` is not `undefined` and is not a string, an [`Error`][] is thrown. @@ -1205,6 +1205,6 @@ console.log(myURL.origin); [WHATWG URL Standard]: https://url.spec.whatwg.org/ [WHATWG URL]: #url_the_whatwg_url_api [examples of parsed URLs]: https://url.spec.whatwg.org/#example-url-parsing -[legacy urlObject]: #url_legacy_urlobject +[legacy `urlObject`]: #url_legacy_urlobject [percent-encoded]: #whatwg-percent-encoding [stable sorting algorithm]: https://en.wikipedia.org/wiki/Sorting_algorithm#Stability diff --git a/doc/api/util.md b/doc/api/util.md index c91bea6549d6a7..380b2fd4089759 100644 --- a/doc/api/util.md +++ b/doc/api/util.md @@ -20,10 +20,10 @@ added: v8.2.0 * `original` {Function} An `async` function * Returns: {Function} a callback style function -Takes an `async` function (or a function that returns a Promise) and returns a +Takes an `async` function (or a function that returns a `Promise`) and returns a function following the error-first callback style, i.e. taking -a `(err, value) => ...` callback as the last argument. In the callback, the -first argument will be the rejection reason (or `null` if the Promise +an `(err, value) => ...` callback as the last argument. In the callback, the +first argument will be the rejection reason (or `null` if the `Promise` resolved), and the second argument will be the resolved value. ```js @@ -197,18 +197,18 @@ The first argument is a string containing zero or more *placeholder* tokens. Each placeholder token is replaced with the converted value from the corresponding argument. Supported placeholders are: -* `%s` - String. -* `%d` - Number (integer or floating point value). +* `%s` - `String`. +* `%d` - `Number` (integer or floating point value). * `%i` - Integer. * `%f` - Floating point value. * `%j` - JSON. Replaced with the string `'[Circular]'` if the argument contains circular references. -* `%o` - Object. A string representation of an object +* `%o` - `Object`. A string representation of an object with generic JavaScript object formatting. Similar to `util.inspect()` with options `{ showHidden: true, showProxy: true }`. This will show the full object including non-enumerable properties and proxies. -* `%O` - Object. A string representation of an object with generic JavaScript +* `%O` - `Object`. A string representation of an object with generic JavaScript object formatting. Similar to `util.inspect()` without options. This will show the full object not including non-enumerable properties and proxies. * `%%` - single percent sign (`'%'`). This does not consume an argument. @@ -362,7 +362,7 @@ added: v0.3.0 changes: - version: v10.0.0 pr-url: https://github.com/nodejs/node/pull/19259 - description: WeakMap and WeakSet entries can now be inspected as well. + description: The `WeakMap` and `WeakSet` entries can now be inspected. - version: v9.9.0 pr-url: https://github.com/nodejs/node/pull/17576 description: The `compact` option is supported now. @@ -381,7 +381,7 @@ changes: description: The `showProxy` option is supported now. --> -* `object` {any} Any JavaScript primitive or Object. +* `object` {any} Any JavaScript primitive or `Object`. * `options` {Object} * `showHidden` {boolean} If `true`, the `object`'s non-enumerable symbols and properties will be included in the formatted result as well as [`WeakMap`][] @@ -623,7 +623,7 @@ util.inspect(obj); added: v6.6.0 --> -A Symbol that can be used to declare custom inspect functions, see +A {symbol} that can be used to declare custom inspect functions, see [Custom inspection functions on Objects][]. ### util.inspect.defaultOptions @@ -670,7 +670,7 @@ added: v8.0.0 * Returns: {Function} Takes a function following the common error-first callback style, i.e. taking -a `(err, value) => ...` callback as the last argument, and returns a version +an `(err, value) => ...` callback as the last argument, and returns a version that returns promises. ```js @@ -752,7 +752,7 @@ added: v8.0.0 * {symbol} -A Symbol that can be used to declare custom promisified variants of functions, +A {symbol} that can be used to declare custom promisified variants of functions, see [Custom promisified functions][]. ## Class: util.TextDecoder @@ -859,7 +859,7 @@ supported encodings or an alias. ### textDecoder.decode([input[, options]]) * `input` {ArrayBuffer|DataView|TypedArray} An `ArrayBuffer`, `DataView` or - Typed Array instance containing the encoded data. + `Typed Array` instance containing the encoded data. * `options` {Object} * `stream` {boolean} `true` if additional chunks of data are expected. **Default:** `false`. diff --git a/doc/api/vm.md b/doc/api/vm.md index 68b25b6aa32d23..9e1249dc4ed8bb 100644 --- a/doc/api/vm.md +++ b/doc/api/vm.md @@ -162,20 +162,20 @@ const contextifiedSandbox = vm.createContext({ secret: 42 }); * `url` {string} URL used in module resolution and stack traces. **Default:** `'vm:module(i)'` where `i` is a context-specific ascending index. * `context` {Object} The [contextified][] object as returned by the - `vm.createContext()` method, to compile and evaluate this Module in. + `vm.createContext()` method, to compile and evaluate this `Module` in. * `lineOffset` {integer} Specifies the line number offset that is displayed - in stack traces produced by this Module. - * `columnOffset` {integer} Spcifies the column number offset that is displayed - in stack traces produced by this Module. - * `initalizeImportMeta` {Function} Called during evaluation of this Module to - initialize the `import.meta`. This function has the signature `(meta, - module)`, where `meta` is the `import.meta` object in the Module, and + in stack traces produced by this `Module`. + * `columnOffset` {integer} Specifies the column number offset that is + displayed in stack traces produced by this `Module`. + * `initalizeImportMeta` {Function} Called during evaluation of this `Module` + to initialize the `import.meta`. This function has the signature `(meta, + module)`, where `meta` is the `import.meta` object in the `Module`, and `module` is this `vm.Module` object. Creates a new ES `Module` object. *Note*: Properties assigned to the `import.meta` object that are objects may -allow the Module to access information outside the specified `context`, if the +allow the `Module` to access information outside the specified `context`, if the object is created in the top level context. Use `vm.runInContext()` to create objects in a specific context. @@ -217,8 +217,8 @@ const contextifiedSandbox = vm.createContext({ secret: 42 }); The specifiers of all dependencies of this module. The returned array is frozen to disallow any changes to it. -Corresponds to the [[RequestedModules]] field of [Source Text Module Record][]s -in the ECMAScript specification. +Corresponds to the `[[RequestedModules]]` field of +[Source Text Module Record][]s in the ECMAScript specification. ### module.error @@ -231,7 +231,7 @@ accessing this property will result in a thrown exception. The value `undefined` cannot be used for cases where there is not a thrown exception due to possible ambiguity with `throw undefined;`. -Corresponds to the [[EvaluationError]] field of [Source Text Module Record][]s +Corresponds to the `[[EvaluationError]]` field of [Source Text Module Record][]s in the ECMAScript specification. ### module.linkingStatus @@ -246,8 +246,8 @@ The current linking status of `module`. It will be one of the following values: - `'linked'`: `module.link()` has been called, and all its dependencies have been successfully linked. - `'errored'`: `module.link()` has been called, but at least one of its - dependencies failed to link, either because the callback returned a Promise - that is rejected, or because the Module the callback returned is invalid. + dependencies failed to link, either because the callback returned a `Promise` + that is rejected, or because the `Module` the callback returned is invalid. ### module.namespace @@ -289,9 +289,9 @@ The current status of the module. Will be one of: - `'errored'`: The module has been evaluated, but an exception was thrown. Other than `'errored'`, this status string corresponds to the specification's -[Source Text Module Record][]'s [[Status]] field. `'errored'` corresponds to -`'evaluated'` in the specification, but with [[EvaluationError]] set to a value -that is not `undefined`. +[Source Text Module Record][]'s `[[Status]]` field. `'errored'` corresponds to +`'evaluated'` in the specification, but with `[[EvaluationError]]` set to a +value that is not `undefined`. ### module.url diff --git a/doc/api/zlib.md b/doc/api/zlib.md index 33dbdbef1d741e..0e66abdcfb0766 100644 --- a/doc/api/zlib.md +++ b/doc/api/zlib.md @@ -165,7 +165,7 @@ The memory requirements for deflate are (in bytes): (1 << (windowBits + 2)) + (1 << (memLevel + 9)) ``` -That is: 128K for windowBits = 15 + 128K for memLevel = 8 +That is: 128K for `windowBits` = 15 + 128K for `memLevel` = 8 (default values) plus a few kilobytes for small objects. For example, to reduce the default memory requirements from 256K to 128K, the @@ -178,7 +178,7 @@ const options = { windowBits: 14, memLevel: 7 }; This will, however, generally degrade compression. The memory requirements for inflate are (in bytes) `1 << windowBits`. -That is, 32K for windowBits = 15 (default value) plus a few kilobytes +That is, 32K for `windowBits` = 15 (default value) plus a few kilobytes for small objects. This is in addition to a single internal output slab buffer of size @@ -287,10 +287,10 @@ added: v0.11.1 changes: - version: v9.4.0 pr-url: https://github.com/nodejs/node/pull/16042 - description: The `dictionary` option can be an ArrayBuffer. + description: The `dictionary` option can be an `ArrayBuffer`. - version: v8.0.0 pr-url: https://github.com/nodejs/node/pull/12001 - description: The `dictionary` option can be an Uint8Array now. + description: The `dictionary` option can be an `Uint8Array` now. - version: v5.11.0 pr-url: https://github.com/nodejs/node/pull/6069 description: The `finishFlush` option is supported now. @@ -473,17 +473,17 @@ Provides an object enumerating Zlib-related constants. added: v0.5.8 --> -Creates and returns a new [Deflate][] object with the given [`options`][]. +Creates and returns a new [`Deflate`][] object with the given [`options`][]. ## zlib.createDeflateRaw([options]) -Creates and returns a new [DeflateRaw][] object with the given [`options`][]. +Creates and returns a new [`DeflateRaw`][] object with the given [`options`][]. -An upgrade of zlib from 1.2.8 to 1.2.11 changed behavior when windowBits -is set to 8 for raw deflate streams. zlib would automatically set windowBits +An upgrade of zlib from 1.2.8 to 1.2.11 changed behavior when `windowBits` +is set to 8 for raw deflate streams. zlib would automatically set `windowBits` to 9 if was initially set to 8. Newer versions of zlib will throw an exception, so Node.js restored the original behavior of upgrading a value of 8 to 9, since passing `windowBits = 9` to zlib actually results in a compressed stream @@ -494,35 +494,35 @@ that effectively uses an 8-bit window only. added: v0.5.8 --> -Creates and returns a new [Gunzip][] object with the given [`options`][]. +Creates and returns a new [`Gunzip`][] object with the given [`options`][]. ## zlib.createGzip([options]) -Creates and returns a new [Gzip][] object with the given [`options`][]. +Creates and returns a new [`Gzip`][] object with the given [`options`][]. ## zlib.createInflate([options]) -Creates and returns a new [Inflate][] object with the given [`options`][]. +Creates and returns a new [`Inflate`][] object with the given [`options`][]. ## zlib.createInflateRaw([options]) -Creates and returns a new [InflateRaw][] object with the given [`options`][]. +Creates and returns a new [`InflateRaw`][] object with the given [`options`][]. ## zlib.createUnzip([options]) -Creates and returns a new [Unzip][] object with the given [`options`][]. +Creates and returns a new [`Unzip`][] object with the given [`options`][]. ## Convenience Methods @@ -542,13 +542,13 @@ added: v0.6.0 changes: - version: v9.4.0 pr-url: https://github.com/nodejs/node/pull/16042 - description: The `buffer` parameter can be an ArrayBuffer. + description: The `buffer` parameter can be an `ArrayBuffer`. - version: v8.0.0 pr-url: https://github.com/nodejs/node/pull/12223 - description: The `buffer` parameter can be any TypedArray or DataView now. + description: The `buffer` parameter can be any `TypedArray` or `DataView`. - version: v8.0.0 pr-url: https://github.com/nodejs/node/pull/12001 - description: The `buffer` parameter can be an Uint8Array now. + description: The `buffer` parameter can be an `Uint8Array` now. --> ### zlib.deflateSync(buffer[, options]) - `buffer` {Buffer|TypedArray|DataView|ArrayBuffer|string} -Compress a chunk of data with [Deflate][]. +Compress a chunk of data with [`Deflate`][]. ### zlib.deflateRaw(buffer[, options], callback) ### zlib.deflateRawSync(buffer[, options]) - `buffer` {Buffer|TypedArray|DataView|ArrayBuffer|string} -Compress a chunk of data with [DeflateRaw][]. +Compress a chunk of data with [`DeflateRaw`][]. ### zlib.gunzip(buffer[, options], callback) ### zlib.gunzipSync(buffer[, options]) - `buffer` {Buffer|TypedArray|DataView|ArrayBuffer|string} -Decompress a chunk of data with [Gunzip][]. +Decompress a chunk of data with [`Gunzip`][]. ### zlib.gzip(buffer[, options], callback) ### zlib.gzipSync(buffer[, options]) - `buffer` {Buffer|TypedArray|DataView|ArrayBuffer|string} -Compress a chunk of data with [Gzip][]. +Compress a chunk of data with [`Gzip`][]. ### zlib.inflate(buffer[, options], callback) ### zlib.inflateSync(buffer[, options]) - `buffer` {Buffer|TypedArray|DataView|ArrayBuffer|string} -Decompress a chunk of data with [Inflate][]. +Decompress a chunk of data with [`Inflate`][]. ### zlib.inflateRaw(buffer[, options], callback) ### zlib.inflateRawSync(buffer[, options]) - `buffer` {Buffer|TypedArray|DataView|ArrayBuffer|string} -Decompress a chunk of data with [InflateRaw][]. +Decompress a chunk of data with [`InflateRaw`][]. ### zlib.unzip(buffer[, options], callback) ### zlib.unzipSync(buffer[, options]) - `buffer` {Buffer|TypedArray|DataView|ArrayBuffer|string} -Decompress a chunk of data with [Unzip][]. +Decompress a chunk of data with [`Unzip`][]. [`.flush()`]: #zlib_zlib_flush_kind_callback [`Accept-Encoding`]: https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.3 @@ -770,16 +770,16 @@ Decompress a chunk of data with [Unzip][]. [`Buffer`]: buffer.html#buffer_class_buffer [`Content-Encoding`]: https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11 [`DataView`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView +[`Deflate`]: #zlib_class_zlib_deflate +[`DeflateRaw`]: #zlib_class_zlib_deflateraw +[`Gunzip`]: #zlib_class_zlib_gunzip +[`Gzip`]: #zlib_class_zlib_gzip +[`Inflate`]: #zlib_class_zlib_inflate +[`InflateRaw`]: #zlib_class_zlib_inflateraw [`TypedArray`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray -[`options`]: #zlib_class_options -[DeflateRaw]: #zlib_class_zlib_deflateraw -[Deflate]: #zlib_class_zlib_deflate -[Gunzip]: #zlib_class_zlib_gunzip -[Gzip]: #zlib_class_zlib_gzip -[InflateRaw]: #zlib_class_zlib_inflateraw -[Inflate]: #zlib_class_zlib_inflate -[Memory Usage Tuning]: #zlib_memory_usage_tuning -[Unzip]: #zlib_class_zlib_unzip [`UV_THREADPOOL_SIZE`]: cli.html#cli_uv_threadpool_size_size +[`Unzip`]: #zlib_class_zlib_unzip +[`options`]: #zlib_class_options [`zlib.bytesWritten`]: #zlib_zlib_byteswritten +[Memory Usage Tuning]: #zlib_memory_usage_tuning [zlib documentation]: https://zlib.net/manual.html#Constants From 166df9e15cce98a10b8d681617b8caa7df927f9f Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sun, 29 Apr 2018 20:37:19 -0700 Subject: [PATCH 094/173] doc: remove squash guideline from onboarding doc Although I agree with the guideline people should generally not squash commits in a pull request until the end (in other words, until it's time to land the PR), it is clear from comments and actions in the issue tracker that many do not share that view. This is fine by me, but I do think that we should our documentation should reflect our practices rather than being an aspirational statement. If we *do* wish to preserve this recommendation, it probably belongs in another document anyway as this is not a recommendation for Collaborators only but for anyone opening a pull request. PR-URL: https://github.com/nodejs/node/pull/20413 Reviewed-By: Colin Ihrig Reviewed-By: Trivikram Kamat Reviewed-By: James M Snell --- doc/onboarding-extras.md | 1 - 1 file changed, 1 deletion(-) diff --git a/doc/onboarding-extras.md b/doc/onboarding-extras.md index ffc316d7a670b6..62a7f7bb6b2837 100644 --- a/doc/onboarding-extras.md +++ b/doc/onboarding-extras.md @@ -97,4 +97,3 @@ to update from nodejs/node: ## Best practices * When making PRs, spend time writing a thorough description. -* Usually only squash at the end of your work. From 7a769ebba870fdfb18b6e04aab504d612133fc82 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Mon, 30 Apr 2018 06:43:15 -0700 Subject: [PATCH 095/173] doc: add squash guideline to pull-requests doc Tell the contributor to generally not squash commits during the pull request review process. PR-URL: https://github.com/nodejs/node/pull/20413 Reviewed-By: Colin Ihrig Reviewed-By: Trivikram Kamat Reviewed-By: James M Snell --- doc/guides/contributing/pull-requests.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/guides/contributing/pull-requests.md b/doc/guides/contributing/pull-requests.md index c248c1b9b6ec6f..a92e1cf305658b 100644 --- a/doc/guides/contributing/pull-requests.md +++ b/doc/guides/contributing/pull-requests.md @@ -599,9 +599,10 @@ whether the failure was caused by the changes in the Pull Request. ### Commit Squashing -When the commits in your Pull Request land, they may be squashed -into one commit per logical change. Metadata will be added to the commit -message (including links to the Pull Request, links to relevant issues, +In most cases, do not squash commits that you add to your Pull Request during +the review process. When the commits in your Pull Request land, they may be +squashed into one commit per logical change. Metadata will be added to the +commit message (including links to the Pull Request, links to relevant issues, and the names of the reviewers). The commit history of your Pull Request, however, will stay intact on the Pull Request page. From 289e4cef3f62073a220e4ed46535372800d4d702 Mon Sep 17 00:00:00 2001 From: Anatoli Papirovski Date: Wed, 2 May 2018 10:12:54 +0200 Subject: [PATCH 096/173] benchmark: fix next-tick-depth A recent change made these benchmarks fail by always finishing with 0 iterations. Restore a counter variable. PR-URL: https://github.com/nodejs/node/pull/20461 Reviewed-By: Ruben Bridgewater Reviewed-By: Rich Trott --- benchmark/process/next-tick-depth-args.js | 33 ++++++++++++----------- benchmark/process/next-tick-depth.js | 4 +-- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/benchmark/process/next-tick-depth-args.js b/benchmark/process/next-tick-depth-args.js index 52d349c776b326..a7670d99efc354 100644 --- a/benchmark/process/next-tick-depth-args.js +++ b/benchmark/process/next-tick-depth-args.js @@ -8,13 +8,14 @@ const bench = common.createBenchmark(main, { process.maxTickDepth = Infinity; function main({ n }) { + let counter = n; function cb4(arg1, arg2, arg3, arg4) { - if (--n) { - if (n % 4 === 0) + if (--counter) { + if (counter % 4 === 0) process.nextTick(cb4, 3.14, 1024, true, false); - else if (n % 3 === 0) + else if (counter % 3 === 0) process.nextTick(cb3, 512, true, null); - else if (n % 2 === 0) + else if (counter % 2 === 0) process.nextTick(cb2, false, 5.1); else process.nextTick(cb1, 0); @@ -22,12 +23,12 @@ function main({ n }) { bench.end(n); } function cb3(arg1, arg2, arg3) { - if (--n) { - if (n % 4 === 0) + if (--counter) { + if (counter % 4 === 0) process.nextTick(cb4, 3.14, 1024, true, false); - else if (n % 3 === 0) + else if (counter % 3 === 0) process.nextTick(cb3, 512, true, null); - else if (n % 2 === 0) + else if (counter % 2 === 0) process.nextTick(cb2, false, 5.1); else process.nextTick(cb1, 0); @@ -35,12 +36,12 @@ function main({ n }) { bench.end(n); } function cb2(arg1, arg2) { - if (--n) { - if (n % 4 === 0) + if (--counter) { + if (counter % 4 === 0) process.nextTick(cb4, 3.14, 1024, true, false); - else if (n % 3 === 0) + else if (counter % 3 === 0) process.nextTick(cb3, 512, true, null); - else if (n % 2 === 0) + else if (counter % 2 === 0) process.nextTick(cb2, false, 5.1); else process.nextTick(cb1, 0); @@ -48,12 +49,12 @@ function main({ n }) { bench.end(n); } function cb1(arg1) { - if (--n) { - if (n % 4 === 0) + if (--counter) { + if (counter % 4 === 0) process.nextTick(cb4, 3.14, 1024, true, false); - else if (n % 3 === 0) + else if (counter % 3 === 0) process.nextTick(cb3, 512, true, null); - else if (n % 2 === 0) + else if (counter % 2 === 0) process.nextTick(cb2, false, 5.1); else process.nextTick(cb1, 0); diff --git a/benchmark/process/next-tick-depth.js b/benchmark/process/next-tick-depth.js index 6669936e398272..1ad32c806181b0 100644 --- a/benchmark/process/next-tick-depth.js +++ b/benchmark/process/next-tick-depth.js @@ -7,11 +7,11 @@ const bench = common.createBenchmark(main, { process.maxTickDepth = Infinity; function main({ n }) { - + let counter = n; bench.start(); process.nextTick(onNextTick); function onNextTick() { - if (--n) + if (--counter) process.nextTick(onNextTick); else bench.end(n); From 658fbdc1057bac26756fa0c46c3778cb42aecde3 Mon Sep 17 00:00:00 2001 From: Daiki Arai Date: Mon, 23 Apr 2018 09:07:00 +0900 Subject: [PATCH 097/173] doc: add http.ClientRequest maxHeadersCount In http.ClientRequest's doc, add maxHeadersCount as a public property. And in the description of server's one, change a hyphen to a comma. PR-URL: https://github.com/nodejs/node/pull/20361 Refs: https://github.com/nodejs/node/pull/20359 Reviewed-By: Rich Trott Reviewed-By: Trivikram Kamat Reviewed-By: Colin Ihrig --- doc/api/http.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/doc/api/http.md b/doc/api/http.md index 673738f60a60b8..d98e4923bad401 100644 --- a/doc/api/http.md +++ b/doc/api/http.md @@ -607,6 +607,12 @@ const setCookie = request.getHeader('set-cookie'); // setCookie is of type string[] ``` +### request.maxHeadersCount + +* {number} **Default:** `2000` + +Limits maximum response headers count. If set to 0, no limit will be applied. + ### request.removeHeader(name) -* `file` {string|Buffer|URL|number} filename or file descriptor +* `path` {string|Buffer|URL|number} filename or file descriptor * `data` {string|Buffer} * `options` {Object|string} * `encoding` {string|null} **Default:** `'utf8'` @@ -939,7 +939,7 @@ If `options` is a string, then it specifies the encoding. Example: fs.appendFile('message.txt', 'data to append', 'utf8', callback); ``` -The `file` may be specified as a numeric file descriptor that has been opened +The `path` may be specified as a numeric file descriptor that has been opened for appending (using `fs.open()` or `fs.openSync()`). The file descriptor will not be closed automatically. @@ -955,7 +955,7 @@ fs.open('message.txt', 'a', (err, fd) => { }); ``` -## fs.appendFileSync(file, data[, options]) +## fs.appendFileSync(path, data[, options]) -* `file` {string|Buffer|URL|number} filename or file descriptor +* `path` {string|Buffer|URL|number} filename or file descriptor * `data` {string|Buffer} * `options` {Object|string} * `encoding` {string|null} **Default:** `'utf8'` @@ -994,7 +994,7 @@ If `options` is a string, then it specifies the encoding. Example: fs.appendFileSync('message.txt', 'data to append', 'utf8'); ``` -The `file` may be specified as a numeric file descriptor that has been opened +The `path` may be specified as a numeric file descriptor that has been opened for appending (using `fs.open()` or `fs.openSync()`). The file descriptor will not be closed automatically. @@ -3687,12 +3687,12 @@ condition, since other processes may change the file's state between the two calls. Instead, user code should open/read/write the file directly and handle the error raised if the file is not accessible. -### fsPromises.appendFile(file, data[, options]) +### fsPromises.appendFile(path, data[, options]) -* `file` {string|Buffer|URL|FileHandle} filename or `FileHandle` +* `path` {string|Buffer|URL|FileHandle} filename or `FileHandle` * `data` {string|Buffer} * `options` {Object|string} * `encoding` {string|null} **Default:** `'utf8'` @@ -3706,7 +3706,7 @@ resolved with no arguments upon success. If `options` is a string, then it specifies the encoding. -The `file` may be specified as a `FileHandle` that has been opened +The `path` may be specified as a `FileHandle` that has been opened for appending (using `fsPromises.open()`). ### fsPromises.chmod(path, mode) From 1b9c40cc71446bd996198c435449a5d213f59a63 Mon Sep 17 00:00:00 2001 From: Carrie Coxwell Date: Sun, 29 Apr 2018 13:29:40 -0500 Subject: [PATCH 109/173] util: named anonymous functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/20408 Reviewed-By: Michaël Zasso Reviewed-By: Luigi Pinca Reviewed-By: Colin Ihrig Reviewed-By: Weijia Wang Reviewed-By: Matheus Marchini --- lib/util.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/util.js b/lib/util.js index 93bcb343a9eefc..45d98de194c836 100644 --- a/lib/util.js +++ b/lib/util.js @@ -277,12 +277,12 @@ function debuglog(set) { if (!debugs[set]) { if (debugEnvRegex.test(set)) { const pid = process.pid; - debugs[set] = function() { + debugs[set] = function debug() { const msg = exports.format.apply(exports, arguments); console.error('%s %d: %s', set, pid, msg); }; } else { - debugs[set] = function() {}; + debugs[set] = function debug() {}; } } return debugs[set]; From b6de6a7e35669b30997cd033e19950ee15b3c55b Mon Sep 17 00:00:00 2001 From: Carrie Coxwell Date: Mon, 30 Apr 2018 02:08:20 -0500 Subject: [PATCH 110/173] lib: named anonymous functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/20408 Reviewed-By: Michaël Zasso Reviewed-By: Luigi Pinca Reviewed-By: Colin Ihrig Reviewed-By: Weijia Wang Reviewed-By: Matheus Marchini --- lib/fs.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/fs.js b/lib/fs.js index 2d41f17e8d1de5..1bcb58a9124f96 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -245,7 +245,7 @@ fs.readFile = function(path, options, callback) { req.oncomplete = readFileAfterOpen; if (context.isUserFd) { - process.nextTick(function() { + process.nextTick(function tick() { req.oncomplete(null, path); }); return; @@ -302,7 +302,7 @@ ReadFileContext.prototype.close = function(err) { this.err = err; if (this.isUserFd) { - process.nextTick(function() { + process.nextTick(function tick() { req.oncomplete(null); }); return; @@ -552,7 +552,7 @@ fs.read = function(fd, buffer, offset, length, position, callback) { length |= 0; if (length === 0) { - return process.nextTick(function() { + return process.nextTick(function tick() { callback && callback(null, 0, buffer); }); } @@ -1217,7 +1217,7 @@ function writeAll(fd, isUserFd, buffer, offset, length, position, callback) { if (isUserFd) { callback(writeErr); } else { - fs.close(fd, function() { + fs.close(fd, function close() { callback(writeErr); }); } From e5537477d4927be4bc383e46df5ba59c70dd61a2 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Wed, 2 May 2018 09:03:47 -0700 Subject: [PATCH 111/173] doc: update Collaborator Guide reference MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In pull-requests.md: * Refer to the Collaborator Guide as Collaborator Guide and not Collaborator's Guide. That is how the doc describes itself and we should be consistent. PR-URL: https://github.com/nodejs/node/pull/20473 Reviewed-By: Vse Mozhet Byt Reviewed-By: Luigi Pinca Reviewed-By: Tobias Nießen Reviewed-By: Trivikram Kamat --- doc/guides/contributing/pull-requests.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/guides/contributing/pull-requests.md b/doc/guides/contributing/pull-requests.md index a92e1cf305658b..0da7022d101ed5 100644 --- a/doc/guides/contributing/pull-requests.md +++ b/doc/guides/contributing/pull-requests.md @@ -35,7 +35,7 @@ so that you can make the actual changes. This is where we will start. * [Getting Approvals for your Pull Request](#getting-approvals-for-your-pull-request) * [CI Testing](#ci-testing) * [Waiting Until the Pull Request Gets Landed](#waiting-until-the-pull-request-gets-landed) - * [Check Out the Collaborator's Guide](#check-out-the-collaborators-guide) + * [Check Out the Collaborator Guide](#check-out-the-collaborator-guide) ## Dependencies @@ -645,17 +645,17 @@ doesn't need to wait. A Pull Request may well take longer to be merged in. All these precautions are important because Node.js is widely used, so don't be discouraged! -### Check Out the Collaborator's Guide +### Check Out the Collaborator Guide -If you want to know more about the code review and the landing process, -you can take a look at the -[collaborator's guide](https://github.com/nodejs/node/blob/master/COLLABORATOR_GUIDE.md). +If you want to know more about the code review and the landing process, see the +[Collaborator Guide][]. [approved]: #getting-approvals-for-your-pull-request [benchmark results]: ../writing-and-running-benchmarks.md [Building guide]: ../../../BUILDING.md [CI (Continuous Integration) test run]: #ci-testing [Code of Conduct]: https://github.com/nodejs/admin/blob/master/CODE_OF_CONDUCT.md +[Collaborator Guide]: ../../../COLLABORATOR_GUIDE.md [guide for writing tests in Node.js]: ../writing-tests.md [https://ci.nodejs.org/]: https://ci.nodejs.org/ [IRC in the #node-dev channel]: https://webchat.freenode.net?channels=node-dev&uio=d4 From b2d6eb74d45482daddad3ffb2690519300945d68 Mon Sep 17 00:00:00 2001 From: Michael Dawson Date: Mon, 30 Apr 2018 12:13:20 -0400 Subject: [PATCH 112/173] doc: cleanup n-api.md doc Partial doc cleanup as per https://github.com/nodejs/node/issues/20421 PR-URL: https://github.com/nodejs/node/pull/20430 Reviewed-By: Trivikram Kamat Reviewed-By: Gabriel Schulhof Reviewed-By: Colin Ihrig Reviewed-By: James M Snell --- doc/api/n-api.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/doc/api/n-api.md b/doc/api/n-api.md index 3ba902f1df5e57..12b39750223754 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -40,7 +40,7 @@ there to be one or more C++ wrapper modules that provide an inlineable C++ API. Binaries built with these wrapper modules will depend on the symbols for the N-API C based functions exported by Node.js. These wrappers are not part of N-API, nor will they be maintained as part of Node.js. One such -example is: [node-api](https://github.com/nodejs/node-api). +example is: [node-addon-api](https://github.com/nodejs/node-addon-api). In order to use the N-API functions, include the file [`node_api.h`](https://github.com/nodejs/node/blob/master/src/node_api.h) @@ -73,7 +73,9 @@ typedef enum { napi_generic_failure, napi_pending_exception, napi_cancelled, - napi_status_last + napi_escape_called_twice, + napi_handle_scope_mismatch, + napi_callback_scope_mismatch } napi_status; ``` If additional information is required upon an API returning a failed status, @@ -589,7 +591,7 @@ that has a loop which iterates through the elements in a large array: ```C for (int i = 0; i < 1000000; i++) { napi_value result; - napi_status status = napi_get_element(e, object, i, &result); + napi_status status = napi_get_element(env, object, i, &result); if (status != napi_ok) { break; } @@ -626,7 +628,7 @@ for (int i = 0; i < 1000000; i++) { break; } napi_value result; - status = napi_get_element(e, object, i, &result); + status = napi_get_element(env, object, i, &result); if (status != napi_ok) { break; } @@ -2486,10 +2488,10 @@ performed using a N-API call). property to be a JavaScript function represented by `method`. If this is passed in, set `value`, `getter` and `setter` to `NULL` (since these members won't be used). -- `data`: The callback data passed into `method`, `getter` and `setter` if -this function is invoked. - `attributes`: The attributes associated with the particular property. See [`napi_property_attributes`](#n_api_napi_property_attributes). +- `data`: The callback data passed into `method`, `getter` and `setter` if +this function is invoked. ### Functions #### napi_get_property_names From c0f153528e58afde5b7c09db9d02d125d00b2a4c Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Sat, 28 Apr 2018 21:33:46 +0200 Subject: [PATCH 113/173] src: remove `kFlagNoShutdown` flag This was originally introduced in 3446ff417ba1e, in order to fix a hard crash. However, since the libuv 1.18.0 update, that hard crash is gone, and since f2b9805f85d3f we do not throw an error in JS land anymore either, rendering the flag unnecessary. Also, the original test that checked this condition was added to `test/parallel/`. Since that typically runs without a TTY stdin, a duplicate test is being added to the pseudo-tty test suite in this commit. Refs: https://github.com/nodejs/node/commit/3446ff417ba1e11d35d1661b8788eac5af029360 Refs: https://github.com/nodejs/node/commit/f2b9805f85d3ff770892b37944a0890e0e60ca78 Refs: https://github.com/libuv/libuv/commit/0e2814179c9903423d058b095e84f48fcfb8f3d1 PR-URL: https://github.com/nodejs/node/pull/20388 Reviewed-By: Anatoli Papirovski Reviewed-By: Ruben Bridgewater Reviewed-By: Ben Noordhuis --- src/stream_base-inl.h | 3 +-- src/stream_base.h | 3 +-- src/tty_wrap.cc | 2 +- test/pseudo-tty/test-tty-stdin-end.js | 7 +++++++ test/pseudo-tty/test-tty-stdin-end.out | 0 5 files changed, 10 insertions(+), 5 deletions(-) create mode 100644 test/pseudo-tty/test-tty-stdin-end.js create mode 100644 test/pseudo-tty/test-tty-stdin-end.out diff --git a/src/stream_base-inl.h b/src/stream_base-inl.h index 392dc2c87c3ca3..4f4252073d26b5 100644 --- a/src/stream_base-inl.h +++ b/src/stream_base-inl.h @@ -335,8 +335,7 @@ void StreamBase::AddMethods(Environment* env, env->SetProtoMethod(t, "readStart", JSMethod); env->SetProtoMethod(t, "readStop", JSMethod); - if ((flags & kFlagNoShutdown) == 0) - env->SetProtoMethod(t, "shutdown", JSMethod); + env->SetProtoMethod(t, "shutdown", JSMethod); if ((flags & kFlagHasWritev) != 0) env->SetProtoMethod(t, "writev", JSMethod); env->SetProtoMethod(t, diff --git a/src/stream_base.h b/src/stream_base.h index 96b8589b06831d..94a091988cfcf9 100644 --- a/src/stream_base.h +++ b/src/stream_base.h @@ -257,8 +257,7 @@ class StreamBase : public StreamResource { public: enum Flags { kFlagNone = 0x0, - kFlagHasWritev = 0x1, - kFlagNoShutdown = 0x2 + kFlagHasWritev = 0x1 }; template diff --git a/src/tty_wrap.cc b/src/tty_wrap.cc index 9977738afcbfd5..c5abc6bf9b9b91 100644 --- a/src/tty_wrap.cc +++ b/src/tty_wrap.cc @@ -61,7 +61,7 @@ void TTYWrap::Initialize(Local target, env->SetProtoMethod(t, "ref", HandleWrap::Ref); env->SetProtoMethod(t, "hasRef", HandleWrap::HasRef); - LibuvStreamWrap::AddMethods(env, t, StreamBase::kFlagNoShutdown); + LibuvStreamWrap::AddMethods(env, t); env->SetProtoMethod(t, "getWindowSize", TTYWrap::GetWindowSize); env->SetProtoMethod(t, "setRawMode", SetRawMode); diff --git a/test/pseudo-tty/test-tty-stdin-end.js b/test/pseudo-tty/test-tty-stdin-end.js new file mode 100644 index 00000000000000..c78f58446d03e9 --- /dev/null +++ b/test/pseudo-tty/test-tty-stdin-end.js @@ -0,0 +1,7 @@ +'use strict'; +require('../common'); + +// This test ensures that Node.js doesn't crash on `process.stdin.emit("end")`. +// https://github.com/nodejs/node/issues/1068 + +process.stdin.emit('end'); diff --git a/test/pseudo-tty/test-tty-stdin-end.out b/test/pseudo-tty/test-tty-stdin-end.out new file mode 100644 index 00000000000000..e69de29bb2d1d6 From c21a52f415d89befab572054740589cde9be578b Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Tue, 1 May 2018 17:24:41 +0200 Subject: [PATCH 114/173] src: access `ContextifyContext*` more directly in property cbs PR-URL: https://github.com/nodejs/node/pull/20455 Fixes: https://github.com/nodejs/node/issues/18897 Reviewed-By: Gus Caplan Reviewed-By: Ben Noordhuis Reviewed-By: Daniel Bevenius --- src/node_contextify.cc | 43 ++++++++++++++++++++---------------------- src/node_contextify.h | 3 +++ 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/node_contextify.cc b/src/node_contextify.cc index e07d5ebcd29d0d..62a9416d325065 100644 --- a/src/node_contextify.cc +++ b/src/node_contextify.cc @@ -120,7 +120,7 @@ Local ContextifyContext::CreateDataWrapper(Environment* env) { if (wrapper.IsEmpty()) return scope.Escape(Local::New(env->isolate(), Local())); - Wrap(wrapper, this); + wrapper->SetAlignedPointerInInternalField(0, this); return scope.Escape(wrapper); } @@ -290,12 +290,19 @@ ContextifyContext* ContextifyContext::ContextFromContextifiedSandbox( return nullptr; } +// static +template +ContextifyContext* ContextifyContext::Get(const PropertyCallbackInfo& args) { + Local data = args.Data(); + return static_cast( + data.As()->GetAlignedPointerFromInternalField(0)); +} + // static void ContextifyContext::PropertyGetterCallback( Local property, const PropertyCallbackInfo& args) { - ContextifyContext* ctx; - ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); + ContextifyContext* ctx = ContextifyContext::Get(args); // Still initializing if (ctx->context_.IsEmpty()) @@ -324,8 +331,7 @@ void ContextifyContext::PropertySetterCallback( Local property, Local value, const PropertyCallbackInfo& args) { - ContextifyContext* ctx; - ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); + ContextifyContext* ctx = ContextifyContext::Get(args); // Still initializing if (ctx->context_.IsEmpty()) @@ -385,8 +391,7 @@ void ContextifyContext::PropertySetterCallback( void ContextifyContext::PropertyDescriptorCallback( Local property, const PropertyCallbackInfo& args) { - ContextifyContext* ctx; - ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); + ContextifyContext* ctx = ContextifyContext::Get(args); // Still initializing if (ctx->context_.IsEmpty()) @@ -408,8 +413,7 @@ void ContextifyContext::PropertyDefinerCallback( Local property, const PropertyDescriptor& desc, const PropertyCallbackInfo& args) { - ContextifyContext* ctx; - ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); + ContextifyContext* ctx = ContextifyContext::Get(args); // Still initializing if (ctx->context_.IsEmpty()) @@ -471,8 +475,7 @@ void ContextifyContext::PropertyDefinerCallback( void ContextifyContext::PropertyDeleterCallback( Local property, const PropertyCallbackInfo& args) { - ContextifyContext* ctx; - ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); + ContextifyContext* ctx = ContextifyContext::Get(args); // Still initializing if (ctx->context_.IsEmpty()) @@ -491,8 +494,7 @@ void ContextifyContext::PropertyDeleterCallback( // static void ContextifyContext::PropertyEnumeratorCallback( const PropertyCallbackInfo& args) { - ContextifyContext* ctx; - ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); + ContextifyContext* ctx = ContextifyContext::Get(args); // Still initializing if (ctx->context_.IsEmpty()) @@ -505,8 +507,7 @@ void ContextifyContext::PropertyEnumeratorCallback( void ContextifyContext::IndexedPropertyGetterCallback( uint32_t index, const PropertyCallbackInfo& args) { - ContextifyContext* ctx; - ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); + ContextifyContext* ctx = ContextifyContext::Get(args); // Still initializing if (ctx->context_.IsEmpty()) @@ -521,8 +522,7 @@ void ContextifyContext::IndexedPropertySetterCallback( uint32_t index, Local value, const PropertyCallbackInfo& args) { - ContextifyContext* ctx; - ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); + ContextifyContext* ctx = ContextifyContext::Get(args); // Still initializing if (ctx->context_.IsEmpty()) @@ -536,8 +536,7 @@ void ContextifyContext::IndexedPropertySetterCallback( void ContextifyContext::IndexedPropertyDescriptorCallback( uint32_t index, const PropertyCallbackInfo& args) { - ContextifyContext* ctx; - ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); + ContextifyContext* ctx = ContextifyContext::Get(args); // Still initializing if (ctx->context_.IsEmpty()) @@ -552,8 +551,7 @@ void ContextifyContext::IndexedPropertyDefinerCallback( uint32_t index, const PropertyDescriptor& desc, const PropertyCallbackInfo& args) { - ContextifyContext* ctx; - ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); + ContextifyContext* ctx = ContextifyContext::Get(args); // Still initializing if (ctx->context_.IsEmpty()) @@ -567,8 +565,7 @@ void ContextifyContext::IndexedPropertyDefinerCallback( void ContextifyContext::IndexedPropertyDeleterCallback( uint32_t index, const PropertyCallbackInfo& args) { - ContextifyContext* ctx; - ASSIGN_OR_RETURN_UNWRAP(&ctx, args.Data().As()); + ContextifyContext* ctx = ContextifyContext::Get(args); // Still initializing if (ctx->context_.IsEmpty()) diff --git a/src/node_contextify.h b/src/node_contextify.h index 565b8ef856ea49..70ce091af3b58e 100644 --- a/src/node_contextify.h +++ b/src/node_contextify.h @@ -55,6 +55,9 @@ class ContextifyContext { context()->GetEmbedderData(ContextEmbedderIndex::kSandboxObject)); } + template + static ContextifyContext* Get(const v8::PropertyCallbackInfo& args); + private: static void MakeContext(const v8::FunctionCallbackInfo& args); static void IsContext(const v8::FunctionCallbackInfo& args); From f5d42532a3d054a07201e7c37ed9e4bb2cec5f21 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Tue, 1 May 2018 18:34:52 +0200 Subject: [PATCH 115/173] src: refactor `BaseObject` internal field management MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Instead of storing a pointer whose type refers to the specific subclass of `BaseObject`, just store a `BaseObject*` directly. This means in particular that one can cast to classes along the way of the inheritance chain without issues, and that `BaseObject*` no longer needs to be the first superclass in the case of multiple inheritance. In particular, this renders hack-y solutions to this problem (like ddc19be6de1ba263d9c175b2760696e7b9918b25) obsolete and addresses a `TODO` comment of mine. - Move wrapping/unwrapping methods to the `BaseObject` class. We use these almost exclusively for `BaseObject`s, and I hope that this gives a better idea of how (and for what) these are used in our code. - Perform initialization/deinitialization of the internal field in the `BaseObject*` constructor/destructor. This makes the code a bit more obviously correct, avoids explicit calls for this in subclass constructors, and in particular allows us to avoid crash situations when we previously called `ClearWrap()` during GC. This also means that we enforce that the object passed to the `BaseObject` constructor needs to have an internal field. This is the only reason for the test change. - Change the signature of `MakeWeak()` to not require a pointer argument. Previously, this would always have been the same as `this`, and no other value made sense. Also, the parameter was something that I personally found somewhat confusing when becoming familiar with Node’s code. - Add a `TODO` comment that motivates switching to real inheritance for the JS types we expose from the native side. This patch brings us a lot closer to being able to do that. - Some less significant drive-by cleanup. Since we *effectively* already store the `BaseObject*` pointer anyway since ddc19be6de1ba263d9c175b2760696e7b9918b25, I do not think that this is going to have any impact on diagnostic tooling. Fixes: https://github.com/nodejs/node/issues/18897 PR-URL: https://github.com/nodejs/node/pull/20455 Reviewed-By: Gus Caplan Reviewed-By: Ben Noordhuis Reviewed-By: Daniel Bevenius --- src/async_wrap.cc | 6 +- src/base_object-inl.h | 78 ++++++++++++++------ src/base_object.h | 50 ++++++++++--- src/cares_wrap.cc | 31 +------- src/connect_wrap.cc | 6 -- src/connect_wrap.h | 1 - src/connection_wrap.h | 1 - src/fs_event_wrap.cc | 2 +- src/handle_wrap.cc | 2 - src/inspector_js_api.cc | 4 - src/js_stream.cc | 7 +- src/js_stream.h | 2 - src/module_wrap.cc | 1 - src/node_contextify.cc | 2 +- src/node_crypto.cc | 8 -- src/node_crypto.h | 16 ++-- src/node_file.cc | 2 +- src/node_file.h | 7 +- src/node_http2.cc | 14 +--- src/node_http2.h | 2 - src/node_http_parser.cc | 6 -- src/node_i18n.cc | 2 +- src/node_internals.h | 7 +- src/node_serdes.cc | 4 +- src/node_stat_watcher.cc | 5 +- src/node_trace_events.cc | 2 +- src/node_wrap.h | 2 + src/node_zlib.cc | 4 +- src/pipe_wrap.cc | 7 +- src/stream_base-inl.h | 14 +--- src/stream_base.cc | 6 -- src/stream_base.h | 2 - src/stream_pipe.cc | 2 +- src/tcp_wrap.cc | 9 +-- src/timer_wrap.cc | 6 +- src/tls_wrap.cc | 12 +-- src/udp_wrap.cc | 16 +--- src/util-inl.h | 19 ----- src/util.h | 18 ----- test/cctest/test_node_postmortem_metadata.cc | 6 +- 40 files changed, 147 insertions(+), 244 deletions(-) diff --git a/src/async_wrap.cc b/src/async_wrap.cc index 06dcbb4fb1d29d..f7a6d4e68dd483 100644 --- a/src/async_wrap.cc +++ b/src/async_wrap.cc @@ -123,8 +123,8 @@ RetainedObjectInfo* WrapperInfo(uint16_t class_id, Local wrapper) { Local object = wrapper.As(); CHECK_GT(object->InternalFieldCount(), 0); - AsyncWrap* wrap = Unwrap(object); - if (wrap == nullptr) return nullptr; // ClearWrap() already called. + AsyncWrap* wrap; + ASSIGN_OR_RETURN_UNWRAP(&wrap, object, nullptr); return new RetainedAsyncInfo(class_id, wrap); } @@ -231,7 +231,7 @@ class PromiseWrap : public AsyncWrap { public: PromiseWrap(Environment* env, Local object, bool silent) : AsyncWrap(env, object, PROVIDER_PROMISE, -1, silent) { - MakeWeak(this); + MakeWeak(); } size_t self_size() const override { return sizeof(*this); } diff --git a/src/base_object-inl.h b/src/base_object-inl.h index 5ff211f473b86b..11ba1c88da0486 100644 --- a/src/base_object-inl.h +++ b/src/base_object-inl.h @@ -31,54 +31,90 @@ namespace node { -inline BaseObject::BaseObject(Environment* env, v8::Local handle) +BaseObject::BaseObject(Environment* env, v8::Local handle) : persistent_handle_(env->isolate(), handle), env_(env) { CHECK_EQ(false, handle.IsEmpty()); - // The zero field holds a pointer to the handle. Immediately set it to - // nullptr in case it's accessed by the user before construction is complete. - if (handle->InternalFieldCount() > 0) - handle->SetAlignedPointerInInternalField(0, nullptr); + CHECK_GT(handle->InternalFieldCount(), 0); + handle->SetAlignedPointerInInternalField(0, static_cast(this)); } -inline Persistent& BaseObject::persistent() { +BaseObject::~BaseObject() { + if (persistent_handle_.IsEmpty()) { + // This most likely happened because the weak callback below cleared it. + return; + } + + { + v8::HandleScope handle_scope(env_->isolate()); + object()->SetAlignedPointerInInternalField(0, nullptr); + } +} + + +Persistent& BaseObject::persistent() { return persistent_handle_; } -inline v8::Local BaseObject::object() { +v8::Local BaseObject::object() { return PersistentToLocal(env_->isolate(), persistent_handle_); } -inline Environment* BaseObject::env() const { +Environment* BaseObject::env() const { return env_; } -template -inline void BaseObject::WeakCallback( - const v8::WeakCallbackInfo& data) { - delete data.GetParameter(); +BaseObject* BaseObject::FromJSObject(v8::Local obj) { + CHECK_GT(obj->InternalFieldCount(), 0); + return static_cast(obj->GetAlignedPointerFromInternalField(0)); } -template -inline void BaseObject::MakeWeak(Type* ptr) { - v8::HandleScope scope(env_->isolate()); - v8::Local handle = object(); - CHECK_GT(handle->InternalFieldCount(), 0); - Wrap(handle, ptr); - persistent_handle_.SetWeak(ptr, WeakCallback, - v8::WeakCallbackType::kParameter); +template +T* BaseObject::FromJSObject(v8::Local object) { + return static_cast(FromJSObject(object)); } -inline void BaseObject::ClearWeak() { +void BaseObject::MakeWeak() { + persistent_handle_.SetWeak( + this, + [](const v8::WeakCallbackInfo& data) { + BaseObject* obj = data.GetParameter(); + // Clear the persistent handle so that ~BaseObject() doesn't attempt + // to mess with internal fields, since the JS object may have + // transitioned into an invalid state. + // Refs: https://github.com/nodejs/node/issues/18897 + obj->persistent_handle_.Reset(); + delete obj; + }, v8::WeakCallbackType::kParameter); +} + + +void BaseObject::ClearWeak() { persistent_handle_.ClearWeak(); } + +v8::Local +BaseObject::MakeLazilyInitializedJSTemplate(Environment* env) { + auto constructor = [](const v8::FunctionCallbackInfo& args) { +#ifdef DEBUG + CHECK(args.IsConstructCall()); + CHECK_GT(args.This()->InternalFieldCount(), 0); +#endif + args.This()->SetAlignedPointerInInternalField(0, nullptr); + }; + + v8::Local t = env->NewFunctionTemplate(constructor); + t->InstanceTemplate()->SetInternalFieldCount(1); + return t; +} + } // namespace node #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS diff --git a/src/base_object.h b/src/base_object.h index 478499bbfeb5b2..7d8281238b1c1d 100644 --- a/src/base_object.h +++ b/src/base_object.h @@ -26,6 +26,7 @@ #include "node_persistent.h" #include "v8.h" +#include // std::remove_reference namespace node { @@ -33,8 +34,10 @@ class Environment; class BaseObject { public: + // Associates this object with `handle`. It uses the 0th internal field for + // that, and in particular aborts if there is no such field. inline BaseObject(Environment* env, v8::Local handle); - virtual ~BaseObject() = default; + virtual inline ~BaseObject(); // Returns the wrapped object. Returns an empty handle when // persistent.IsEmpty() is true. @@ -44,23 +47,30 @@ class BaseObject { inline Environment* env() const; - // The handle_ must have an internal field count > 0, and the first - // index is reserved for a pointer to this class. This is an - // implicit requirement, but Node does not have a case where it's - // required that MakeWeak() be called and the internal field not - // be set. - template - inline void MakeWeak(Type* ptr); + // Get a BaseObject* pointer, or subclass pointer, for the JS object that + // was also passed to the `BaseObject()` constructor initially. + // This may return `nullptr` if the C++ object has not been constructed yet, + // e.g. when the JS object used `MakeLazilyInitializedJSTemplate`. + static inline BaseObject* FromJSObject(v8::Local object); + template + static inline T* FromJSObject(v8::Local object); + // Make the `Persistent` a weak reference and, `delete` this object once + // the JS object has been garbage collected. + inline void MakeWeak(); + + // Undo `MakeWeak()`, i.e. turn this into a strong reference. inline void ClearWeak(); + // Utility to create a FunctionTemplate with one internal field (used for + // the `BaseObject*` pointer) and a constructor that initializes that field + // to `nullptr`. + static inline v8::Local MakeLazilyInitializedJSTemplate( + Environment* env); + private: BaseObject(); - template - static inline void WeakCallback( - const v8::WeakCallbackInfo& data); - // persistent_handle_ needs to be at a fixed offset from the start of the // class because it is used by src/node_postmortem_metadata.cc to calculate // offsets and generate debug symbols for BaseObject, which assumes that the @@ -71,6 +81,22 @@ class BaseObject { Environment* env_; }; + +// Global alias for FromJSObject() to avoid churn. +template +inline T* Unwrap(v8::Local obj) { + return BaseObject::FromJSObject(obj); +} + + +#define ASSIGN_OR_RETURN_UNWRAP(ptr, obj, ...) \ + do { \ + *ptr = static_cast::type>( \ + BaseObject::FromJSObject(obj)); \ + if (*ptr == nullptr) \ + return __VA_ARGS__; \ + } while (0) + } // namespace node #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS diff --git a/src/cares_wrap.cc b/src/cares_wrap.cc index 0cc7ed1464fdb7..4df47d75d43ba8 100644 --- a/src/cares_wrap.cc +++ b/src/cares_wrap.cc @@ -187,7 +187,7 @@ ChannelWrap::ChannelWrap(Environment* env, is_servers_default_(true), library_inited_(false), active_query_count_(0) { - MakeWeak(this); + MakeWeak(); Setup(); } @@ -205,7 +205,6 @@ class GetAddrInfoReqWrap : public ReqWrap { GetAddrInfoReqWrap(Environment* env, Local req_wrap_obj, bool verbatim); - ~GetAddrInfoReqWrap(); size_t self_size() const override { return sizeof(*this); } bool verbatim() const { return verbatim_; } @@ -219,18 +218,12 @@ GetAddrInfoReqWrap::GetAddrInfoReqWrap(Environment* env, bool verbatim) : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_GETADDRINFOREQWRAP) , verbatim_(verbatim) { - Wrap(req_wrap_obj, this); -} - -GetAddrInfoReqWrap::~GetAddrInfoReqWrap() { - ClearWrap(object()); } class GetNameInfoReqWrap : public ReqWrap { public: GetNameInfoReqWrap(Environment* env, Local req_wrap_obj); - ~GetNameInfoReqWrap(); size_t self_size() const override { return sizeof(*this); } }; @@ -238,11 +231,6 @@ class GetNameInfoReqWrap : public ReqWrap { GetNameInfoReqWrap::GetNameInfoReqWrap(Environment* env, Local req_wrap_obj) : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_GETNAMEINFOREQWRAP) { - Wrap(req_wrap_obj, this); -} - -GetNameInfoReqWrap::~GetNameInfoReqWrap() { - ClearWrap(object()); } @@ -587,8 +575,6 @@ class QueryWrap : public AsyncWrap { QueryWrap(ChannelWrap* channel, Local req_wrap_obj) : AsyncWrap(channel->env(), req_wrap_obj, AsyncWrap::PROVIDER_QUERYWRAP), channel_(channel) { - Wrap(req_wrap_obj, this); - // Make sure the channel object stays alive during the query lifetime. req_wrap_obj->Set(env()->context(), env()->channel_string(), @@ -597,7 +583,6 @@ class QueryWrap : public AsyncWrap { ~QueryWrap() override { CHECK_EQ(false, persistent().IsEmpty()); - ClearWrap(object()); } // Subclasses should implement the appropriate Send method. @@ -2143,14 +2128,8 @@ void Initialize(Local target, target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "AI_V4MAPPED"), Integer::New(env->isolate(), AI_V4MAPPED)); - auto is_construct_call_callback = - [](const FunctionCallbackInfo& args) { - CHECK(args.IsConstructCall()); - ClearWrap(args.This()); - }; Local aiw = - FunctionTemplate::New(env->isolate(), is_construct_call_callback); - aiw->InstanceTemplate()->SetInternalFieldCount(1); + BaseObject::MakeLazilyInitializedJSTemplate(env); AsyncWrap::AddWrapMethods(env, aiw); Local addrInfoWrapString = FIXED_ONE_BYTE_STRING(env->isolate(), "GetAddrInfoReqWrap"); @@ -2158,8 +2137,7 @@ void Initialize(Local target, target->Set(addrInfoWrapString, aiw->GetFunction()); Local niw = - FunctionTemplate::New(env->isolate(), is_construct_call_callback); - niw->InstanceTemplate()->SetInternalFieldCount(1); + BaseObject::MakeLazilyInitializedJSTemplate(env); AsyncWrap::AddWrapMethods(env, niw); Local nameInfoWrapString = FIXED_ONE_BYTE_STRING(env->isolate(), "GetNameInfoReqWrap"); @@ -2167,8 +2145,7 @@ void Initialize(Local target, target->Set(nameInfoWrapString, niw->GetFunction()); Local qrw = - FunctionTemplate::New(env->isolate(), is_construct_call_callback); - qrw->InstanceTemplate()->SetInternalFieldCount(1); + BaseObject::MakeLazilyInitializedJSTemplate(env); AsyncWrap::AddWrapMethods(env, qrw); Local queryWrapString = FIXED_ONE_BYTE_STRING(env->isolate(), "QueryReqWrap"); diff --git a/src/connect_wrap.cc b/src/connect_wrap.cc index f9ea987e05f5a3..dacdf72da7c494 100644 --- a/src/connect_wrap.cc +++ b/src/connect_wrap.cc @@ -13,12 +13,6 @@ using v8::Object; ConnectWrap::ConnectWrap(Environment* env, Local req_wrap_obj, AsyncWrap::ProviderType provider) : ReqWrap(env, req_wrap_obj, provider) { - Wrap(req_wrap_obj, this); -} - - -ConnectWrap::~ConnectWrap() { - ClearWrap(object()); } } // namespace node diff --git a/src/connect_wrap.h b/src/connect_wrap.h index 6227542bcbee50..80eae7f9bb8290 100644 --- a/src/connect_wrap.h +++ b/src/connect_wrap.h @@ -15,7 +15,6 @@ class ConnectWrap : public ReqWrap { ConnectWrap(Environment* env, v8::Local req_wrap_obj, AsyncWrap::ProviderType provider); - ~ConnectWrap(); size_t self_size() const override { return sizeof(*this); } }; diff --git a/src/connection_wrap.h b/src/connection_wrap.h index 096672efddaae2..afb168c614aa97 100644 --- a/src/connection_wrap.h +++ b/src/connection_wrap.h @@ -29,7 +29,6 @@ class ConnectionWrap : public LibuvStreamWrap { UVType handle_; }; - } // namespace node #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS diff --git a/src/fs_event_wrap.cc b/src/fs_event_wrap.cc index 1e7505d6d3219a..ed74f36719db79 100644 --- a/src/fs_event_wrap.cc +++ b/src/fs_event_wrap.cc @@ -131,7 +131,7 @@ void FSEventWrap::New(const FunctionCallbackInfo& args) { void FSEventWrap::Start(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); - FSEventWrap* wrap = Unwrap(args.Holder()); + FSEventWrap* wrap = Unwrap(args.This()); CHECK_NE(wrap, nullptr); CHECK(!wrap->initialized_); diff --git a/src/handle_wrap.cc b/src/handle_wrap.cc index a3b0209eb3121f..49bf0c55bea0a1 100644 --- a/src/handle_wrap.cc +++ b/src/handle_wrap.cc @@ -93,7 +93,6 @@ HandleWrap::HandleWrap(Environment* env, handle_(handle) { handle_->data = this; HandleScope scope(env->isolate()); - Wrap(object, this); env->handle_wrap_queue()->PushBack(this); } @@ -114,7 +113,6 @@ void HandleWrap::OnClose(uv_handle_t* handle) { if (have_close_callback) wrap->MakeCallback(env->onclose_string(), 0, nullptr); - ClearWrap(wrap->object()); delete wrap; } diff --git a/src/inspector_js_api.cc b/src/inspector_js_api.cc index 37cdcecd61dabb..ae353defe8079d 100644 --- a/src/inspector_js_api.cc +++ b/src/inspector_js_api.cc @@ -64,7 +64,6 @@ class JSBindingsConnection : public AsyncWrap { Local callback) : AsyncWrap(env, wrap, PROVIDER_INSPECTORJSBINDING), callback_(env->isolate(), callback) { - Wrap(wrap, this); Agent* inspector = env->inspector_agent(); session_ = inspector->Connect(std::unique_ptr( new JSBindingsSessionDelegate(env, this))); @@ -83,9 +82,6 @@ class JSBindingsConnection : public AsyncWrap { void Disconnect() { session_.reset(); - if (!persistent().IsEmpty()) { - ClearWrap(object()); - } delete this; } diff --git a/src/js_stream.cc b/src/js_stream.cc index ed6c6ee738e568..2293d8cf203d07 100644 --- a/src/js_stream.cc +++ b/src/js_stream.cc @@ -24,12 +24,7 @@ using v8::Value; JSStream::JSStream(Environment* env, Local obj) : AsyncWrap(env, obj, AsyncWrap::PROVIDER_JSSTREAM), StreamBase(env) { - node::Wrap(obj, this); - MakeWeak(this); -} - - -JSStream::~JSStream() { + MakeWeak(); } diff --git a/src/js_stream.h b/src/js_stream.h index 338cbe545630f1..b47a91a653ba7e 100644 --- a/src/js_stream.h +++ b/src/js_stream.h @@ -16,8 +16,6 @@ class JSStream : public AsyncWrap, public StreamBase { v8::Local unused, v8::Local context); - ~JSStream(); - bool IsAlive() override; bool IsClosing() override; int ReadStart() override; diff --git a/src/module_wrap.cc b/src/module_wrap.cc index 9bcdb4dce75ff2..fcccbfe93cea32 100644 --- a/src/module_wrap.cc +++ b/src/module_wrap.cc @@ -158,7 +158,6 @@ void ModuleWrap::New(const FunctionCallbackInfo& args) { obj->context_.Reset(isolate, context); env->module_map.emplace(module->GetIdentityHash(), obj); - Wrap(that, obj); that->SetIntegrityLevel(context, IntegrityLevel::kFrozen); args.GetReturnValue().Set(that); diff --git a/src/node_contextify.cc b/src/node_contextify.cc index 62a9416d325065..6e7027a29ba8a0 100644 --- a/src/node_contextify.cc +++ b/src/node_contextify.cc @@ -884,7 +884,7 @@ class ContextifyScript : public BaseObject { ContextifyScript(Environment* env, Local object) : BaseObject(env, object) { - MakeWeak(this); + MakeWeak(); } }; diff --git a/src/node_crypto.cc b/src/node_crypto.cc index c195868033f968..d5f27994307696 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -4653,7 +4653,6 @@ class PBKDF2Request : public AsyncWrap { keylen_(keylen), key_(node::Malloc(keylen)), iter_(iter) { - Wrap(object, this); } ~PBKDF2Request() override { @@ -4668,8 +4667,6 @@ class PBKDF2Request : public AsyncWrap { free(key_); key_ = nullptr; keylen_ = 0; - - ClearWrap(object()); } uv_work_t* work_req() { @@ -4831,11 +4828,6 @@ class RandomBytesRequest : public AsyncWrap { size_(size), data_(data), free_mode_(free_mode) { - Wrap(object, this); - } - - ~RandomBytesRequest() override { - ClearWrap(object()); } uv_work_t* work_req() { diff --git a/src/node_crypto.h b/src/node_crypto.h index df7f47c82ab159..b3b91b30396c4a 100644 --- a/src/node_crypto.h +++ b/src/node_crypto.h @@ -175,7 +175,7 @@ class SecureContext : public BaseObject { ctx_(nullptr), cert_(nullptr), issuer_(nullptr) { - MakeWeak(this); + MakeWeak(); env->isolate()->AdjustAmountOfExternalAllocatedMemory(kExternalSize); } @@ -401,7 +401,7 @@ class CipherBase : public BaseObject { auth_tag_set_(false), auth_tag_len_(0), pending_auth_failed_(false) { - MakeWeak(this); + MakeWeak(); } private: @@ -432,7 +432,7 @@ class Hmac : public BaseObject { Hmac(Environment* env, v8::Local wrap) : BaseObject(env, wrap), ctx_(nullptr) { - MakeWeak(this); + MakeWeak(); } private: @@ -457,7 +457,7 @@ class Hash : public BaseObject { : BaseObject(env, wrap), mdctx_(nullptr), finalized_(false) { - MakeWeak(this); + MakeWeak(); } private: @@ -512,7 +512,7 @@ class Sign : public SignBase { static void SignFinal(const v8::FunctionCallbackInfo& args); Sign(Environment* env, v8::Local wrap) : SignBase(env, wrap) { - MakeWeak(this); + MakeWeak(); } }; @@ -535,7 +535,7 @@ class Verify : public SignBase { static void VerifyFinal(const v8::FunctionCallbackInfo& args); Verify(Environment* env, v8::Local wrap) : SignBase(env, wrap) { - MakeWeak(this); + MakeWeak(); } }; @@ -603,7 +603,7 @@ class DiffieHellman : public BaseObject { initialised_(false), verifyError_(0), dh(nullptr) { - MakeWeak(this); + MakeWeak(); } private: @@ -639,7 +639,7 @@ class ECDH : public BaseObject { : BaseObject(env, wrap), key_(key), group_(EC_KEY_get0_group(key_)) { - MakeWeak(this); + MakeWeak(); CHECK_NE(group_, nullptr); } diff --git a/src/node_file.cc b/src/node_file.cc index 89c53afc5b197e..97b957eed66b31 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -99,7 +99,7 @@ FileHandle::FileHandle(Environment* env, int fd, Local obj) AsyncWrap::PROVIDER_FILEHANDLE), StreamBase(env), fd_(fd) { - MakeWeak(this); + MakeWeak(); v8::PropertyAttribute attr = static_cast(v8::ReadOnly | v8::DontDelete); object()->DefineOwnProperty(env->context(), diff --git a/src/node_file.h b/src/node_file.h index d6c8aa443c39f4..03e41097d5f12e 100644 --- a/src/node_file.h +++ b/src/node_file.h @@ -28,11 +28,6 @@ class FSReqBase : public ReqWrap { FSReqBase(Environment* env, Local req, AsyncWrap::ProviderType type) : ReqWrap(env, req, type) { - Wrap(object(), this); - } - - virtual ~FSReqBase() { - ClearWrap(object()); } void Init(const char* syscall, @@ -249,10 +244,10 @@ class FileHandle : public AsyncWrap, public StreamBase { env->fdclose_constructor_template() ->NewInstance(env->context()).ToLocalChecked(), AsyncWrap::PROVIDER_FILEHANDLECLOSEREQ) { - Wrap(object(), this); promise_.Reset(env->isolate(), promise); ref_.Reset(env->isolate(), ref); } + ~CloseReq() { uv_fs_req_cleanup(req()); promise_.Reset(); diff --git a/src/node_http2.cc b/src/node_http2.cc index cb5c14a6faa20c..3563013da3e089 100644 --- a/src/node_http2.cc +++ b/src/node_http2.cc @@ -244,11 +244,6 @@ Http2Session::Http2Settings::Http2Settings( Init(); } -Http2Session::Http2Settings::~Http2Settings() { - if (!object().IsEmpty()) - ClearWrap(object()); -} - // Generates a Buffer that contains the serialized payload of a SETTINGS // frame. This can be used, for instance, to create the Base64-encoded // content of an Http2-Settings header field. @@ -458,7 +453,7 @@ Http2Session::Http2Session(Environment* env, nghttp2_session_type type) : AsyncWrap(env, wrap, AsyncWrap::PROVIDER_HTTP2SESSION), session_type_(type) { - MakeWeak(this); + MakeWeak(); statistics_.start_time = uv_hrtime(); // Capture the configuration options for this session @@ -1668,7 +1663,7 @@ Http2Stream::Http2Stream( session_(session), id_(id), current_headers_category_(category) { - MakeWeak(this); + MakeWeak(); statistics_.start_time = uv_hrtime(); // Limit the number of header pairs @@ -2615,11 +2610,6 @@ Http2Session::Http2Ping::Http2Ping( session_(session), startTime_(uv_hrtime()) { } -Http2Session::Http2Ping::~Http2Ping() { - if (!object().IsEmpty()) - ClearWrap(object()); -} - void Http2Session::Http2Ping::Send(uint8_t* payload) { uint8_t data[8]; if (payload == nullptr) { diff --git a/src/node_http2.h b/src/node_http2.h index 8ee4fd450e578d..f4ac926bb54452 100644 --- a/src/node_http2.h +++ b/src/node_http2.h @@ -1148,7 +1148,6 @@ class Http2StreamPerformanceEntry : public PerformanceEntry { class Http2Session::Http2Ping : public AsyncWrap { public: explicit Http2Ping(Http2Session* session); - ~Http2Ping(); size_t self_size() const override { return sizeof(*this); } @@ -1169,7 +1168,6 @@ class Http2Session::Http2Settings : public AsyncWrap { public: explicit Http2Settings(Environment* env); explicit Http2Settings(Http2Session* session); - ~Http2Settings(); size_t self_size() const override { return sizeof(*this); } diff --git a/src/node_http_parser.cc b/src/node_http_parser.cc index 085f4494e3484e..d6f9b110c3af34 100644 --- a/src/node_http_parser.cc +++ b/src/node_http_parser.cc @@ -151,16 +151,10 @@ class Parser : public AsyncWrap, public StreamListener { : AsyncWrap(env, wrap, AsyncWrap::PROVIDER_HTTPPARSER), current_buffer_len_(0), current_buffer_data_(nullptr) { - Wrap(object(), this); Init(type); } - ~Parser() override { - ClearWrap(object()); - } - - size_t self_size() const override { return sizeof(*this); } diff --git a/src/node_i18n.cc b/src/node_i18n.cc index f491d2191d7b55..5dd30a254ab969 100644 --- a/src/node_i18n.cc +++ b/src/node_i18n.cc @@ -259,7 +259,7 @@ class ConverterObject : public BaseObject, Converter { BaseObject(env, wrap), Converter(converter, sub), ignoreBOM_(ignoreBOM) { - MakeWeak(this); + MakeWeak(); switch (ucnv_getType(converter)) { case UCNV_UTF8: diff --git a/src/node_internals.h b/src/node_internals.h index b8acfa63c26ecf..e5ea575ebc5981 100644 --- a/src/node_internals.h +++ b/src/node_internals.h @@ -244,9 +244,10 @@ v8::Local AddressToJS( template void GetSockOrPeerName(const v8::FunctionCallbackInfo& args) { - T* const wrap = Unwrap(args.Holder()); - if (wrap == nullptr) - return args.GetReturnValue().Set(UV_EBADF); + T* wrap; + ASSIGN_OR_RETURN_UNWRAP(&wrap, + args.Holder(), + args.GetReturnValue().Set(UV_EBADF)); CHECK(args[0]->IsObject()); sockaddr_storage storage; int addrlen = sizeof(storage); diff --git a/src/node_serdes.cc b/src/node_serdes.cc index 6ace942c29fd56..520b350199245a 100644 --- a/src/node_serdes.cc +++ b/src/node_serdes.cc @@ -86,7 +86,7 @@ class DeserializerContext : public BaseObject, SerializerContext::SerializerContext(Environment* env, Local wrap) : BaseObject(env, wrap), serializer_(env->isolate(), this) { - MakeWeak(this); + MakeWeak(); } void SerializerContext::ThrowDataCloneError(Local message) { @@ -274,7 +274,7 @@ DeserializerContext::DeserializerContext(Environment* env, deserializer_(env->isolate(), data_, length_, this) { object()->Set(env->context(), env->buffer_string(), buffer).FromJust(); - MakeWeak(this); + MakeWeak(); } MaybeLocal DeserializerContext::ReadHostObject(Isolate* isolate) { diff --git a/src/node_stat_watcher.cc b/src/node_stat_watcher.cc index 41683a0dc1d36c..a2cfb1088c9d25 100644 --- a/src/node_stat_watcher.cc +++ b/src/node_stat_watcher.cc @@ -83,8 +83,7 @@ static void Delete(uv_handle_t* handle) { StatWatcher::StatWatcher(Environment* env, Local wrap) : AsyncWrap(env, wrap, AsyncWrap::PROVIDER_STATWATCHER), watcher_(new uv_fs_poll_t) { - MakeWeak(this); - Wrap(wrap, this); + MakeWeak(); uv_fs_poll_init(env->event_loop(), watcher_); watcher_->data = static_cast(this); } @@ -191,7 +190,7 @@ void StatWatcher::Stop(const FunctionCallbackInfo& args) { void StatWatcher::Stop() { uv_fs_poll_stop(watcher_); - MakeWeak(this); + MakeWeak(); } diff --git a/src/node_trace_events.cc b/src/node_trace_events.cc index f37537d54544a2..0c0699f7be9e1f 100644 --- a/src/node_trace_events.cc +++ b/src/node_trace_events.cc @@ -37,7 +37,7 @@ class NodeCategorySet : public BaseObject { Local wrap, std::set categories) : BaseObject(env, wrap), categories_(categories) { - MakeWeak(this); + MakeWeak(); } bool enabled_ = false; diff --git a/src/node_wrap.h b/src/node_wrap.h index 843fa7151743de..67cea2e715f869 100644 --- a/src/node_wrap.h +++ b/src/node_wrap.h @@ -33,6 +33,8 @@ namespace node { +// TODO(addaleax): Use real inheritance for the JS object templates to avoid +// this unnecessary case switching. #define WITH_GENERIC_UV_STREAM(env, obj, BODY, ELSE) \ do { \ if (env->tcp_constructor_template().IsEmpty() == false && \ diff --git a/src/node_zlib.cc b/src/node_zlib.cc index 67987baf8a375d..ec447638e2ae62 100644 --- a/src/node_zlib.cc +++ b/src/node_zlib.cc @@ -89,8 +89,6 @@ class ZCtx : public AsyncWrap { refs_(0), gzip_id_bytes_read_(0), write_result_(nullptr) { - MakeWeak(this); - Wrap(wrap, this); } @@ -662,7 +660,7 @@ class ZCtx : public AsyncWrap { void Unref() { CHECK_GT(refs_, 0); if (--refs_ == 0) { - MakeWeak(this); + MakeWeak(); } } diff --git a/src/pipe_wrap.cc b/src/pipe_wrap.cc index 0116051b3b6485..da7cb9e3ab55ba 100644 --- a/src/pipe_wrap.cc +++ b/src/pipe_wrap.cc @@ -102,12 +102,7 @@ void PipeWrap::Initialize(Local target, env->set_pipe_constructor_template(t); // Create FunctionTemplate for PipeConnectWrap. - auto constructor = [](const FunctionCallbackInfo& args) { - CHECK(args.IsConstructCall()); - ClearWrap(args.This()); - }; - auto cwt = FunctionTemplate::New(env->isolate(), constructor); - cwt->InstanceTemplate()->SetInternalFieldCount(1); + auto cwt = BaseObject::MakeLazilyInitializedJSTemplate(env); AsyncWrap::AddWrapMethods(env, cwt); Local wrapString = FIXED_ONE_BYTE_STRING(env->isolate(), "PipeConnectWrap"); diff --git a/src/stream_base-inl.h b/src/stream_base-inl.h index 4f4252073d26b5..cfe0de0872df4a 100644 --- a/src/stream_base-inl.h +++ b/src/stream_base-inl.h @@ -243,12 +243,6 @@ SimpleShutdownWrap::SimpleShutdownWrap( OtherBase(stream->stream_env(), req_wrap_obj, AsyncWrap::PROVIDER_SHUTDOWNWRAP) { - Wrap(req_wrap_obj, static_cast(this)); -} - -template -SimpleShutdownWrap::~SimpleShutdownWrap() { - ClearWrap(static_cast(this)->object()); } inline ShutdownWrap* StreamBase::CreateShutdownWrap( @@ -264,12 +258,6 @@ SimpleWriteWrap::SimpleWriteWrap( OtherBase(stream->stream_env(), req_wrap_obj, AsyncWrap::PROVIDER_WRITEWRAP) { - Wrap(req_wrap_obj, static_cast(this)); -} - -template -SimpleWriteWrap::~SimpleWriteWrap() { - ClearWrap(static_cast(this)->object()); } inline WriteWrap* StreamBase::CreateWriteWrap( @@ -460,7 +448,7 @@ inline void StreamReq::ResetObject(v8::Local obj) { #ifdef DEBUG CHECK_GT(obj->InternalFieldCount(), StreamReq::kStreamReqField); #endif - ClearWrap(obj); + obj->SetAlignedPointerInInternalField(0, nullptr); // BaseObject field. obj->SetAlignedPointerInInternalField(StreamReq::kStreamReqField, nullptr); } diff --git a/src/stream_base.cc b/src/stream_base.cc index 801b7f4b2f4560..3708ffe7b65c0d 100644 --- a/src/stream_base.cc +++ b/src/stream_base.cc @@ -286,12 +286,6 @@ int StreamBase::WriteString(const FunctionCallbackInfo& args) { uv_stream_t* send_handle = nullptr; if (IsIPCPipe() && !send_handle_obj.IsEmpty()) { - // TODO(addaleax): This relies on the fact that HandleWrap comes first - // as a superclass of each individual subclass. - // There are similar assumptions in other places in the code base. - // A better idea would be having all BaseObject's internal pointers - // refer to the BaseObject* itself; this would require refactoring - // throughout the code base but makes Node rely much less on C++ quirks. HandleWrap* wrap; ASSIGN_OR_RETURN_UNWRAP(&wrap, send_handle_obj, UV_EINVAL); send_handle = reinterpret_cast(wrap->GetHandle()); diff --git a/src/stream_base.h b/src/stream_base.h index 94a091988cfcf9..b91cf7df6cf8c4 100644 --- a/src/stream_base.h +++ b/src/stream_base.h @@ -350,7 +350,6 @@ class SimpleShutdownWrap : public ShutdownWrap, public OtherBase { public: SimpleShutdownWrap(StreamBase* stream, v8::Local req_wrap_obj); - ~SimpleShutdownWrap(); AsyncWrap* GetAsyncWrap() override { return this; } size_t self_size() const override { return sizeof(*this); } @@ -361,7 +360,6 @@ class SimpleWriteWrap : public WriteWrap, public OtherBase { public: SimpleWriteWrap(StreamBase* stream, v8::Local req_wrap_obj); - ~SimpleWriteWrap(); AsyncWrap* GetAsyncWrap() override { return this; } size_t self_size() const override { return sizeof(*this) + StorageSize(); } diff --git a/src/stream_pipe.cc b/src/stream_pipe.cc index 8f0263cd9ae99b..617a0129cfea07 100644 --- a/src/stream_pipe.cc +++ b/src/stream_pipe.cc @@ -17,7 +17,7 @@ StreamPipe::StreamPipe(StreamBase* source, StreamBase* sink, Local obj) : AsyncWrap(source->stream_env(), obj, AsyncWrap::PROVIDER_STREAMPIPE) { - MakeWeak(this); + MakeWeak(); CHECK_NE(sink, nullptr); CHECK_NE(source, nullptr); diff --git a/src/tcp_wrap.cc b/src/tcp_wrap.cc index 6158a1c4a424eb..3ccd157159c287 100644 --- a/src/tcp_wrap.cc +++ b/src/tcp_wrap.cc @@ -26,7 +26,6 @@ #include "handle_wrap.h" #include "node_buffer.h" #include "node_internals.h" -#include "node_wrap.h" #include "connect_wrap.h" #include "stream_base-inl.h" #include "stream_wrap.h" @@ -117,12 +116,8 @@ void TCPWrap::Initialize(Local target, env->set_tcp_constructor_template(t); // Create FunctionTemplate for TCPConnectWrap. - auto constructor = [](const FunctionCallbackInfo& args) { - CHECK(args.IsConstructCall()); - ClearWrap(args.This()); - }; - auto cwt = FunctionTemplate::New(env->isolate(), constructor); - cwt->InstanceTemplate()->SetInternalFieldCount(1); + Local cwt = + BaseObject::MakeLazilyInitializedJSTemplate(env); AsyncWrap::AddWrapMethods(env, cwt); Local wrapString = FIXED_ONE_BYTE_STRING(env->isolate(), "TCPConnectWrap"); diff --git a/src/timer_wrap.cc b/src/timer_wrap.cc index 02c0b8166981ab..88377a3e1b88cc 100644 --- a/src/timer_wrap.cc +++ b/src/timer_wrap.cc @@ -115,7 +115,8 @@ class TimerWrap : public HandleWrap { } static void Start(const FunctionCallbackInfo& args) { - TimerWrap* wrap = Unwrap(args.Holder()); + TimerWrap* wrap; + ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); CHECK(HandleWrap::IsAlive(wrap)); @@ -125,7 +126,8 @@ class TimerWrap : public HandleWrap { } static void Stop(const FunctionCallbackInfo& args) { - TimerWrap* wrap = Unwrap(args.Holder()); + TimerWrap* wrap; + ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); CHECK(HandleWrap::IsAlive(wrap)); diff --git a/src/tls_wrap.cc b/src/tls_wrap.cc index 71adbdfc52ca36..3764e2f3c93d4c 100644 --- a/src/tls_wrap.cc +++ b/src/tls_wrap.cc @@ -68,8 +68,7 @@ TLSWrap::TLSWrap(Environment* env, shutdown_(false), cycle_depth_(0), eof_(false) { - node::Wrap(object(), this); - MakeWeak(this); + MakeWeak(); // sc comes from an Unwrap. Make sure it was assigned. CHECK_NE(sc, nullptr); @@ -873,16 +872,9 @@ void TLSWrap::Initialize(Local target, env->SetMethod(target, "wrap", TLSWrap::Wrap); - auto constructor = [](const FunctionCallbackInfo& args) { - CHECK(args.IsConstructCall()); - args.This()->SetAlignedPointerInInternalField(0, nullptr); - }; - + Local t = BaseObject::MakeLazilyInitializedJSTemplate(env); Local tlsWrapString = FIXED_ONE_BYTE_STRING(env->isolate(), "TLSWrap"); - - auto t = env->NewFunctionTemplate(constructor); - t->InstanceTemplate()->SetInternalFieldCount(1); t->SetClassName(tlsWrapString); Local get_write_queue_size = diff --git a/src/udp_wrap.cc b/src/udp_wrap.cc index e02220a8784d74..414fe07eab6da8 100644 --- a/src/udp_wrap.cc +++ b/src/udp_wrap.cc @@ -53,7 +53,6 @@ using AsyncHooks = Environment::AsyncHooks; class SendWrap : public ReqWrap { public: SendWrap(Environment* env, Local req_wrap_obj, bool have_callback); - ~SendWrap(); inline bool have_callback() const; size_t msg_size; size_t self_size() const override { return sizeof(*this); } @@ -67,12 +66,6 @@ SendWrap::SendWrap(Environment* env, bool have_callback) : ReqWrap(env, req_wrap_obj, AsyncWrap::PROVIDER_UDPSENDWRAP), have_callback_(have_callback) { - Wrap(req_wrap_obj, this); -} - - -SendWrap::~SendWrap() { - ClearWrap(object()); } @@ -81,12 +74,6 @@ inline bool SendWrap::have_callback() const { } -static void NewSendWrap(const FunctionCallbackInfo& args) { - CHECK(args.IsConstructCall()); - ClearWrap(args.This()); -} - - UDPWrap::UDPWrap(Environment* env, Local object) : HandleWrap(env, object, @@ -153,8 +140,7 @@ void UDPWrap::Initialize(Local target, // Create FunctionTemplate for SendWrap Local swt = - FunctionTemplate::New(env->isolate(), NewSendWrap); - swt->InstanceTemplate()->SetInternalFieldCount(1); + BaseObject::MakeLazilyInitializedJSTemplate(env); AsyncWrap::AddWrapMethods(env, swt); Local sendWrapString = FIXED_ONE_BYTE_STRING(env->isolate(), "SendWrap"); diff --git a/src/util-inl.h b/src/util-inl.h index d07cfea9227fbe..41a22c97efd9c0 100644 --- a/src/util-inl.h +++ b/src/util-inl.h @@ -217,25 +217,6 @@ inline v8::Local OneByteString(v8::Isolate* isolate, length).ToLocalChecked(); } -template -void Wrap(v8::Local object, TypeName* pointer) { - CHECK_EQ(false, object.IsEmpty()); - CHECK_GT(object->InternalFieldCount(), 0); - object->SetAlignedPointerInInternalField(0, pointer); -} - -void ClearWrap(v8::Local object) { - Wrap(object, nullptr); -} - -template -TypeName* Unwrap(v8::Local object) { - CHECK_EQ(false, object.IsEmpty()); - CHECK_GT(object->InternalFieldCount(), 0); - void* pointer = object->GetAlignedPointerFromInternalField(0); - return static_cast(pointer); -} - void SwapBytes16(char* data, size_t nbytes) { CHECK_EQ(nbytes % 2, 0); diff --git a/src/util.h b/src/util.h index c8bad8171e3bc1..133899008fb7ce 100644 --- a/src/util.h +++ b/src/util.h @@ -35,7 +35,6 @@ #include #include // std::function -#include // std::remove_reference namespace node { @@ -84,8 +83,6 @@ NO_RETURN void Abort(); NO_RETURN void Assert(const char* const (*args)[4]); void DumpBacktrace(FILE* fp); -template using remove_reference = std::remove_reference; - #define FIXED_ONE_BYTE_STRING(isolate, string) \ (node::OneByteString((isolate), (string), sizeof(string) - 1)) @@ -135,14 +132,6 @@ template using remove_reference = std::remove_reference; #define UNREACHABLE() ABORT() -#define ASSIGN_OR_RETURN_UNWRAP(ptr, obj, ...) \ - do { \ - *ptr = \ - Unwrap::type>(obj); \ - if (*ptr == nullptr) \ - return __VA_ARGS__; \ - } while (0) - // TAILQ-style intrusive list node. template class ListNode; @@ -250,13 +239,6 @@ inline v8::Local OneByteString(v8::Isolate* isolate, const unsigned char* data, int length = -1); -inline void Wrap(v8::Local object, void* pointer); - -inline void ClearWrap(v8::Local object); - -template -inline TypeName* Unwrap(v8::Local object); - // Swaps bytes in place. nbytes is the number of bytes to swap and must be a // multiple of the word size (checked by function). inline void SwapBytes16(char* data, size_t nbytes); diff --git a/test/cctest/test_node_postmortem_metadata.cc b/test/cctest/test_node_postmortem_metadata.cc index 335f3e85812547..f69df3ed227717 100644 --- a/test/cctest/test_node_postmortem_metadata.cc +++ b/test/cctest/test_node_postmortem_metadata.cc @@ -72,7 +72,11 @@ TEST_F(DebugSymbolsTest, BaseObjectPersistentHandle) { const Argv argv; Env env{handle_scope, argv}; - v8::Local object = v8::Object::New(isolate_); + v8::Local obj_templ = v8::ObjectTemplate::New(isolate_); + obj_templ->SetInternalFieldCount(1); + + v8::Local object = + obj_templ->NewInstance(env.context()).ToLocalChecked(); node::BaseObject obj(*env, object); auto expected = reinterpret_cast(&obj.persistent()); From d7db306d3bd65485caabff3219a7eb0932bdbc19 Mon Sep 17 00:00:00 2001 From: BeniCheni Date: Tue, 1 May 2018 19:31:28 -0400 Subject: [PATCH 116/173] doc: update examples for fs.access() PR-URL: https://github.com/nodejs/node/pull/20460 Fixes: https://github.com/nodejs/node/issues/17508 Reviewed-By: Vse Mozhet Byt Reviewed-By: Trivikram Kamat --- doc/api/fs.md | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/doc/api/fs.md b/doc/api/fs.md index 644dde050046b7..da2b263e163559 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -760,12 +760,35 @@ no effect on Windows (will behave like `fs.constants.F_OK`). The final argument, `callback`, is a callback function that is invoked with a possible error argument. If any of the accessibility checks fail, the error -argument will be an `Error` object. The following example checks if the file -`/etc/passwd` can be read and written by the current process. +argument will be an `Error` object. The following examples check if +`package.json` exists, and if it is readable or writable. ```js -fs.access('/etc/passwd', fs.constants.R_OK | fs.constants.W_OK, (err) => { - console.log(err ? 'no access!' : 'can read/write'); +const file = 'package.json'; + +// Check if the file exists in the current directory. +fs.access(file, fs.constants.F_OK, (err) => { + console.log(`${file} ${err ? 'does not exist' : 'exists'}`); +}); + +// Check if the file is readable. +fs.access(file, fs.constants.R_OK, (err) => { + console.log(`${file} ${err ? 'is not readable' : 'is readable'}`); +}); + +// Check if the file is writable. +fs.access(file, fs.constants.W_OK, (err) => { + console.log(`${file} ${err ? 'is not writable' : 'is writable'}`); +}); + +// Check if the file exists in the current directory, and if it is writable. +fs.access(file, fs.constants.F_OK | fs.constants.W_OK, (err) => { + if (err) { + console.error( + `${file} ${err.code === 'ENOENT' ? 'does not exist' : 'is read-only'}`); + } else { + console.log(`${file} exists, and it is writable`); + } }); ``` From 17dbf6c77f366ee586b3e203aca9e480a133fe5f Mon Sep 17 00:00:00 2001 From: Gabriel Schulhof Date: Fri, 27 Apr 2018 11:36:35 -0400 Subject: [PATCH 117/173] n-api: make test_error functions static PR-URL: https://github.com/nodejs/node/pull/20373/ Reviewed-By: Colin Ihrig Reviewed-By: Michael Dawson --- test/addons-napi/test_error/test_error.c | 30 ++++++++++++------------ 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/test/addons-napi/test_error/test_error.c b/test/addons-napi/test_error/test_error.c index c9ac7a425fae76..52a9ac7956954e 100644 --- a/test/addons-napi/test_error/test_error.c +++ b/test/addons-napi/test_error/test_error.c @@ -1,7 +1,7 @@ #include #include "../common.h" -napi_value checkError(napi_env env, napi_callback_info info) { +static napi_value checkError(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -15,7 +15,7 @@ napi_value checkError(napi_env env, napi_callback_info info) { return result; } -napi_value throwExistingError(napi_env env, napi_callback_info info) { +static napi_value throwExistingError(napi_env env, napi_callback_info info) { napi_value message; napi_value error; NAPI_CALL(env, napi_create_string_utf8( @@ -25,34 +25,34 @@ napi_value throwExistingError(napi_env env, napi_callback_info info) { return NULL; } -napi_value throwError(napi_env env, napi_callback_info info) { +static napi_value throwError(napi_env env, napi_callback_info info) { NAPI_CALL(env, napi_throw_error(env, NULL, "error")); return NULL; } -napi_value throwRangeError(napi_env env, napi_callback_info info) { +static napi_value throwRangeError(napi_env env, napi_callback_info info) { NAPI_CALL(env, napi_throw_range_error(env, NULL, "range error")); return NULL; } -napi_value throwTypeError(napi_env env, napi_callback_info info) { +static napi_value throwTypeError(napi_env env, napi_callback_info info) { NAPI_CALL(env, napi_throw_type_error(env, NULL, "type error")); return NULL; } -napi_value throwErrorCode(napi_env env, napi_callback_info info) { +static napi_value throwErrorCode(napi_env env, napi_callback_info info) { NAPI_CALL(env, napi_throw_error(env, "ERR_TEST_CODE", "Error [error]")); return NULL; } -napi_value throwRangeErrorCode(napi_env env, napi_callback_info info) { +static napi_value throwRangeErrorCode(napi_env env, napi_callback_info info) { NAPI_CALL(env, napi_throw_range_error(env, "ERR_TEST_CODE", "RangeError [range error]")); return NULL; } -napi_value throwTypeErrorCode(napi_env env, napi_callback_info info) { +static napi_value throwTypeErrorCode(napi_env env, napi_callback_info info) { NAPI_CALL(env, napi_throw_type_error(env, "ERR_TEST_CODE", "TypeError [type error]")); @@ -60,7 +60,7 @@ napi_value throwTypeErrorCode(napi_env env, napi_callback_info info) { } -napi_value createError(napi_env env, napi_callback_info info) { +static napi_value createError(napi_env env, napi_callback_info info) { napi_value result; napi_value message; NAPI_CALL(env, napi_create_string_utf8( @@ -69,7 +69,7 @@ napi_value createError(napi_env env, napi_callback_info info) { return result; } -napi_value createRangeError(napi_env env, napi_callback_info info) { +static napi_value createRangeError(napi_env env, napi_callback_info info) { napi_value result; napi_value message; NAPI_CALL(env, napi_create_string_utf8( @@ -78,7 +78,7 @@ napi_value createRangeError(napi_env env, napi_callback_info info) { return result; } -napi_value createTypeError(napi_env env, napi_callback_info info) { +static napi_value createTypeError(napi_env env, napi_callback_info info) { napi_value result; napi_value message; NAPI_CALL(env, napi_create_string_utf8( @@ -87,7 +87,7 @@ napi_value createTypeError(napi_env env, napi_callback_info info) { return result; } -napi_value createErrorCode(napi_env env, napi_callback_info info) { +static napi_value createErrorCode(napi_env env, napi_callback_info info) { napi_value result; napi_value message; napi_value code; @@ -99,7 +99,7 @@ napi_value createErrorCode(napi_env env, napi_callback_info info) { return result; } -napi_value createRangeErrorCode(napi_env env, napi_callback_info info) { +static napi_value createRangeErrorCode(napi_env env, napi_callback_info info) { napi_value result; napi_value message; napi_value code; @@ -113,7 +113,7 @@ napi_value createRangeErrorCode(napi_env env, napi_callback_info info) { return result; } -napi_value createTypeErrorCode(napi_env env, napi_callback_info info) { +static napi_value createTypeErrorCode(napi_env env, napi_callback_info info) { napi_value result; napi_value message; napi_value code; @@ -135,7 +135,7 @@ static napi_value throwArbitrary(napi_env env, napi_callback_info info) { return NULL; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor descriptors[] = { DECLARE_NAPI_PROPERTY("checkError", checkError), DECLARE_NAPI_PROPERTY("throwExistingError", throwExistingError), From 3cf53b66c28baf127f458648fe86fb7203fa3cb1 Mon Sep 17 00:00:00 2001 From: Myles Borins Date: Wed, 2 May 2018 15:31:45 -0400 Subject: [PATCH 118/173] deps: patch V8 to 6.6.346.27 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/20480 Refs: https://github.com/v8/v8/compare/6.6.346.24...6.6.346.27 Reviewed-By: Khaidi Chu Reviewed-By: Michaël Zasso --- deps/v8/include/v8-version.h | 2 +- deps/v8/src/keys.cc | 9 +- deps/v8/src/wasm/wasm-js.cc | 87 +++++++++---------- .../mjsunit/regress/regress-crbug-831984.js | 10 +++ .../mjsunit/regress/wasm/regress-836141.js | 20 +++++ .../mjsunit/regress/wasm/regress-837417.js | 23 +++++ 6 files changed, 105 insertions(+), 46 deletions(-) create mode 100644 deps/v8/test/mjsunit/regress/regress-crbug-831984.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-836141.js create mode 100644 deps/v8/test/mjsunit/regress/wasm/regress-837417.js diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h index 68d0a359292bd7..81f014cbd4b68d 100644 --- a/deps/v8/include/v8-version.h +++ b/deps/v8/include/v8-version.h @@ -11,7 +11,7 @@ #define V8_MAJOR_VERSION 6 #define V8_MINOR_VERSION 6 #define V8_BUILD_NUMBER 346 -#define V8_PATCH_LEVEL 24 +#define V8_PATCH_LEVEL 27 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) diff --git a/deps/v8/src/keys.cc b/deps/v8/src/keys.cc index 4f59c2553caf0c..638c83f4270b95 100644 --- a/deps/v8/src/keys.cc +++ b/deps/v8/src/keys.cc @@ -77,7 +77,14 @@ void KeyAccumulator::AddKey(Handle key, AddKeyConversion convert) { Handle::cast(key)->AsArrayIndex(&index)) { key = isolate_->factory()->NewNumberFromUint(index); } - keys_ = OrderedHashSet::Add(keys(), key); + Handle new_set = OrderedHashSet::Add(keys(), key); + if (*new_set != *keys_) { + // The keys_ Set is converted directly to a FixedArray in GetKeys which can + // be left-trimmer. Hence the previous Set should not keep a pointer to the + // new one. + keys_->set(OrderedHashTableBase::kNextTableIndex, Smi::kZero); + keys_ = new_set; + } } void KeyAccumulator::AddKeys(Handle array, diff --git a/deps/v8/src/wasm/wasm-js.cc b/deps/v8/src/wasm/wasm-js.cc index dc1f690a63ac8b..915d4d9ead6b1f 100644 --- a/deps/v8/src/wasm/wasm-js.cc +++ b/deps/v8/src/wasm/wasm-js.cc @@ -330,16 +330,22 @@ MaybeLocal WebAssemblyInstantiateImpl(Isolate* isolate, i::MaybeHandle instance_object; { ScheduledErrorThrower thrower(i_isolate, "WebAssembly Instantiation"); + + // TODO(ahaas): These checks on the module should not be necessary here They + // are just a workaround for https://crbug.com/837417. + i::Handle module_obj = Utils::OpenHandle(*module); + if (!module_obj->IsWasmModuleObject()) { + thrower.TypeError("Argument 0 must be a WebAssembly.Module object"); + return {}; + } + i::MaybeHandle maybe_imports = GetValueAsImports(ffi, &thrower); if (thrower.error()) return {}; - i::Handle module_obj = - i::Handle::cast( - Utils::OpenHandle(Object::Cast(*module))); instance_object = i_isolate->wasm_engine()->SyncInstantiate( - i_isolate, &thrower, module_obj, maybe_imports, - i::MaybeHandle()); + i_isolate, &thrower, i::Handle::cast(module_obj), + maybe_imports, i::MaybeHandle()); } DCHECK_EQ(instance_object.is_null(), i_isolate->has_scheduled_exception()); @@ -347,25 +353,7 @@ MaybeLocal WebAssemblyInstantiateImpl(Isolate* isolate, return Utils::ToLocal(instance_object.ToHandleChecked()); } -// Entered as internal implementation detail of sync and async instantiate. -// args[0] *must* be a WebAssembly.Module. -void WebAssemblyInstantiateImplCallback( - const v8::FunctionCallbackInfo& args) { - DCHECK_GE(args.Length(), 1); - v8::Isolate* isolate = args.GetIsolate(); - MicrotasksScope does_not_run_microtasks(isolate, - MicrotasksScope::kDoNotRunMicrotasks); - - HandleScope scope(args.GetIsolate()); - Local module = args[0]; - Local ffi = args.Data(); - Local instance; - if (WebAssemblyInstantiateImpl(isolate, module, ffi).ToLocal(&instance)) { - args.GetReturnValue().Set(instance); - } -} - -void WebAssemblyInstantiateToPairCallback( +void WebAssemblyInstantiateCallback( const v8::FunctionCallbackInfo& args) { DCHECK_GE(args.Length(), 1); Isolate* isolate = args.GetIsolate(); @@ -454,7 +442,7 @@ void WebAssemblyInstantiateStreaming( DCHECK(!module_promise.IsEmpty()); Local data = args[1]; ASSIGN(Function, instantiate_impl, - Function::New(context, WebAssemblyInstantiateToPairCallback, data)); + Function::New(context, WebAssemblyInstantiateCallback, data)); ASSIGN(Promise, result, module_promise->Then(context, instantiate_impl)); args.GetReturnValue().Set(result); } @@ -476,10 +464,12 @@ void WebAssemblyInstantiate(const v8::FunctionCallbackInfo& args) { Local context = isolate->GetCurrentContext(); ASSIGN(Promise::Resolver, resolver, Promise::Resolver::New(context)); - Local module_promise = resolver->GetPromise(); - args.GetReturnValue().Set(module_promise); + Local promise = resolver->GetPromise(); + args.GetReturnValue().Set(promise); Local first_arg_value = args[0]; + // If args.Length < 2, this will be undefined - see FunctionCallbackInfo. + Local ffi = args[1]; i::Handle first_arg = Utils::OpenHandle(*first_arg_value); if (!first_arg->IsJSObject()) { thrower.TypeError( @@ -490,26 +480,35 @@ void WebAssemblyInstantiate(const v8::FunctionCallbackInfo& args) { return; } - FunctionCallback instantiator = nullptr; if (first_arg->IsWasmModuleObject()) { - module_promise = resolver->GetPromise(); - if (!resolver->Resolve(context, first_arg_value).IsJust()) return; - instantiator = WebAssemblyInstantiateImplCallback; - } else { - ASSIGN(Function, async_compile, Function::New(context, WebAssemblyCompile)); - ASSIGN(Value, async_compile_retval, - async_compile->Call(context, args.Holder(), 1, &first_arg_value)); - module_promise = Local::Cast(async_compile_retval); - instantiator = WebAssemblyInstantiateToPairCallback; + i::Handle module_obj = + i::Handle::cast(first_arg); + // If args.Length < 2, this will be undefined - see FunctionCallbackInfo. + i::MaybeHandle maybe_imports = + GetValueAsImports(ffi, &thrower); + + if (thrower.error()) { + auto maybe = resolver->Reject(context, Utils::ToLocal(thrower.Reify())); + CHECK_IMPLIES(!maybe.FromMaybe(false), + i_isolate->has_scheduled_exception()); + return; + } + + i_isolate->wasm_engine()->AsyncInstantiate( + i_isolate, Utils::OpenHandle(*promise), module_obj, maybe_imports); + return; } - DCHECK(!module_promise.IsEmpty()); - DCHECK_NOT_NULL(instantiator); - // If args.Length < 2, this will be undefined - see FunctionCallbackInfo. - // We'll check for that in WebAssemblyInstantiateImpl. - Local data = args[1]; + + // We did not get a WasmModuleObject as input, we first have to compile the + // input. + ASSIGN(Function, async_compile, Function::New(context, WebAssemblyCompile)); + ASSIGN(Value, async_compile_retval, + async_compile->Call(context, args.Holder(), 1, &first_arg_value)); + promise = Local::Cast(async_compile_retval); + DCHECK(!promise.IsEmpty()); ASSIGN(Function, instantiate_impl, - Function::New(context, instantiator, data)); - ASSIGN(Promise, result, module_promise->Then(context, instantiate_impl)); + Function::New(context, WebAssemblyInstantiateCallback, ffi)); + ASSIGN(Promise, result, promise->Then(context, instantiate_impl)); args.GetReturnValue().Set(result); } diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-831984.js b/deps/v8/test/mjsunit/regress/regress-crbug-831984.js new file mode 100644 index 00000000000000..c4833232c4edfd --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-831984.js @@ -0,0 +1,10 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + + +let arr = [...Array(9000)]; +for (let j = 0; j < 40; j++) { + Reflect.ownKeys(arr).shift(); + Array(64386); +} diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-836141.js b/deps/v8/test/mjsunit/regress/wasm/regress-836141.js new file mode 100644 index 00000000000000..b37dbea628de37 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-836141.js @@ -0,0 +1,20 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +load('test/mjsunit/wasm/wasm-constants.js'); +load('test/mjsunit/wasm/wasm-module-builder.js'); + +const builder = new WasmModuleBuilder(); +builder.addMemory(16, 32); +builder.addFunction("test", kSig_i_v).addBody([ + kExprI32Const, 12, // i32.const 0 +]); + +let module = new WebAssembly.Module(builder.toBuffer()); +module.then = () => { + // Use setTimeout to get out of the promise chain. + setTimeout(assertUnreachable); +}; + +WebAssembly.instantiate(module); diff --git a/deps/v8/test/mjsunit/regress/wasm/regress-837417.js b/deps/v8/test/mjsunit/regress/wasm/regress-837417.js new file mode 100644 index 00000000000000..572139fac55825 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/wasm/regress-837417.js @@ -0,0 +1,23 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +load('test/mjsunit/wasm/wasm-constants.js'); +load('test/mjsunit/wasm/wasm-module-builder.js'); + +const builder = new WasmModuleBuilder(); +builder.addMemory(16, 32); +builder.addFunction("test", kSig_i_v).addBody([ + kExprI32Const, 12, // i32.const 0 +]); + +WebAssembly.Module.prototype.then = resolve => resolve( + String.fromCharCode(null, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41)); + +// WebAssembly.instantiate should not actually throw a TypeError in this case. +// However, this is a workaround for +assertPromiseResult( + WebAssembly.instantiate(builder.toBuffer()), assertUnreachable, + exception => { + assertInstanceof(exception, TypeError); + }); From b2e8b9c473608f1b0cf0b226b9f39552735695dc Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Thu, 3 May 2018 21:51:03 -0700 Subject: [PATCH 119/173] doc: fix mkdtemp() documentation Several minor fixes to the entries for `mkdtemp()`. The most significant is that a mistaken use of `fs.mkdtemp()` is corrected to `fsPromises.mkdtemp()`. PR-URL: https://github.com/nodejs/node/pull/20512 Reviewed-By: Vse Mozhet Byt Reviewed-By: James M Snell Reviewed-By: Colin Ihrig Reviewed-By: Shingo Inoue --- doc/api/fs.md | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/doc/api/fs.md b/doc/api/fs.md index da2b263e163559..bace6d94836c23 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -2064,8 +2064,6 @@ parameter. The optional `options` argument can be a string specifying an encoding, or an object with an `encoding` property specifying the character encoding to use. -Example: - ```js fs.mkdtemp(path.join(os.tmpdir(), 'foo-'), (err, folder) => { if (err) throw err; @@ -2077,7 +2075,7 @@ fs.mkdtemp(path.join(os.tmpdir(), 'foo-'), (err, folder) => { The `fs.mkdtemp()` method will append the six randomly selected characters directly to the `prefix` string. For instance, given a directory `/tmp`, if the intention is to create a temporary directory *within* `/tmp`, the `prefix` -*must* end with a trailing platform-specific path separator +must end with a trailing platform-specific path separator (`require('path').sep`). ```js @@ -4003,24 +4001,22 @@ added: v10.0.0 * `encoding` {string} **Default:** `'utf8'` * Returns: {Promise} -Creates a unique temporary directory then resolves the `Promise` with the -created folder path. A unique directory name is generated by appending six -random characters to the end of the provided `prefix`. +Creates a unique temporary directory and resolves the `Promise` with the created +folder path. A unique directory name is generated by appending six random +characters to the end of the provided `prefix`. The optional `options` argument can be a string specifying an encoding, or an object with an `encoding` property specifying the character encoding to use. -Example: - ```js fsPromises.mkdtemp(path.join(os.tmpdir(), 'foo-')) .catch(console.error); ``` -The `fs.mkdtemp()` method will append the six randomly selected characters -directly to the `prefix` string. For instance, given a directory `/tmp`, if the -intention is to create a temporary directory *within* `/tmp`, the `prefix` -*must* end with a trailing platform-specific path separator +The `fsPromises.mkdtemp()` method will append the six randomly selected +characters directly to the `prefix` string. For instance, given a directory +`/tmp`, if the intention is to create a temporary directory *within* `/tmp`, the +`prefix` must end with a trailing platform-specific path separator (`require('path').sep`). ### fsPromises.open(path, flags[, mode]) From 745e0a558331be32fca8f60d97bf7fd7c985c819 Mon Sep 17 00:00:00 2001 From: Ayush Gupta Date: Sat, 28 Apr 2018 21:21:19 +0530 Subject: [PATCH 120/173] doc: document using `domain` in REPL Document that REPL uses the `domain` module to handle uncaught exceptions, and the side effects caused by it. PR-URL: https://github.com/nodejs/node/pull/20382 Fixes: https://github.com/nodejs/node/issues/19998 Reviewed-By: Vse Mozhet Byt Reviewed-By: Anna Henningsen Reviewed-By: Trivikram Kamat Reviewed-By: Ruben Bridgewater Reviewed-By: Colin Ihrig Reviewed-By: James M Snell --- doc/api/repl.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/doc/api/repl.md b/doc/api/repl.md index b751472049a672..356d5ef47e206f 100644 --- a/doc/api/repl.md +++ b/doc/api/repl.md @@ -141,6 +141,17 @@ global or scoped variable, the input `fs` will be evaluated on-demand as > fs.createReadStream('./some/file'); ``` +#### Global Uncaught Exceptions + +The REPL uses the [`domain`][] module to catch all uncaught exceptions for that +REPL session. + +This use of the [`domain`][] module in the REPL has these side effects: + +* Uncaught exceptions do not emit the [`'uncaughtException'`][] event. +* Trying to use [`process.setUncaughtExceptionCaptureCallback()`][] throws + an [`ERR_DOMAIN_CANNOT_SET_UNCAUGHT_EXCEPTION_CAPTURE`][] error. + #### Assignment of the `_` (underscore) variable | item | +// | item | | item | | item | +// | ... | | ... | | ... | +// | item | | item | | item | +// | item | | item | | item | +// | [empty] | <-- top | item | | item | +// | [empty] | | item | | item | +// | [empty] | | [empty] | <-- top top --> | [empty] | +// +-----------+ +-----------+ +-----------+ +// +// Or, if there is only one circular buffer, it looks something +// like either of these: +// +// head tail head tail +// | | | | +// v v v v +// +-----------+ +-----------+ +// | [null] | | [null] | +// +-----------+ +-----------+ +// | [empty] | | item | +// | [empty] | | item | +// | item | <-- bottom top --> | [empty] | +// | item | | [empty] | +// | [empty] | <-- top bottom --> | item | +// | [empty] | | item | +// +-----------+ +-----------+ +// +// Adding a value means moving `top` forward by one, removing means +// moving `bottom` forward by one. After reaching the end, the queue +// wraps around. +// +// When `top === bottom` the current queue is empty and when +// `top + 1 === bottom` it's full. This wastes a single space of storage +// but allows much quicker checks. + +const FixedCircularBuffer = class FixedCircularBuffer { + constructor() { + this.bottom = 0; + this.top = 0; + this.list = new Array(kSize); + this.next = null; + } + + isEmpty() { + return this.top === this.bottom; + } + + isFull() { + return ((this.top + 1) & kMask) === this.bottom; + } + + push(data) { + this.list[this.top] = data; + this.top = (this.top + 1) & kMask; + } + + shift() { + const nextItem = this.list[this.bottom]; + if (nextItem === undefined) + return null; + this.list[this.bottom] = undefined; + this.bottom = (this.bottom + 1) & kMask; + return nextItem; + } +}; + +module.exports = class FixedQueue { + constructor() { + this.head = this.tail = new FixedCircularBuffer(); + } + + isEmpty() { + return this.head.isEmpty(); + } + + push(data) { + if (this.head.isFull()) { + // Head is full: Creates a new queue, sets the old queue's `.next` to it, + // and sets it as the new main queue. + this.head = this.head.next = new FixedCircularBuffer(); + } + this.head.push(data); + } + + shift() { + const { tail } = this; + const next = tail.shift(); + if (tail.isEmpty() && tail.next !== null) { + // If there is another queue, it forms the new tail. + this.tail = tail.next; + } + return next; + } +}; diff --git a/lib/internal/process/next_tick.js b/lib/internal/process/next_tick.js index 7a5d2f88a6d17e..dbe0ce8cdbdacf 100644 --- a/lib/internal/process/next_tick.js +++ b/lib/internal/process/next_tick.js @@ -16,6 +16,7 @@ function setupNextTick() { } = require('internal/async_hooks'); const promises = require('internal/process/promises'); const { ERR_INVALID_CALLBACK } = require('internal/errors').codes; + const FixedQueue = require('internal/fixed_queue'); const { emitPromiseRejectionWarnings } = promises; // tickInfo is used so that the C++ code in src/node.cc can @@ -31,119 +32,7 @@ function setupNextTick() { const kHasScheduled = 0; const kHasPromiseRejections = 1; - // Queue size for each tick array. Must be a power of two. - const kQueueSize = 2048; - const kQueueMask = kQueueSize - 1; - - // The next tick queue is implemented as a singly-linked list of fixed-size - // circular buffers. It looks something like this: - // - // head tail - // | | - // v v - // +-----------+ <-----\ +-----------+ <------\ +-----------+ - // | [null] | \----- | next | \------- | next | - // +-----------+ +-----------+ +-----------+ - // | tick | <-- bottom | tick | <-- bottom | [empty] | - // | tick | | tick | | [empty] | - // | tick | | tick | | [empty] | - // | tick | | tick | | [empty] | - // | tick | | tick | bottom --> | tick | - // | tick | | tick | | tick | - // | ... | | ... | | ... | - // | tick | | tick | | tick | - // | tick | | tick | | tick | - // | [empty] | <-- top | tick | | tick | - // | [empty] | | tick | | tick | - // | [empty] | | tick | | tick | - // +-----------+ +-----------+ <-- top top --> +-----------+ - // - // Or, if there is only one fixed-size queue, it looks something - // like either of these: - // - // head tail head tail - // | | | | - // v v v v - // +-----------+ +-----------+ - // | [null] | | [null] | - // +-----------+ +-----------+ - // | [empty] | | tick | - // | [empty] | | tick | - // | tick | <-- bottom top --> | [empty] | - // | tick | | [empty] | - // | [empty] | <-- top bottom --> | tick | - // | [empty] | | tick | - // +-----------+ +-----------+ - // - // Adding a value means moving `top` forward by one, removing means - // moving `bottom` forward by one. - // - // We let `bottom` and `top` wrap around, so when `top` is conceptually - // pointing to the end of the list, that means that the actual value is `0`. - // - // In particular, when `top === bottom`, this can mean *either* that the - // current queue is empty or that it is full. We can differentiate by - // checking whether an entry in the queue is empty (a.k.a. `=== undefined`). - - class FixedQueue { - constructor() { - this.bottom = 0; - this.top = 0; - this.list = new Array(kQueueSize); - this.next = null; - } - - push(data) { - this.list[this.top] = data; - this.top = (this.top + 1) & kQueueMask; - } - - shift() { - const nextItem = this.list[this.bottom]; - if (nextItem === undefined) - return null; - this.list[this.bottom] = undefined; - this.bottom = (this.bottom + 1) & kQueueMask; - return nextItem; - } - } - - var head = new FixedQueue(); - var tail = head; - - function push(data) { - if (head.bottom === head.top) { - // Either empty or full: - if (head.list[head.top] !== undefined) { - // It's full: Creates a new queue, sets the old queue's `.next` to it, - // and sets it as the new main queue. - head = head.next = new FixedQueue(); - } else { - // If the head is empty, that means that it was the only fixed-sized - // queue in existence. - DCHECK_EQ(head.next, null); - // This is the first tick object in existence, so we need to inform - // the C++ side that we do want to run `_tickCallback()`. - tickInfo[kHasScheduled] = 1; - } - } - head.push(data); - } - - function shift() { - const next = tail.shift(); - if (tail.top === tail.bottom) { // -> .shift() emptied the current queue. - if (tail.next !== null) { - // If there is another queue, it forms the new tail. - tail = tail.next; - } else { - // We've just run out of items. Let the native side know that it - // doesn't need to bother calling into JS to run the queue. - tickInfo[kHasScheduled] = 0; - } - } - return next; - } + const queue = new FixedQueue(); process.nextTick = nextTick; // Needs to be accessible from beyond this scope. @@ -152,7 +41,7 @@ function setupNextTick() { function _tickCallback() { let tock; do { - while (tock = shift()) { + while (tock = queue.shift()) { const asyncId = tock[async_id_symbol]; emitBefore(asyncId, tock[trigger_async_id_symbol]); // emitDestroy() places the async_id_symbol into an asynchronous queue @@ -175,8 +64,9 @@ function setupNextTick() { emitAfter(asyncId); } + tickInfo[kHasScheduled] = 0; runMicrotasks(); - } while (head.top !== head.bottom || emitPromiseRejectionWarnings()); + } while (!queue.isEmpty() || emitPromiseRejectionWarnings()); tickInfo[kHasPromiseRejections] = 0; } @@ -222,6 +112,8 @@ function setupNextTick() { args[i - 1] = arguments[i]; } - push(new TickObject(callback, args, getDefaultTriggerAsyncId())); + if (queue.isEmpty()) + tickInfo[kHasScheduled] = 1; + queue.push(new TickObject(callback, args, getDefaultTriggerAsyncId())); } } diff --git a/node.gyp b/node.gyp index ac3c28037e8613..1d971d76a0a690 100644 --- a/node.gyp +++ b/node.gyp @@ -101,6 +101,7 @@ 'lib/internal/constants.js', 'lib/internal/encoding.js', 'lib/internal/errors.js', + 'lib/internal/fixed_queue.js', 'lib/internal/freelist.js', 'lib/internal/fs.js', 'lib/internal/http.js', diff --git a/test/parallel/test-fixed-queue.js b/test/parallel/test-fixed-queue.js new file mode 100644 index 00000000000000..a50be1309a5ea8 --- /dev/null +++ b/test/parallel/test-fixed-queue.js @@ -0,0 +1,34 @@ +// Flags: --expose-internals +'use strict'; + +require('../common'); + +const assert = require('assert'); +const FixedQueue = require('internal/fixed_queue'); + +{ + const queue = new FixedQueue(); + assert.strictEqual(queue.head, queue.tail); + assert(queue.isEmpty()); + queue.push('a'); + assert(!queue.isEmpty()); + assert.strictEqual(queue.shift(), 'a'); + assert.strictEqual(queue.shift(), null); +} + +{ + const queue = new FixedQueue(); + for (let i = 0; i < 2047; i++) + queue.push('a'); + assert(queue.head.isFull()); + queue.push('a'); + assert(!queue.head.isFull()); + + assert.notStrictEqual(queue.head, queue.tail); + for (let i = 0; i < 2047; i++) + assert.strictEqual(queue.shift(), 'a'); + assert.strictEqual(queue.head, queue.tail); + assert(!queue.isEmpty()); + assert.strictEqual(queue.shift(), 'a'); + assert(queue.isEmpty()); +} diff --git a/test/parallel/test-next-tick-fixed-queue-regression.js b/test/parallel/test-next-tick-fixed-queue-regression.js new file mode 100644 index 00000000000000..1fe82d02b10907 --- /dev/null +++ b/test/parallel/test-next-tick-fixed-queue-regression.js @@ -0,0 +1,18 @@ +'use strict'; + +const common = require('../common'); + +// This tests a highly specific regression tied to the FixedQueue size, which +// was introduced in Node.js 9.7.0: https://github.com/nodejs/node/pull/18617 +// More specifically, a nextTick list could potentially end up not fully +// clearing in one run through if exactly 2048 ticks were added after +// microtasks were executed within the nextTick loop. + +process.nextTick(() => { + Promise.resolve(1).then(() => { + for (let i = 0; i < 2047; i++) + process.nextTick(common.mustCall()); + const immediate = setImmediate(common.mustNotCall()); + process.nextTick(common.mustCall(() => clearImmediate(immediate))); + }); +}); From 1ebec18624368285541823b54c65136df7ff6ca6 Mon Sep 17 00:00:00 2001 From: Anatoli Papirovski Date: Wed, 2 May 2018 12:49:13 +0200 Subject: [PATCH 132/173] tls: cleanup onhandshakestart callback Re-arrange and cleanup the flow of the onhandshakestart to be more clear and less repetitive. Exit early in the case of a first ever handshake for a given connection. PR-URL: https://github.com/nodejs/node/pull/20466 Reviewed-By: Ben Noordhuis Reviewed-By: Ruben Bridgewater --- lib/_tls_wrap.js | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/lib/_tls_wrap.js b/lib/_tls_wrap.js index 2e6b2e8da559db..65c684abfe89a3 100644 --- a/lib/_tls_wrap.js +++ b/lib/_tls_wrap.js @@ -62,32 +62,28 @@ const noop = () => {}; function onhandshakestart(now) { debug('onhandshakestart'); - assert(now >= this.lastHandshakeTime); + const { lastHandshakeTime } = this; + assert(now >= lastHandshakeTime); - const owner = this.owner; + this.lastHandshakeTime = now; - if ((now - this.lastHandshakeTime) >= tls.CLIENT_RENEG_WINDOW * 1000) { - this.handshakes = 0; - } + // If this is the first handshake we can skip the rest of the checks. + if (lastHandshakeTime === 0) + return; - const first = (this.lastHandshakeTime === 0); - this.lastHandshakeTime = now; - if (first) return; + if ((now - lastHandshakeTime) >= tls.CLIENT_RENEG_WINDOW * 1000) + this.handshakes = 1; + else + this.handshakes++; - if (++this.handshakes > tls.CLIENT_RENEG_LIMIT) { - // Defer the error event to the next tick. We're being called from OpenSSL's - // state machine and OpenSSL is not re-entrant. We cannot allow the user's - // callback to destroy the connection right now, it would crash and burn. - setImmediate(emitSessionAttackError, owner); + const { owner } = this; + if (this.handshakes > tls.CLIENT_RENEG_LIMIT) { + owner._emitTLSError(new ERR_TLS_SESSION_ATTACK()); + return; } - if (owner[kDisableRenegotiation] && this.handshakes > 0) { + if (owner[kDisableRenegotiation]) owner._emitTLSError(new ERR_TLS_RENEGOTIATION_DISABLED()); - } -} - -function emitSessionAttackError(socket) { - socket._emitTLSError(new ERR_TLS_SESSION_ATTACK()); } function onhandshakedone() { From 16970ffda455c189816ad1d8dac2bf6c0e153ee1 Mon Sep 17 00:00:00 2001 From: Anatoli Papirovski Date: Wed, 2 May 2018 10:17:23 +0200 Subject: [PATCH 133/173] benchmark: track exec time in next-tick-exec The next-tick-exec benchmarks were meant to track nextTick execution time but due to an error, they actually track addition and execution. PR-URL: https://github.com/nodejs/node/pull/20462 Reviewed-By: Ruben Bridgewater Reviewed-By: Rich Trott Reviewed-By: Trivikram Kamat Reviewed-By: James M Snell --- benchmark/process/next-tick-exec-args.js | 11 ++++++----- benchmark/process/next-tick-exec.js | 11 ++++++----- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/benchmark/process/next-tick-exec-args.js b/benchmark/process/next-tick-exec-args.js index 3be86cc08e177a..f5d0fb94224148 100644 --- a/benchmark/process/next-tick-exec-args.js +++ b/benchmark/process/next-tick-exec-args.js @@ -5,8 +5,11 @@ const bench = common.createBenchmark(main, { }); function main({ n }) { + function onNextTick(i) { + if (i + 1 === n) + bench.end(n); + } - bench.start(); for (var i = 0; i < n; i++) { if (i % 4 === 0) process.nextTick(onNextTick, i, true, 10, 'test'); @@ -17,8 +20,6 @@ function main({ n }) { else process.nextTick(onNextTick, i); } - function onNextTick(i) { - if (i + 1 === n) - bench.end(n); - } + + bench.start(); } diff --git a/benchmark/process/next-tick-exec.js b/benchmark/process/next-tick-exec.js index d00ee017de4bff..936b253bfaf324 100644 --- a/benchmark/process/next-tick-exec.js +++ b/benchmark/process/next-tick-exec.js @@ -5,13 +5,14 @@ const bench = common.createBenchmark(main, { }); function main({ n }) { - - bench.start(); - for (var i = 0; i < n; i++) { - process.nextTick(onNextTick, i); - } function onNextTick(i) { if (i + 1 === n) bench.end(n); } + + for (var i = 0; i < n; i++) { + process.nextTick(onNextTick, i); + } + + bench.start(); } From 880772a7ff9bb427af9def5580221f97c0009396 Mon Sep 17 00:00:00 2001 From: Gabriel Schulhof Date: Mon, 30 Apr 2018 13:54:51 -0400 Subject: [PATCH 134/173] doc: fix N-API property descriptor documentation PR-URL: https://github.com/nodejs/node/pull/20433 Reviewed-By: Colin Ihrig --- doc/api/n-api.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/doc/api/n-api.md b/doc/api/n-api.md index 12b39750223754..17958c8daf255e 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -915,8 +915,7 @@ provided by the addon: napi_value Init(napi_env env, napi_value exports) { napi_status status; napi_property_descriptor desc = - {"hello", Method, 0, 0, 0, napi_default, 0}; - if (status != napi_ok) return NULL; + {"hello", NULL, Method, NULL, NULL, NULL, napi_default, NULL}; status = napi_define_properties(env, exports, 1, &desc); if (status != napi_ok) return NULL; return exports; @@ -943,7 +942,7 @@ To define a class so that new instances can be created (often used with napi_value Init(napi_env env, napi_value exports) { napi_status status; napi_property_descriptor properties[] = { - { "value", NULL, GetValue, SetValue, 0, napi_default, 0 }, + { "value", NULL, NULL, GetValue, SetValue, NULL, napi_default, NULL }, DECLARE_NAPI_METHOD("plusOne", PlusOne), DECLARE_NAPI_METHOD("multiply", Multiply), }; @@ -2405,8 +2404,8 @@ if (status != napi_ok) return status; // Set the properties napi_property_descriptor descriptors[] = { - { "foo", NULL, 0, 0, 0, fooValue, napi_default, 0 }, - { "bar", NULL, 0, 0, 0, barValue, napi_default, 0 } + { "foo", NULL, NULL, NULL, NULL, fooValue, napi_default, NULL }, + { "bar", NULL, NULL, NULL, NULL, barValue, napi_default, NULL } } status = napi_define_properties(env, obj, From 8bd45d82128c9711e94e86a2fe47bd2fe1819c16 Mon Sep 17 00:00:00 2001 From: Shobhit Chittora Date: Thu, 3 May 2018 20:37:19 +0530 Subject: [PATCH 135/173] doc: updates crypto doc with openssl list -cipher-algorithms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/20502 Refs: https://github.com/nodejs/node/issues/20385 Reviewed-By: Tobias Nießen Reviewed-By: Trivikram Kamat Reviewed-By: James M Snell Reviewed-By: Shigeki Ohtsu --- doc/api/crypto.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/doc/api/crypto.md b/doc/api/crypto.md index 5527c5afa3c2ac..002c1c01c3adae 100644 --- a/doc/api/crypto.md +++ b/doc/api/crypto.md @@ -1334,8 +1334,9 @@ cipher in CCM mode is used (e.g. `'aes-128-ccm'`). In that case, the authentication tag in bytes, see [CCM mode][]. The `algorithm` is dependent on OpenSSL, examples are `'aes192'`, etc. On -recent OpenSSL releases, `openssl list-cipher-algorithms` will display the -available cipher algorithms. +recent OpenSSL releases, `openssl list -cipher-algorithms` +(`openssl list-cipher-algorithms` for older versions of OpenSSL) will +display the available cipher algorithms. The `password` is used to derive the cipher key and initialization vector (IV). The value must be either a `'latin1'` encoded string, a [`Buffer`][], a @@ -1381,8 +1382,9 @@ cipher in CCM mode is used (e.g. `'aes-128-ccm'`). In that case, the authentication tag in bytes, see [CCM mode][]. The `algorithm` is dependent on OpenSSL, examples are `'aes192'`, etc. On -recent OpenSSL releases, `openssl list-cipher-algorithms` will display the -available cipher algorithms. +recent OpenSSL releases, `openssl list -cipher-algorithms` +(`openssl list-cipher-algorithms` for older versions of OpenSSL) will +display the 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, @@ -1472,8 +1474,9 @@ cipher in CCM mode is used (e.g. `'aes-128-ccm'`). In that case, the authentication tag in bytes, see [CCM mode][]. The `algorithm` is dependent on OpenSSL, examples are `'aes192'`, etc. On -recent OpenSSL releases, `openssl list-cipher-algorithms` will display the -available cipher algorithms. +recent OpenSSL releases, `openssl list -cipher-algorithms` +(`openssl list-cipher-algorithms` for older versions of OpenSSL) will +display the 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, From 11091042060bc1adc278e87e7667b977a358eae3 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Thu, 3 May 2018 08:28:45 +0200 Subject: [PATCH 136/173] tls: remove sharedCreds in Server constructor This commit removes the var sharedCreds which is just reassigned to this._sharedCreds in the following line. PR-URL: https://github.com/nodejs/node/pull/20491 Reviewed-By: Luigi Pinca Reviewed-By: Colin Ihrig Reviewed-By: James M Snell Reviewed-By: Anna Henningsen Reviewed-By: Ruben Bridgewater --- lib/_tls_wrap.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/_tls_wrap.js b/lib/_tls_wrap.js index 65c684abfe89a3..d85d85752b631b 100644 --- a/lib/_tls_wrap.js +++ b/lib/_tls_wrap.js @@ -871,7 +871,7 @@ function Server(options, listener) { // Handle option defaults: this.setOptions(options); - var sharedCreds = tls.createSecureContext({ + this._sharedCreds = tls.createSecureContext({ pfx: this.pfx, key: this.key, passphrase: this.passphrase, @@ -887,7 +887,6 @@ function Server(options, listener) { crl: this.crl, sessionIdContext: this.sessionIdContext }); - this._sharedCreds = sharedCreds; this[kHandshakeTimeout] = options.handshakeTimeout || (120 * 1000); this[kSNICallback] = options.SNICallback; @@ -898,11 +897,11 @@ function Server(options, listener) { } if (this.sessionTimeout) { - sharedCreds.context.setSessionTimeout(this.sessionTimeout); + this._sharedCreds.context.setSessionTimeout(this.sessionTimeout); } if (this.ticketKeys) { - sharedCreds.context.setTicketKeys(this.ticketKeys); + this._sharedCreds.context.setTicketKeys(this.ticketKeys); } // constructor call From e25f2c9e91cc0fb55aede9f13f1cf435de02c260 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Wed, 2 May 2018 15:45:26 +0200 Subject: [PATCH 137/173] errors: remove dead code This was never falsy, since an array length can only be an integer. PR-URL: https://github.com/nodejs/node/pull/20483 Reviewed-By: James M Snell Reviewed-By: Khaidi Chu Reviewed-By: Trivikram Kamat Reviewed-By: Shingo Inoue --- lib/internal/errors.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/internal/errors.js b/lib/internal/errors.js index cc4c955cba1588..fc306e256c1f1a 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -870,7 +870,6 @@ E('ERR_INVALID_ARG_VALUE', (name, value, reason = 'is invalid') => { }, TypeError, RangeError); E('ERR_INVALID_ARRAY_LENGTH', (name, len, actual) => { - internalAssert(typeof actual === 'number', 'actual must be of type number'); return `The array "${name}" (length ${actual}) must be of length ${len}.`; }, TypeError); E('ERR_INVALID_ASYNC_ID', 'Invalid %s value: %s', RangeError); From 6acefc36ee2a0e9713345d3226963dd084e04d89 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Mon, 30 Apr 2018 15:12:57 +0200 Subject: [PATCH 138/173] http2: rename http2_state class to Http2State This commit renames the http2_state class to follow the guidelines in CPP_STYLE_GUIDE.md. PR-URL: https://github.com/nodejs/node/pull/20423 Reviewed-By: Anna Henningsen --- src/env-inl.h | 4 ++-- src/env.h | 6 +++--- src/node_http2.cc | 2 +- src/node_http2_state.h | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/env-inl.h b/src/env-inl.h index 1aa62fc18ded52..6202e50548a3ce 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -482,12 +482,12 @@ inline void Environment::set_http_parser_buffer_in_use(bool in_use) { http_parser_buffer_in_use_ = in_use; } -inline http2::http2_state* Environment::http2_state() const { +inline http2::Http2State* Environment::http2_state() const { return http2_state_.get(); } inline void Environment::set_http2_state( - std::unique_ptr buffer) { + std::unique_ptr buffer) { CHECK(!http2_state_); // Should be set only once. http2_state_ = std::move(buffer); } diff --git a/src/env.h b/src/env.h index 252151028164d2..c0d79883d0ff1c 100644 --- a/src/env.h +++ b/src/env.h @@ -643,8 +643,8 @@ class Environment { inline bool http_parser_buffer_in_use() const; inline void set_http_parser_buffer_in_use(bool in_use); - inline http2::http2_state* http2_state() const; - inline void set_http2_state(std::unique_ptr state); + inline http2::Http2State* http2_state() const; + inline void set_http2_state(std::unique_ptr state); inline AliasedBuffer* fs_stats_field_array(); @@ -831,7 +831,7 @@ class Environment { char* http_parser_buffer_; bool http_parser_buffer_in_use_ = false; - std::unique_ptr http2_state_; + std::unique_ptr http2_state_; AliasedBuffer fs_stats_field_array_; diff --git a/src/node_http2.cc b/src/node_http2.cc index 3563013da3e089..94f774e2d3506d 100644 --- a/src/node_http2.cc +++ b/src/node_http2.cc @@ -2650,7 +2650,7 @@ void Initialize(Local target, Isolate* isolate = env->isolate(); HandleScope scope(isolate); - std::unique_ptr state(new http2_state(isolate)); + std::unique_ptr state(new Http2State(isolate)); #define SET_STATE_TYPEDARRAY(name, field) \ target->Set(context, \ diff --git a/src/node_http2_state.h b/src/node_http2_state.h index ed88f068a04b16..64a0942f7ffa67 100644 --- a/src/node_http2_state.h +++ b/src/node_http2_state.h @@ -84,9 +84,9 @@ namespace http2 { IDX_SESSION_STATS_COUNT }; -class http2_state { +class Http2State { public: - explicit http2_state(v8::Isolate* isolate) : + explicit Http2State(v8::Isolate* isolate) : root_buffer( isolate, sizeof(http2_state_internal)), From 018b5ad800cc28a298d68dab33649adc1e8656e8 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Wed, 2 May 2018 08:59:35 +0200 Subject: [PATCH 139/173] doc: add snake_case section for C-like structs This commit adds a section mentioning that for C-like structs it is alright to use snake_case. PR-URL: https://github.com/nodejs/node/pull/20423 Reviewed-By: Anna Henningsen --- CPP_STYLE_GUIDE.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CPP_STYLE_GUIDE.md b/CPP_STYLE_GUIDE.md index edc5f0f12e212c..41e1f082f87751 100644 --- a/CPP_STYLE_GUIDE.md +++ b/CPP_STYLE_GUIDE.md @@ -12,6 +12,7 @@ * [CamelCase for methods, functions, and classes](#camelcase-for-methods-functions-and-classes) * [snake\_case for local variables and parameters](#snake_case-for-local-variables-and-parameters) * [snake\_case\_ for private class fields](#snake_case_-for-private-class-fields) + * [snake\_case\_ for C-like structs](#snake_case_-for-c-like-structs) * [Space after `template`](#space-after-template) * [Memory Management](#memory-management) * [Memory allocation](#memory-allocation) @@ -147,6 +148,15 @@ class Foo { }; ``` +## snake\_case\_ for C-like structs +For plain C-like structs snake_case can be used. + +```c++ +struct foo_bar { + int name; +} +``` + ## Space after `template` ```c++ From d357875ea14dbeea724251a539260004a477b9f1 Mon Sep 17 00:00:00 2001 From: Allen Yonghuang Wang Date: Mon, 30 Apr 2018 17:34:05 -0700 Subject: [PATCH 140/173] src: add public API to expose the main V8 Platform Add an API to get MultiIsolatePlatform used in node main thread. PR-URL: https://github.com/nodejs/node/pull/20447 Reviewed-By: Anna Henningsen Reviewed-By: James M Snell Reviewed-By: Ben Noordhuis Reviewed-By: Daniel Bevenius Reviewed-By: Colin Ihrig --- src/node.cc | 5 +++++ src/node.h | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/node.cc b/src/node.cc index 0472e55a5a2e10..693457d3ed0aae 100644 --- a/src/node.cc +++ b/src/node.cc @@ -4439,6 +4439,11 @@ void FreeEnvironment(Environment* env) { } +MultiIsolatePlatform* GetMainThreadMultiIsolatePlatform() { + return v8_platform.Platform(); +} + + MultiIsolatePlatform* CreatePlatform( int thread_pool_size, v8::TracingController* tracing_controller) { diff --git a/src/node.h b/src/node.h index ab5d1c120fa007..5a491c1abf5457 100644 --- a/src/node.h +++ b/src/node.h @@ -251,6 +251,11 @@ NODE_EXTERN Environment* CreateEnvironment(IsolateData* isolate_data, NODE_EXTERN void LoadEnvironment(Environment* env); NODE_EXTERN void FreeEnvironment(Environment* env); +// This returns the MultiIsolatePlatform used in the main thread of Node.js. +// If NODE_USE_V8_PLATFORM haven't been defined when Node.js was built, +// it returns nullptr. +NODE_EXTERN MultiIsolatePlatform* GetMainThreadMultiIsolatePlatform(); + NODE_EXTERN MultiIsolatePlatform* CreatePlatform( int thread_pool_size, v8::TracingController* tracing_controller); From bea4ffcc97ef3b70bf74052ee650cb77bf97803b Mon Sep 17 00:00:00 2001 From: Shobhit Chittora Date: Thu, 3 May 2018 20:16:08 +0530 Subject: [PATCH 141/173] doc: update one more command in crypto.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/20500 Refs: https://github.com/nodejs/node/pull/20400 Reviewed-By: Tobias Nießen Reviewed-By: Trivikram Kamat --- doc/api/crypto.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/api/crypto.md b/doc/api/crypto.md index 002c1c01c3adae..b98693466a8efd 100644 --- a/doc/api/crypto.md +++ b/doc/api/crypto.md @@ -1602,7 +1602,8 @@ Optional `options` argument controls stream behavior. The `algorithm` is dependent on the available algorithms supported by the version of OpenSSL on the platform. Examples are `'sha256'`, `'sha512'`, etc. -On recent releases of OpenSSL, `openssl list-message-digest-algorithms` will +On recent releases of OpenSSL, `openssl list -digest-algorithms` +(`openssl list-message-digest-algorithms` for older versions of OpenSSL) will display the available digest algorithms. The `key` is the HMAC key used to generate the cryptographic HMAC hash. From 4c4be8565595ead9cf72595470415ba03785a0c6 Mon Sep 17 00:00:00 2001 From: Brian White Date: Tue, 1 May 2018 00:29:16 -0400 Subject: [PATCH 142/173] Revert "stream: prevent 'end' to be emitted after 'error'" This reverts commit 08577906569a4c2de70ad2a861e2f8456cd8fcdd. PR-URL: https://github.com/nodejs/node/pull/20449 Fixes: https://github.com/nodejs/node/issues/20334 Reviewed-By: Luigi Pinca Reviewed-By: Matteo Collina Reviewed-By: Anna Henningsen --- lib/_stream_readable.js | 16 ++++--------- lib/_stream_writable.js | 10 -------- lib/internal/streams/destroy.js | 14 ++--------- test/parallel/test-http2-client-destroy.js | 1 + .../test-http2-client-onconnect-errors.js | 1 + ...p2-client-stream-destroy-before-connect.js | 1 + ...est-http2-compat-serverresponse-destroy.js | 2 ++ .../test-http2-max-concurrent-streams.js | 1 + .../test-http2-misused-pseudoheaders.js | 1 + .../test-http2-multi-content-length.js | 1 + .../test-http2-respond-file-fd-invalid.js | 2 +- .../test-http2-respond-nghttperrors.js | 2 +- .../test-http2-respond-with-fd-errors.js | 2 +- ...st-http2-server-shutdown-before-respond.js | 2 +- .../test-http2-server-socket-destroy.js | 1 + .../test-stream-duplex-error-write.js | 24 ------------------- test/parallel/test-stream-readable-destroy.js | 15 ------------ 17 files changed, 20 insertions(+), 76 deletions(-) delete mode 100644 test/parallel/test-stream-duplex-error-write.js diff --git a/lib/_stream_readable.js b/lib/_stream_readable.js index 31a8a11e4a0673..8073e174cc586f 100644 --- a/lib/_stream_readable.js +++ b/lib/_stream_readable.js @@ -99,9 +99,6 @@ function ReadableState(options, stream, isDuplex) { this.endEmitted = false; this.reading = false; - // Flipped if an 'error' is emitted. - this.errorEmitted = false; - // a flag to be able to tell if the event 'readable'/'data' is emitted // immediately, or on a later tick. We set this to true at first, because // any actions that shouldn't happen until "later" should generally also @@ -1072,23 +1069,20 @@ function fromList(n, state) { function endReadable(stream) { var state = stream._readableState; - debug('endReadable', state.endEmitted, state.errorEmitted); - if (!state.endEmitted && !state.errorEmitted) { + debug('endReadable', state.endEmitted); + if (!state.endEmitted) { state.ended = true; process.nextTick(endReadableNT, state, stream); } } function endReadableNT(state, stream) { - debug('endReadableNT', state.endEmitted, state.length, state.errorEmitted); + debug('endReadableNT', state.endEmitted, state.length); // Check that we didn't get one last unshift. if (!state.endEmitted && state.length === 0) { + state.endEmitted = true; stream.readable = false; - - if (!state.errorEmitted) { - state.endEmitted = true; - stream.emit('end'); - } + stream.emit('end'); } } diff --git a/lib/_stream_writable.js b/lib/_stream_writable.js index 0891f85526f132..d21daf0541d339 100644 --- a/lib/_stream_writable.js +++ b/lib/_stream_writable.js @@ -424,22 +424,12 @@ function onwriteError(stream, state, sync, er, cb) { // this can emit finish, and it will always happen // after error process.nextTick(finishMaybe, stream, state); - - // needed for duplex, fixes https://github.com/nodejs/node/issues/6083 - if (stream._readableState) { - stream._readableState.errorEmitted = true; - } stream._writableState.errorEmitted = true; stream.emit('error', er); } else { // the caller expect this to happen before if // it is async cb(er); - - // needed for duplex, fixes https://github.com/nodejs/node/issues/6083 - if (stream._readableState) { - stream._readableState.errorEmitted = true; - } stream._writableState.errorEmitted = true; stream.emit('error', er); // this can emit finish, but finish must diff --git a/lib/internal/streams/destroy.js b/lib/internal/streams/destroy.js index 2ab614e1d597da..3a0383cc3cea70 100644 --- a/lib/internal/streams/destroy.js +++ b/lib/internal/streams/destroy.js @@ -8,14 +8,10 @@ function destroy(err, cb) { this._writableState.destroyed; if (readableDestroyed || writableDestroyed) { - const readableErrored = this._readableState && - this._readableState.errorEmitted; - const writableErrored = this._writableState && - this._writableState.errorEmitted; - if (cb) { cb(err); - } else if (err && !readableErrored && !writableErrored) { + } else if (err && + (!this._writableState || !this._writableState.errorEmitted)) { process.nextTick(emitErrorNT, this, err); } return this; @@ -36,11 +32,6 @@ function destroy(err, cb) { this._destroy(err || null, (err) => { if (!cb && err) { process.nextTick(emitErrorAndCloseNT, this, err); - - if (this._readableState) { - this._readableState.errorEmitted = true; - } - if (this._writableState) { this._writableState.errorEmitted = true; } @@ -74,7 +65,6 @@ function undestroy() { this._readableState.reading = false; this._readableState.ended = false; this._readableState.endEmitted = false; - this._readableState.errorEmitted = false; } if (this._writableState) { diff --git a/test/parallel/test-http2-client-destroy.js b/test/parallel/test-http2-client-destroy.js index e641335e751287..6238363511a791 100644 --- a/test/parallel/test-http2-client-destroy.js +++ b/test/parallel/test-http2-client-destroy.js @@ -95,6 +95,7 @@ const Countdown = require('../common/countdown'); }); req.resume(); + req.on('end', common.mustCall()); req.on('close', common.mustCall(() => server.close())); })); } diff --git a/test/parallel/test-http2-client-onconnect-errors.js b/test/parallel/test-http2-client-onconnect-errors.js index f427bfb4907339..a75dc590c669a1 100644 --- a/test/parallel/test-http2-client-onconnect-errors.js +++ b/test/parallel/test-http2-client-onconnect-errors.js @@ -101,6 +101,7 @@ function runTest(test) { }); } + req.on('end', common.mustCall()); req.on('close', common.mustCall(() => { client.destroy(); diff --git a/test/parallel/test-http2-client-stream-destroy-before-connect.js b/test/parallel/test-http2-client-stream-destroy-before-connect.js index 9e81015ec58d28..d834de5d11ebe7 100644 --- a/test/parallel/test-http2-client-stream-destroy-before-connect.js +++ b/test/parallel/test-http2-client-stream-destroy-before-connect.js @@ -45,4 +45,5 @@ server.listen(0, common.mustCall(() => { req.on('response', common.mustNotCall()); req.resume(); + req.on('end', common.mustCall()); })); diff --git a/test/parallel/test-http2-compat-serverresponse-destroy.js b/test/parallel/test-http2-compat-serverresponse-destroy.js index 49822082979a01..8ee52a74ab4e81 100644 --- a/test/parallel/test-http2-compat-serverresponse-destroy.js +++ b/test/parallel/test-http2-compat-serverresponse-destroy.js @@ -63,6 +63,7 @@ server.listen(0, common.mustCall(() => { req.on('close', common.mustCall(() => countdown.dec())); req.resume(); + req.on('end', common.mustCall()); } { @@ -77,5 +78,6 @@ server.listen(0, common.mustCall(() => { req.on('close', common.mustCall(() => countdown.dec())); req.resume(); + req.on('end', common.mustCall()); } })); diff --git a/test/parallel/test-http2-max-concurrent-streams.js b/test/parallel/test-http2-max-concurrent-streams.js index 2b576700aa4e00..b270d6cc6aff31 100644 --- a/test/parallel/test-http2-max-concurrent-streams.js +++ b/test/parallel/test-http2-max-concurrent-streams.js @@ -45,6 +45,7 @@ server.listen(0, common.mustCall(() => { req.on('aborted', common.mustCall()); req.on('response', common.mustNotCall()); req.resume(); + req.on('end', common.mustCall()); req.on('close', common.mustCall(() => countdown.dec())); req.on('error', common.expectsError({ code: 'ERR_HTTP2_STREAM_ERROR', diff --git a/test/parallel/test-http2-misused-pseudoheaders.js b/test/parallel/test-http2-misused-pseudoheaders.js index 0b7becef5f6f0a..c1ae37b9a36938 100644 --- a/test/parallel/test-http2-misused-pseudoheaders.js +++ b/test/parallel/test-http2-misused-pseudoheaders.js @@ -41,6 +41,7 @@ server.listen(0, common.mustCall(() => { req.on('response', common.mustCall()); req.resume(); + req.on('end', common.mustCall()); req.on('close', common.mustCall(() => { server.close(); client.close(); diff --git a/test/parallel/test-http2-multi-content-length.js b/test/parallel/test-http2-multi-content-length.js index 908f6ecd64fea1..7d8ff4858fedbb 100644 --- a/test/parallel/test-http2-multi-content-length.js +++ b/test/parallel/test-http2-multi-content-length.js @@ -53,6 +53,7 @@ server.listen(0, common.mustCall(() => { // header to be set for non-payload bearing requests... const req = client.request({ 'content-length': 1 }); req.resume(); + req.on('end', common.mustCall()); req.on('close', common.mustCall(() => countdown.dec())); req.on('error', common.expectsError({ code: 'ERR_HTTP2_STREAM_ERROR', diff --git a/test/parallel/test-http2-respond-file-fd-invalid.js b/test/parallel/test-http2-respond-file-fd-invalid.js index 28d1c0f057dd23..21fcf790b449eb 100644 --- a/test/parallel/test-http2-respond-file-fd-invalid.js +++ b/test/parallel/test-http2-respond-file-fd-invalid.js @@ -40,7 +40,7 @@ server.listen(0, () => { req.on('response', common.mustCall()); req.on('error', common.mustCall(errorCheck)); req.on('data', common.mustNotCall()); - req.on('close', common.mustCall(() => { + req.on('end', common.mustCall(() => { assert.strictEqual(req.rstCode, NGHTTP2_INTERNAL_ERROR); client.close(); server.close(); diff --git a/test/parallel/test-http2-respond-nghttperrors.js b/test/parallel/test-http2-respond-nghttperrors.js index 4adf678b681b09..ad9eee0d59fecc 100644 --- a/test/parallel/test-http2-respond-nghttperrors.js +++ b/test/parallel/test-http2-respond-nghttperrors.js @@ -87,7 +87,7 @@ function runTest(test) { req.resume(); req.end(); - req.on('close', common.mustCall(() => { + req.on('end', common.mustCall(() => { client.close(); if (!tests.length) { diff --git a/test/parallel/test-http2-respond-with-fd-errors.js b/test/parallel/test-http2-respond-with-fd-errors.js index 7e7394d29305cc..3a671a3e36490a 100644 --- a/test/parallel/test-http2-respond-with-fd-errors.js +++ b/test/parallel/test-http2-respond-with-fd-errors.js @@ -95,7 +95,7 @@ function runTest(test) { req.resume(); req.end(); - req.on('close', common.mustCall(() => { + req.on('end', common.mustCall(() => { client.close(); if (!tests.length) { diff --git a/test/parallel/test-http2-server-shutdown-before-respond.js b/test/parallel/test-http2-server-shutdown-before-respond.js index 50b3a5572a58e6..33f224fc69a9d5 100644 --- a/test/parallel/test-http2-server-shutdown-before-respond.js +++ b/test/parallel/test-http2-server-shutdown-before-respond.js @@ -32,5 +32,5 @@ server.on('listening', common.mustCall(() => { })); req.resume(); req.on('data', common.mustNotCall()); - req.on('close', common.mustCall(() => server.close())); + req.on('end', common.mustCall(() => server.close())); })); diff --git a/test/parallel/test-http2-server-socket-destroy.js b/test/parallel/test-http2-server-socket-destroy.js index d631ef032b823b..03afc1957b8af4 100644 --- a/test/parallel/test-http2-server-socket-destroy.js +++ b/test/parallel/test-http2-server-socket-destroy.js @@ -52,4 +52,5 @@ server.on('listening', common.mustCall(() => { req.on('aborted', common.mustCall()); req.resume(); + req.on('end', common.mustCall()); })); diff --git a/test/parallel/test-stream-duplex-error-write.js b/test/parallel/test-stream-duplex-error-write.js deleted file mode 100644 index 5a80ce5c3e4989..00000000000000 --- a/test/parallel/test-stream-duplex-error-write.js +++ /dev/null @@ -1,24 +0,0 @@ -'use strict'; - -const common = require('../common'); -const { Duplex } = require('stream'); -const { strictEqual } = require('assert'); - -const duplex = new Duplex({ - write(chunk, enc, cb) { - cb(new Error('kaboom')); - }, - read() { - this.push(null); - } -}); - -duplex.on('error', common.mustCall(function() { - strictEqual(this._readableState.errorEmitted, true); - strictEqual(this._writableState.errorEmitted, true); -})); - -duplex.on('end', common.mustNotCall()); - -duplex.end('hello'); -duplex.resume(); diff --git a/test/parallel/test-stream-readable-destroy.js b/test/parallel/test-stream-readable-destroy.js index eecee04294e6fe..026aa8ca1603b8 100644 --- a/test/parallel/test-stream-readable-destroy.js +++ b/test/parallel/test-stream-readable-destroy.js @@ -189,18 +189,3 @@ const { inherits } = require('util'); read.push('hi'); read.on('data', common.mustNotCall()); } - -{ - // double error case - const read = new Readable({ - read() {} - }); - - read.on('close', common.mustCall()); - read.on('error', common.mustCall()); - - read.destroy(new Error('kaboom 1')); - read.destroy(new Error('kaboom 2')); - assert.strictEqual(read._readableState.errorEmitted, true); - assert.strictEqual(read.destroyed, true); -} From ff619d39e6f483f648f75a2220b8123ae5183e5f Mon Sep 17 00:00:00 2001 From: Yichao 'Peak' Ji Date: Thu, 3 May 2018 15:13:25 +0800 Subject: [PATCH 143/173] url: fix WHATWG host formatting error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current url.format implementation will return an invalid URL string without the host if there is a port and unicode: true. This unexpected behavior is caused by domainToUnicode, which expects a hostname instead of a host string according to node_url.cc. Adds both a fix and a test for the issue. PR-URL: https://github.com/nodejs/node/pull/20493 Reviewed-By: Michaël Zasso Reviewed-By: Colin Ihrig Reviewed-By: James M Snell Reviewed-By: Anatoli Papirovski Reviewed-By: Trivikram Kamat Reviewed-By: Joyee Cheung Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: Ruben Bridgewater Reviewed-By: Daijiro Wachi --- lib/internal/url.js | 4 +++- test/parallel/test-url-format-whatwg.js | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/internal/url.js b/lib/internal/url.js index cff94e6b7d2b5b..d9daef1524787d 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -400,7 +400,9 @@ Object.defineProperties(URL.prototype, { ret += '@'; } ret += options.unicode ? - domainToUnicode(this.host) : this.host; + domainToUnicode(this.hostname) : this.hostname; + if (ctx.port !== null) + ret += `:${ctx.port}`; } else if (ctx.scheme === 'file:') { ret += '//'; } diff --git a/test/parallel/test-url-format-whatwg.js b/test/parallel/test-url-format-whatwg.js index 26cef6063c212f..e5c3e369e80390 100644 --- a/test/parallel/test-url-format-whatwg.js +++ b/test/parallel/test-url-format-whatwg.js @@ -111,3 +111,8 @@ assert.strictEqual( url.format(myURL, { unicode: 0 }), 'http://xn--lck1c3crb1723bpq4a.com/a?a=b#c' ); + +assert.strictEqual( + url.format(new URL('http://xn--0zwm56d.com:8080/path'), { unicode: true }), + 'http://测试.com:8080/path' +); From a4d2089c76de40103e313e91b2540ae44343ad8f Mon Sep 17 00:00:00 2001 From: Vse Mozhet Byt Date: Fri, 4 May 2018 12:16:38 +0300 Subject: [PATCH 144/173] tools: remove redundant code in doc/html.js MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR reduces code by 40 lines and docs size by ~7.5 KB. Only
...
wrappers are removed from docs, no other changes are found in results. PR-URL: https://github.com/nodejs/node/pull/20514 Reviewed-By: Ruben Bridgewater Reviewed-By: Tobias Nießen Reviewed-By: Trivikram Kamat --- test/doctool/test-doctool-html.js | 6 +-- tools/doc/html.js | 64 ++++++------------------------- 2 files changed, 15 insertions(+), 55 deletions(-) diff --git a/test/doctool/test-doctool-html.js b/test/doctool/test-doctool-html.js index 91037bfd6501bc..91a18d536a6992 100644 --- a/test/doctool/test-doctool-html.js +++ b/test/doctool/test-doctool-html.js @@ -29,11 +29,11 @@ const testData = [ file: fixtures.path('order_of_end_tags_5873.md'), html: '

ClassMethod: Buffer.from(array) ' + '#

' }, { file: fixtures.path('doc_with_yaml.md'), diff --git a/tools/doc/html.js b/tools/doc/html.js index 439fc057012ca7..1bb5fa630fa8c2 100644 --- a/tools/doc/html.js +++ b/tools/doc/html.js @@ -93,7 +93,7 @@ function render(opts, cb) { filename = path.basename(filename, '.md'); parseText(lexed); - lexed = parseLists(lexed); + lexed = preprocessElements(lexed); // Generate the table of contents. // This mutates the lexed contents in-place. @@ -231,25 +231,28 @@ function parseText(lexed) { }); } -// Just update the list item text in-place. -// Lists that come right after a heading are what we're after. -function parseLists(input) { +// Preprocess stability blockquotes and YAML blocks. +function preprocessElements(input) { var state = null; - const savedState = []; - var depth = 0; const output = []; let headingIndex = -1; let heading = null; output.links = input.links; input.forEach(function(tok, index) { + if (tok.type === 'heading') { + headingIndex = index; + heading = tok; + } + if (tok.type === 'html' && common.isYAMLBlock(tok.text)) { + tok.text = parseYAML(tok.text); + } if (tok.type === 'blockquote_start') { - savedState.push(state); state = 'MAYBE_STABILITY_BQ'; return; } if (tok.type === 'blockquote_end' && state === 'MAYBE_STABILITY_BQ') { - state = savedState.pop(); + state = null; return; } if ((tok.type === 'paragraph' && state === 'MAYBE_STABILITY_BQ') || @@ -271,50 +274,7 @@ function parseLists(input) { return; } else if (state === 'MAYBE_STABILITY_BQ') { output.push({ type: 'blockquote_start' }); - state = savedState.pop(); - } - } - if (state === null || - (state === 'AFTERHEADING' && tok.type === 'heading')) { - if (tok.type === 'heading') { - headingIndex = index; - heading = tok; - state = 'AFTERHEADING'; - } - output.push(tok); - return; - } - if (state === 'AFTERHEADING') { - if (tok.type === 'list_start') { - state = 'LIST'; - if (depth === 0) { - output.push({ type: 'html', text: '
' }); - } - depth++; - output.push(tok); - return; - } - if (tok.type === 'html' && common.isYAMLBlock(tok.text)) { - tok.text = parseYAML(tok.text); - } - state = null; - output.push(tok); - return; - } - if (state === 'LIST') { - if (tok.type === 'list_start') { - depth++; - output.push(tok); - return; - } - if (tok.type === 'list_end') { - depth--; - output.push(tok); - if (depth === 0) { - state = null; - output.push({ type: 'html', text: '
' }); - } - return; + state = null; } } output.push(tok); From 98ccaead0d9375e69f31ef7047e0f7ce41849a9b Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Sat, 28 Apr 2018 17:22:19 +0200 Subject: [PATCH 145/173] doc: clearer doc-only deprecations Explicitely mention that a documentation only deprecation does not always imply that it will be staged for deprecation in a future Node.js major release. It is mainly there to tell developers that a specific API should be avoided. PR-URL: https://github.com/nodejs/node/pull/20381 Reviewed-By: Vse Mozhet Byt Reviewed-By: Anna Henningsen Reviewed-By: Trivikram Kamat Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: James M Snell --- COLLABORATOR_GUIDE.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/COLLABORATOR_GUIDE.md b/COLLABORATOR_GUIDE.md index 89c532e9d025f5..0f24dfa810d0b3 100644 --- a/COLLABORATOR_GUIDE.md +++ b/COLLABORATOR_GUIDE.md @@ -416,14 +416,15 @@ longer be used. Node.js uses three Deprecation levels: -* *Documentation-Only Deprecation* refers to elements of the Public API that are - being staged for deprecation in a future Node.js major release. An explicit - notice indicating the deprecated status is added to the API documentation - but no functional changes are implemented in the code. There will be no - runtime deprecation warnings emitted for such deprecations by default. - Documentation-only deprecations may trigger a runtime warning when Node.js - is started with the [`--pending-deprecation`][] flag or the - `NODE_PENDING_DEPRECATION=1` environment variable is set. +* *Documentation-Only Deprecation* refers to elements of the Public API that + should be avoided by developers and that might be staged for a runtime + deprecation in a future Node.js major release. An explicit notice indicating + the deprecation status is added to the API documentation but no functional + changes are implemented in the code. By default there will be no deprecation + warnings emitted for such deprecations at runtime. Documentation-only + deprecations may trigger a runtime warning when Node.js is started with the + [`--pending-deprecation`][] flag or the `NODE_PENDING_DEPRECATION=1` + environment variable is set. * *Runtime Deprecation* refers to the use of process warnings emitted at runtime the first time that a deprecated API is used. A command-line From 601f138063cf08cd7affc61df62a93d763f1c687 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Sat, 28 Apr 2018 01:45:21 +0200 Subject: [PATCH 146/173] test: fix buffer writes on mips Mips has a different way of handling NaN. This makes sure the tests pass on MIPS as well. PR-URL: https://github.com/nodejs/node/pull/20377 Reviewed-By: Richard Lau --- test/parallel/test-buffer-writedouble.js | 17 +++++++++++++---- test/parallel/test-buffer-writefloat.js | 14 ++++++++++++-- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/test/parallel/test-buffer-writedouble.js b/test/parallel/test-buffer-writedouble.js index 0dc26dbd3b23f1..8a17d536909dce 100644 --- a/test/parallel/test-buffer-writedouble.js +++ b/test/parallel/test-buffer-writedouble.js @@ -67,10 +67,19 @@ assert.strictEqual(buffer.readDoubleLE(8), -Infinity); buffer.writeDoubleBE(NaN, 0); buffer.writeDoubleLE(NaN, 8); -assert.ok(buffer.equals(new Uint8Array([ - 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x7F -]))); +// JS only knows a single NaN but there exist two platform specific +// implementations. Therefore, allow both quiet and signalling NaNs. +if (buffer[1] === 0xF7) { + assert.ok(buffer.equals(new Uint8Array([ + 0x7F, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0x7F + ]))); +} else { + assert.ok(buffer.equals(new Uint8Array([ + 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x7F + ]))); +} assert.ok(Number.isNaN(buffer.readDoubleBE(0))); assert.ok(Number.isNaN(buffer.readDoubleLE(8))); diff --git a/test/parallel/test-buffer-writefloat.js b/test/parallel/test-buffer-writefloat.js index 77dd4793e5e749..4c2c7539eaafcb 100644 --- a/test/parallel/test-buffer-writefloat.js +++ b/test/parallel/test-buffer-writefloat.js @@ -50,8 +50,18 @@ assert.strictEqual(buffer.readFloatLE(4), -Infinity); buffer.writeFloatBE(NaN, 0); buffer.writeFloatLE(NaN, 4); -assert.ok(buffer.equals( - new Uint8Array([ 0x7F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x7F ]))); + +// JS only knows a single NaN but there exist two platform specific +// implementations. Therefore, allow both quiet and signalling NaNs. +if (buffer[1] === 0xBF) { + assert.ok( + buffer.equals(new Uint8Array( + [ 0x7F, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0x7F ]))); +} else { + assert.ok( + buffer.equals(new Uint8Array( + [ 0x7F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x7F ]))); +} assert.ok(Number.isNaN(buffer.readFloatBE(0))); assert.ok(Number.isNaN(buffer.readFloatLE(4))); From 578e0546e0a42ddbd90f9039d4b8096966370e9d Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Sat, 28 Apr 2018 02:27:53 +0200 Subject: [PATCH 147/173] test: fix test-cli-node-options.js on mips The performance jit logger is not implemented on mips. PR-URL: https://github.com/nodejs/node/pull/20377 Reviewed-By: Richard Lau --- test/parallel/test-cli-node-options.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/parallel/test-cli-node-options.js b/test/parallel/test-cli-node-options.js index 8eae27b1a2a3a2..2383935f4bb7a3 100644 --- a/test/parallel/test-cli-node-options.js +++ b/test/parallel/test-cli-node-options.js @@ -32,7 +32,7 @@ if (!common.isWindows) { expect('--perf-basic-prof', 'B\n'); } -if (common.isLinux && ['arm', 'x64', 'mips'].includes(process.arch)) { +if (common.isLinux && ['arm', 'x64'].includes(process.arch)) { // PerfJitLogger is only implemented in Linux. expect('--perf-prof', 'B\n'); } From 0e8805186f4cebac14fa8c3efcd3071b78a0439f Mon Sep 17 00:00:00 2001 From: Ujjwal Sharma Date: Sun, 6 May 2018 00:31:03 +0530 Subject: [PATCH 148/173] doc: add parameters for Http2Session:stream event Add parameters for the callback for the Http2Session:stream event inline with the pattern in the rest of the documentation. Refs: https://github.com/nodejs/help/issues/877#issuecomment-381253464 PR-URL: https://github.com/nodejs/node/pull/20547 Reviewed-By: Anna Henningsen Reviewed-By: Vse Mozhet Byt Reviewed-By: Matteo Collina Reviewed-By: Trivikram Kamat --- doc/api/http2.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/doc/api/http2.md b/doc/api/http2.md index 566cdc065e171d..a8f762173404f1 100644 --- a/doc/api/http2.md +++ b/doc/api/http2.md @@ -232,10 +232,13 @@ session.on('remoteSettings', (settings) => { added: v8.4.0 --> -The `'stream'` event is emitted when a new `Http2Stream` is created. When -invoked, the handler function will receive a reference to the `Http2Stream` -object, a [HTTP/2 Headers Object][], and numeric flags associated with the -creation of the stream. +* `stream` {Http2Stream} A reference to the stream +* `headers` {HTTP/2 Headers Object} An object describing the headers +* `flags` {number} The associated numeric flags +* `rawHeaders` {Array} An array containing the raw header names followed by + their respective values. + +The `'stream'` event is emitted when a new `Http2Stream` is created. ```js const http2 = require('http2'); From 67e44bf58802f87668dc2191217e3e4e4c9c1efd Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Fri, 4 May 2018 09:51:44 -0700 Subject: [PATCH 149/173] doc: edit text for DEP0104 Make the deprecation message a bit clear and concise. PR-URL: https://github.com/nodejs/node/pull/20519 Reviewed-By: Vse Mozhet Byt Reviewed-By: Refael Ackermann Reviewed-By: Luigi Pinca Reviewed-By: Ruben Bridgewater Reviewed-By: James M Snell Reviewed-By: Trivikram Kamat --- doc/api/deprecations.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md index 10969cde64c499..34f857ae399045 100644 --- a/doc/api/deprecations.md +++ b/doc/api/deprecations.md @@ -950,11 +950,11 @@ methods in particular can be replaced by using [`util.types`][]. Type: Documentation-only (supports [`--pending-deprecation`][]) -Currently when assigning a property to [`process.env`][], the assigned value is -implicitly converted to a string if it is not a string. This behavior is -deprecated if the assigned value is not a string, boolean, or number. In the -future, such assignment may result in a thrown error. Please convert the -property to a string before assigning it to `process.env`. +When assigning a non-string property to [`process.env`][], the assigned value is +implicitly converted to a string. This behavior is deprecated if the assigned +value is not a string, boolean, or number. In the future, such assignment may +result in a thrown error. Please convert the property to a string before +assigning it to `process.env`. ### DEP0105: decipher.finaltol From adf5b80b200aa0441112e7306f5d33a2ad7eb6fa Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Fri, 4 May 2018 09:53:42 -0700 Subject: [PATCH 150/173] doc: edit text for DEP0101 Make the text slightly more concise. Fix awkward verb tense. PR-URL: https://github.com/nodejs/node/pull/20519 Reviewed-By: Vse Mozhet Byt Reviewed-By: Refael Ackermann Reviewed-By: Luigi Pinca Reviewed-By: Ruben Bridgewater Reviewed-By: James M Snell Reviewed-By: Trivikram Kamat --- doc/api/deprecations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md index 34f857ae399045..5e6d88b8654ee0 100644 --- a/doc/api/deprecations.md +++ b/doc/api/deprecations.md @@ -926,7 +926,7 @@ This was never a documented feature. Type: End-of-Life -The `--with-lttng` compile time option is removed. +The `--with-lttng` compile-time option has been removed. ### DEP0102: Using `noAssert` in Buffer#(read|write) operations. From c6e4ffa429db605e335b38b3899d4a51345086c0 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Fri, 4 May 2018 09:55:05 -0700 Subject: [PATCH 151/173] doc: edit text for DEP0012 Fix awkward verb tense. PR-URL: https://github.com/nodejs/node/pull/20519 Reviewed-By: Vse Mozhet Byt Reviewed-By: Refael Ackermann Reviewed-By: Luigi Pinca Reviewed-By: Ruben Bridgewater Reviewed-By: James M Snell Reviewed-By: Trivikram Kamat --- doc/api/deprecations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md index 5e6d88b8654ee0..5f3c1a437b36ed 100644 --- a/doc/api/deprecations.md +++ b/doc/api/deprecations.md @@ -161,7 +161,7 @@ instead. Type: End-of-Life -`Domain.dispose()` is removed. Recover from failed I/O actions +`Domain.dispose()` has been removed. Recover from failed I/O actions explicitly via error event handlers set on the domain instead. From 74c74db35eaa2dd2f5c22880ae007f19ad6e48bd Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Fri, 4 May 2018 09:56:45 -0700 Subject: [PATCH 152/173] doc: edit text for DEP0094 Make deprecation text slightly more concise and direct. PR-URL: https://github.com/nodejs/node/pull/20519 Reviewed-By: Vse Mozhet Byt Reviewed-By: Refael Ackermann Reviewed-By: Luigi Pinca Reviewed-By: Ruben Bridgewater Reviewed-By: James M Snell Reviewed-By: Trivikram Kamat --- doc/api/deprecations.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md index 5f3c1a437b36ed..c4119d8649ac13 100644 --- a/doc/api/deprecations.md +++ b/doc/api/deprecations.md @@ -861,9 +861,9 @@ and `crypto.getFips()` instead. Type: Runtime -Using `assert.fail()` with more than one argument has no benefit over writing an -individual error message. Either use `assert.fail()` with one argument or switch -to one of the other assert methods. +Using `assert.fail()` with more than one argument is deprecated. Use +`assert.fail()` with only one argument or use a different `assert` module +method. ### DEP0095: timers.enroll() From f796b0856cd80736e72d5e6009d9e6100aa99a3b Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Fri, 4 May 2018 10:00:19 -0700 Subject: [PATCH 153/173] doc: fix text for DEP0085 Fix a typographical error in deprecation text. Convert run-on sentence to two sentences (one in parentheses). PR-URL: https://github.com/nodejs/node/pull/20519 Reviewed-By: Vse Mozhet Byt Reviewed-By: Refael Ackermann Reviewed-By: Luigi Pinca Reviewed-By: Ruben Bridgewater Reviewed-By: James M Snell Reviewed-By: Trivikram Kamat --- doc/api/deprecations.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md index c4119d8649ac13..1754d4b831d638 100644 --- a/doc/api/deprecations.md +++ b/doc/api/deprecations.md @@ -798,8 +798,8 @@ code modification is necessary if that is done. Type: End-of-Life -The AsyncHooks Sensitive API was never documented and had various of minor -issues, see https://github.com/nodejs/node/issues/15572. Use the `AsyncResource` +The AsyncHooks Sensitive API was never documented and had various minor issues. +(See https://github.com/nodejs/node/issues/15572.) Use the `AsyncResource` API instead. From faa81937a500deb656748cabb6dc3eb58688b4cb Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Fri, 4 May 2018 10:03:45 -0700 Subject: [PATCH 154/173] doc: edit text for DEP0082 Make deprecation text more concise and direct. PR-URL: https://github.com/nodejs/node/pull/20519 Reviewed-By: Vse Mozhet Byt Reviewed-By: Refael Ackermann Reviewed-By: Luigi Pinca Reviewed-By: Ruben Bridgewater Reviewed-By: James M Snell Reviewed-By: Trivikram Kamat --- doc/api/deprecations.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md index 1754d4b831d638..de7c2f2a2ef17c 100644 --- a/doc/api/deprecations.md +++ b/doc/api/deprecations.md @@ -748,9 +748,8 @@ file descriptors. Type: Runtime -`REPLServer.prototype.memory()` is a function only necessary for the -internal mechanics of the `REPLServer` itself, and is therefore not -necessary in user space. +`REPLServer.prototype.memory()` is only necessary for the internal mechanics of +the `REPLServer` itself. Do not use this function. ### DEP0083: Disabling ECDH by setting ecdhCurve to false From 73f5ea9bd95d688ebdce729741ec30646c6c413a Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Fri, 4 May 2018 10:05:44 -0700 Subject: [PATCH 155/173] doc: fix minor typographical error in DEP0079 text Change `backwards compatibility` to `backward compatibility`. (It's confusing because "backwards compatible" is acceptable because "backwards" can be used as an adverb like that. However, as an adjective, as in "backward compatibility", only "backward" will do. Easiest solution: Always use "backward" because it is OK in both cases. This is all compounded by the US vs UK English thing. US English tends to favor "backward", and we standardize on US English, so that's another point in favor of "backward" over "backwards" in this context.) PR-URL: https://github.com/nodejs/node/pull/20519 Reviewed-By: Vse Mozhet Byt Reviewed-By: Refael Ackermann Reviewed-By: Luigi Pinca Reviewed-By: Ruben Bridgewater Reviewed-By: James M Snell Reviewed-By: Trivikram Kamat --- doc/api/deprecations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md index de7c2f2a2ef17c..b055f81a05c504 100644 --- a/doc/api/deprecations.md +++ b/doc/api/deprecations.md @@ -722,7 +722,7 @@ Type: Runtime Using a property named `inspect` on an object to specify a custom inspection function for [`util.inspect()`][] is deprecated. Use [`util.inspect.custom`][] -instead. For backwards compatibility with Node.js prior to version 6.4.0, both +instead. For backward compatibility with Node.js prior to version 6.4.0, both may be specified. From b2b4871c150a14c011bf1fc877c5d466ddbfb4e0 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Fri, 4 May 2018 10:11:02 -0700 Subject: [PATCH 156/173] doc: minor edit to DEP0065 Use "Node.js 6.0.0" instead of "Node.js v6.0.0". (We decided to drop "v" before version numbers to avoid confusion with the V8 JavaScript engine.) PR-URL: https://github.com/nodejs/node/pull/20519 Reviewed-By: Vse Mozhet Byt Reviewed-By: Refael Ackermann Reviewed-By: Luigi Pinca Reviewed-By: Ruben Bridgewater Reviewed-By: James M Snell Reviewed-By: Trivikram Kamat --- doc/api/deprecations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md index b055f81a05c504..37ec3e4937ffd2 100644 --- a/doc/api/deprecations.md +++ b/doc/api/deprecations.md @@ -569,7 +569,7 @@ Type: End-of-Life The `repl` module's `REPL_MODE_MAGIC` constant, used for `replMode` option, has been removed. Its behavior has been functionally identical to that of -`REPL_MODE_SLOPPY` since Node.js v6.0.0, when V8 5.0 was imported. Please use +`REPL_MODE_SLOPPY` since Node.js 6.0.0, when V8 5.0 was imported. Please use `REPL_MODE_SLOPPY` instead. The `NODE_REPL_MODE` environment variable is used to set the underlying From eed3f10615b11eaab78a7a9be5184b4fd46ae43b Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Fri, 4 May 2018 10:14:25 -0700 Subject: [PATCH 157/173] doc: edit text for DEP0013 * v10.0.0 -> Node.js 10.0.0 * Parenthetical with URL rather than "PR" as a lot of people may not know what "PR" stands for but they will know what a URL is. Plus not hiding the URL means the text is more copy/paste-able. In this particular case, "PR 12562" is not more useful or informative than https://github.com/nodejs/node/pull/12562 so just use the URL. PR-URL: https://github.com/nodejs/node/pull/20519 Reviewed-By: Vse Mozhet Byt Reviewed-By: Refael Ackermann Reviewed-By: Luigi Pinca Reviewed-By: Ruben Bridgewater Reviewed-By: James M Snell Reviewed-By: Trivikram Kamat --- doc/api/deprecations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md index 37ec3e4937ffd2..9b8998ec7593f4 100644 --- a/doc/api/deprecations.md +++ b/doc/api/deprecations.md @@ -170,7 +170,7 @@ explicitly via error event handlers set on the domain instead. Type: End-of-Life Calling an asynchronous function without a callback throws a `TypeError` -v10.0.0 onwards. Refer: [PR 12562](https://github.com/nodejs/node/pull/12562). +in Node.js 10.0.0 onwards. (See https://github.com/nodejs/node/pull/12562.) ### DEP0014: fs.read legacy String interface From 01560b69a7d0172e90bdeaa390ff5baeac23d6a8 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Fri, 4 May 2018 10:22:09 -0700 Subject: [PATCH 158/173] doc: edit text about revoking deprecations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * "un-deprecation" ಠ_ಠ -> "revoking deprecations" * "From time-to-time" -> "Occastionally" * "semver-major" and "semver-minor" are jargon that readers who don't follow our issue tracker will not know. Remove the sentence as it doesn't really impact end users. The deprecation is revoked when it is revoked. Rules around the releases where deprecations can be revoked may be added to the COLLABORATOR_GUIDE in the extensive section about deprecations there. If so, great, but let's still remove it here as having the information scattered in two places makes it likely that one will be edited to contradict the other and then it won't be clear which one is correct. * Remove unneeded italics. The italicized sentence is not hugely critical information that we desperately want users to know. Most users won't care. They will only care about the deprecation message that they are looking up at that moment. PR-URL: https://github.com/nodejs/node/pull/20519 Reviewed-By: Vse Mozhet Byt Reviewed-By: Refael Ackermann Reviewed-By: Luigi Pinca Reviewed-By: Ruben Bridgewater Reviewed-By: James M Snell Reviewed-By: Trivikram Kamat --- doc/api/deprecations.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md index 9b8998ec7593f4..2f20bc5d891fd8 100644 --- a/doc/api/deprecations.md +++ b/doc/api/deprecations.md @@ -30,12 +30,11 @@ cause an error to be thrown. An End-of-Life deprecation is used to identify code that either has been removed or will soon be removed from Node.js. -## Un-deprecation +## Revoking deprecations -From time-to-time the deprecation of an API may be reversed. Such action may -happen in either a semver-minor or semver-major release. In such situations, +Occasionally, the deprecation of an API may be reversed. In such situations, this document will be updated with information relevant to the decision. -*However, the deprecation identifier will not be modified*. +However, the deprecation identifier will not be modified. ## List of Deprecated APIs From 70586c0334e26629a08d0240b8441e9d3223d372 Mon Sep 17 00:00:00 2001 From: "Jesse W. Collins" Date: Mon, 7 May 2018 15:17:09 -0400 Subject: [PATCH 159/173] doc: excise "periodically" before "emit events" "periodically" implies regular time intervals between emitted events, but as first example, "peer connects", implies, the time intervals may be irregular or unpredictable. PR-URL: https://github.com/nodejs/node/pull/20581 Reviewed-By: Anna Henningsen Reviewed-By: Vse Mozhet Byt --- doc/api/events.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/doc/api/events.md b/doc/api/events.md index 536a87d1b46e0f..8b3cb966afd274 100644 --- a/doc/api/events.md +++ b/doc/api/events.md @@ -8,8 +8,7 @@ Much of the Node.js core API is built around an idiomatic asynchronous event-driven architecture in which certain kinds of objects (called "emitters") -periodically emit named events that cause `Function` objects ("listeners") to be -called. +emit named events that cause `Function` objects ("listeners") to be called. For instance: a [`net.Server`][] object emits an event each time a peer connects to it; a [`fs.ReadStream`][] emits an event when the file is opened; From 8148fca730bf9326301bbdeb8dfa637e65160958 Mon Sep 17 00:00:00 2001 From: Vse Mozhet Byt Date: Mon, 7 May 2018 02:08:57 +0300 Subject: [PATCH 160/173] doc: update "Who to cc..." in COLLABORATOR_GUIDE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some of the mentioned files seem to be moved or renamed. PR-URL: https://github.com/nodejs/node/pull/20564 Reviewed-By: Ruben Bridgewater Reviewed-By: Luigi Pinca Reviewed-By: Trivikram Kamat Reviewed-By: Tobias Nießen Reviewed-By: Colin Ihrig Reviewed-By: Ujjwal Sharma Reviewed-By: Michael Dawson --- COLLABORATOR_GUIDE.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/COLLABORATOR_GUIDE.md b/COLLABORATOR_GUIDE.md index 0f24dfa810d0b3..0cb03822c98947 100644 --- a/COLLABORATOR_GUIDE.md +++ b/COLLABORATOR_GUIDE.md @@ -832,7 +832,6 @@ LTS working group and the Release team. | Subsystem | Maintainers | | --- | --- | | `benchmark/*` | @nodejs/benchmarking, @mscdex | -| `bootstrap_node.js` | @nodejs/process | | `doc/*`, `*.md` | @nodejs/documentation | | `lib/assert` | @nodejs/testing | | `lib/async_hooks` | @nodejs/async\_hooks for bugs/reviews (+ @nodejs/diagnostics for API) | @@ -845,6 +844,7 @@ LTS working group and the Release team. | `lib/fs`, `src/{fs,file}` | @nodejs/fs | | `lib/{_}http{*}` | @nodejs/http | | `lib/inspector.js`, `src/inspector_*` | @nodejs/V8-inspector | +| `lib/internal/bootstrap/*` | @nodejs/process | | `lib/internal/url`, `src/node_url` | @nodejs/url | | `lib/net` | @bnoordhuis, @indutny, @nodejs/streams | | `lib/repl` | @nodejs/repl | @@ -852,13 +852,13 @@ LTS working group and the Release team. | `lib/timers` | @nodejs/timers | | `lib/util` | @nodejs/util | | `lib/zlib` | @nodejs/zlib | -| `src/async-wrap.*` | @nodejs/async\_hooks | +| `src/async_wrap.*` | @nodejs/async\_hooks | | `src/node_api.*` | @nodejs/n-api | | `src/node_crypto.*` | @nodejs/crypto | | `test/*` | @nodejs/testing | | `tools/node_modules/eslint`, `.eslintrc` | @nodejs/linting | | build | @nodejs/build | -| `src/module_wrap.*`, `lib/internal/loader/*`, `lib/internal/vm/Module.js` | @nodejs/modules | +| `src/module_wrap.*`, `lib/internal/modules/*`, `lib/internal/vm/module.js` | @nodejs/modules | | GYP | @nodejs/gyp | | performance | @nodejs/performance | | platform specific | @nodejs/platform-{aix,arm,freebsd,macos,ppc,smartos,s390,windows} | From 0b5dd102e0982ef09f190f514a8498a9934914ce Mon Sep 17 00:00:00 2001 From: cjihrig Date: Thu, 3 May 2018 14:40:48 -0400 Subject: [PATCH 161/173] fs: move fs/promises to fs.promises PR-URL: https://github.com/nodejs/node/pull/20504 Refs: https://github.com/nodejs/TSC/issues/389 Reviewed-By: Rich Trott Reviewed-By: Trivikram Kamat Reviewed-By: James M Snell Reviewed-By: Myles Borins Reviewed-By: Shingo Inoue Reviewed-By: Joyee Cheung Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: Ali Ijaz Sheikh --- benchmark/fs/bench-stat-promise.js | 2 +- doc/api/fs.md | 4 ++-- lib/fs.js | 18 +++++++++++++++++- lib/{ => internal}/fs/promises.js | 5 +---- lib/internal/{fs.js => fs/utils.js} | 0 lib/internal/modules/cjs/loader.js | 2 +- lib/internal/modules/esm/default_resolve.js | 2 +- lib/internal/process/stdio.js | 2 +- node.gyp | 4 ++-- test/parallel/test-fs-filehandle.js | 2 +- test/parallel/test-fs-open-flags.js | 2 +- ...test-fs-promises-file-handle-append-file.js | 4 ++-- .../test-fs-promises-file-handle-chmod.js | 4 ++-- .../test-fs-promises-file-handle-read.js | 4 ++-- .../test-fs-promises-file-handle-readFile.js | 4 ++-- .../test-fs-promises-file-handle-stat.js | 4 ++-- .../test-fs-promises-file-handle-write.js | 4 ++-- .../test-fs-promises-file-handle-writeFile.js | 4 ++-- test/parallel/test-fs-promises-readfile.js | 2 +- test/parallel/test-fs-promises-writefile.js | 2 +- test/parallel/test-fs-promises.js | 2 +- test/parallel/test-fs-syncwritestream.js | 4 ++-- .../test-internal-fs-syncwritestream.js | 2 +- test/parallel/test-internal-fs.js | 2 +- test/sequential/test-async-wrap-getasyncid.js | 2 +- 25 files changed, 50 insertions(+), 37 deletions(-) rename lib/{ => internal}/fs/promises.js (99%) rename lib/internal/{fs.js => fs/utils.js} (100%) diff --git a/benchmark/fs/bench-stat-promise.js b/benchmark/fs/bench-stat-promise.js index b0317455728b46..96c7058fa6218a 100644 --- a/benchmark/fs/bench-stat-promise.js +++ b/benchmark/fs/bench-stat-promise.js @@ -1,7 +1,7 @@ 'use strict'; const common = require('../common'); -const fsPromises = require('fs/promises'); +const fsPromises = require('fs').promises; const bench = common.createBenchmark(main, { n: [20e4], diff --git a/doc/api/fs.md b/doc/api/fs.md index bace6d94836c23..30d6729d48c13d 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -3382,9 +3382,9 @@ Synchronous versions of [`fs.write()`][]. Returns the number of bytes written. > Stability: 1 - Experimental -The `fs/promises` API provides an alternative set of asynchronous file system +The `fs.promises` API provides an alternative set of asynchronous file system methods that return `Promise` objects rather than using callbacks. The -API is accessible via `require('fs/promises')`. +API is accessible via `require('fs').promises`. ### class: FileHandle From e19200a66663cae0a024a7d404ec8040ac151590 Mon Sep 17 00:00:00 2001 From: Anatoli Papirovski Date: Sun, 6 May 2018 08:01:02 +0200 Subject: [PATCH 172/173] test: fix flaky http2-flow-control test PR-URL: https://github.com/nodejs/node/pull/20556 Reviewed-By: James M Snell Reviewed-By: Trivikram Kamat Reviewed-By: Matteo Collina --- test/parallel/test-http2-misbehaving-flow-control-paused.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/parallel/test-http2-misbehaving-flow-control-paused.js b/test/parallel/test-http2-misbehaving-flow-control-paused.js index 60a2cdabf847d9..26d2ed5dd244a2 100644 --- a/test/parallel/test-http2-misbehaving-flow-control-paused.js +++ b/test/parallel/test-http2-misbehaving-flow-control-paused.js @@ -70,8 +70,6 @@ server.on('stream', (stream) => { client.destroy(); })); stream.on('end', common.mustNotCall()); - stream.respond(); - stream.end('ok'); }); server.listen(0, () => { From 687867dbf02e1d1b7a09faa7849a7b8136cacfa2 Mon Sep 17 00:00:00 2001 From: Myles Borins Date: Tue, 8 May 2018 09:11:24 -0700 Subject: [PATCH 173/173] 2018-05-08, Version 10.1.0 (Current) Notable Changes: * console: - make console.table() use colored inspect (TSUYUSATO Kitsune) https://github.com/nodejs/node/pull/20510 * fs: - move fs/promises to fs.promises (cjihrig) https://github.com/nodejs/node/pull/20504 * http: - added aborted property to request (Robert Nagy) https://github.com/nodejs/node/pull/20094 * n-api: - initialize a module via a special symbol (Gabriel Schulhof) https://github.com/nodejs/node/pull/20161 * src: - add public API to expose the main V8 Platform (Allen Yonghuang Wang) https://github.com/nodejs/node/pull/20447 PR-URL: https://github.com/nodejs/node/pull/20606 --- CHANGELOG.md | 3 +- doc/api/http.md | 2 +- doc/api/http2.md | 2 +- doc/changelogs/CHANGELOG_V10.md | 192 ++++++++++++++++++++++++++++++++ src/node_version.h | 6 +- 5 files changed, 199 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8625b2026a093a..053e4381c1563c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,7 +33,8 @@ release. -10.0.0
+10.1.0
+10.0.0
9.11.1
diff --git a/doc/api/http.md b/doc/api/http.md index d98e4923bad401..74e531f9702f8a 100644 --- a/doc/api/http.md +++ b/doc/api/http.md @@ -1496,7 +1496,7 @@ Just like `'end'`, this event occurs only once per response. ### message.aborted * {boolean} diff --git a/doc/api/http2.md b/doc/api/http2.md index a8f762173404f1..d737471e8670ee 100644 --- a/doc/api/http2.md +++ b/doc/api/http2.md @@ -2424,7 +2424,7 @@ Just like `'end'`, this event occurs only once per response. #### request.aborted * {boolean} diff --git a/doc/changelogs/CHANGELOG_V10.md b/doc/changelogs/CHANGELOG_V10.md index b3d4a008203c14..48e757a5c452bc 100644 --- a/doc/changelogs/CHANGELOG_V10.md +++ b/doc/changelogs/CHANGELOG_V10.md @@ -9,6 +9,7 @@ +10.1.0
10.0.0
@@ -26,6 +27,197 @@ * [io.js](CHANGELOG_IOJS.md) * [Archive](CHANGELOG_ARCHIVE.md) + +## 2018-05-08, Version 10.1.0 (Current), @MylesBorins + +### Notable Changes + +* **console**: + - make console.table() use colored inspect (TSUYUSATO Kitsune) [#20510](https://github.com/nodejs/node/pull/20510) +* **fs**: + - move fs/promises to fs.promises (cjihrig) [#20504](https://github.com/nodejs/node/pull/20504) +* **http**: + - added aborted property to request (Robert Nagy) [#20094](https://github.com/nodejs/node/pull/20094) +* **n-api**: + - initialize a module via a special symbol (Gabriel Schulhof) [#20161](https://github.com/nodejs/node/pull/20161) +* **src**: + - add public API to expose the main V8 Platform (Allen Yonghuang Wang) [#20447](https://github.com/nodejs/node/pull/20447) + +### Commits + +* [[`7293c58d51`](https://github.com/nodejs/node/commit/7293c58d51)] - **assert**: make skipping indicator blue (Ruben Bridgewater) [#20315](https://github.com/nodejs/node/pull/20315) +* [[`f5054d3412`](https://github.com/nodejs/node/commit/f5054d3412)] - **assert**: minor error message improvements (Ruben Bridgewater) [#20315](https://github.com/nodejs/node/pull/20315) +* [[`16970ffda4`](https://github.com/nodejs/node/commit/16970ffda4)] - **benchmark**: track exec time in next-tick-exec (Anatoli Papirovski) [#20462](https://github.com/nodejs/node/pull/20462) +* [[`289e4cef3f`](https://github.com/nodejs/node/commit/289e4cef3f)] - **benchmark**: fix next-tick-depth (Anatoli Papirovski) [#20461](https://github.com/nodejs/node/pull/20461) +* [[`b0e6f10530`](https://github.com/nodejs/node/commit/b0e6f10530)] - **benchmark**: add bench for zlib gzip + gunzip cycle (Anna Henningsen) [#20034](https://github.com/nodejs/node/pull/20034) +* [[`167de1f038`](https://github.com/nodejs/node/commit/167de1f038)] - **build**: check for different deprecation signatures (Ruben Bridgewater) [#20384](https://github.com/nodejs/node/pull/20384) +* [[`348d391a71`](https://github.com/nodejs/node/commit/348d391a71)] - **build**: remove --xcode configure switch (Ben Noordhuis) [#20328](https://github.com/nodejs/node/pull/20328) +* [[`2ce4b7cb8c`](https://github.com/nodejs/node/commit/2ce4b7cb8c)] - **build**: do not depend on `cp` in `PATH` (Anna Henningsen) [#20296](https://github.com/nodejs/node/pull/20296) +* [[`c5b3459003`](https://github.com/nodejs/node/commit/c5b3459003)] - **build**: use -9 with `kill` in Makefile (Rich Trott) [#20195](https://github.com/nodejs/node/pull/20195) +* [[`b5931e1d45`](https://github.com/nodejs/node/commit/b5931e1d45)] - **child_process**: name anonymous functions (Denis Fäcke) [#20399](https://github.com/nodejs/node/pull/20399) +* [[`ec2037da12`](https://github.com/nodejs/node/commit/ec2037da12)] - **child_process**: fix leak when passing http sockets (Santiago Gimeno) [#20305](https://github.com/nodejs/node/pull/20305) +* [[`a7758c76c0`](https://github.com/nodejs/node/commit/a7758c76c0)] - **(SEMVER-MINOR)** **console**: make console.table() use colored inspect (TSUYUSATO Kitsune) [#20510](https://github.com/nodejs/node/pull/20510) +* [[`29bc735d42`](https://github.com/nodejs/node/commit/29bc735d42)] - **console**: fix console.table() display edge case (Rich Trott) [#20323](https://github.com/nodejs/node/pull/20323) +* [[`dfcf20f5fd`](https://github.com/nodejs/node/commit/dfcf20f5fd)] - **crypto**: use new OpenSSL constants in CipherBase (Tobias Nießen) [#20339](https://github.com/nodejs/node/pull/20339) +* [[`e17280e8c9`](https://github.com/nodejs/node/commit/e17280e8c9)] - **crypto**: make pbkdf2 use checkIsArrayBufferView (Daniel Bevenius) [#20251](https://github.com/nodejs/node/pull/20251) +* [[`61e93963ce`](https://github.com/nodejs/node/commit/61e93963ce)] - **crypto**: add checkIsArrayBufferView (Daniel Bevenius) [#20251](https://github.com/nodejs/node/pull/20251) +* [[`e81bb9f8a3`](https://github.com/nodejs/node/commit/e81bb9f8a3)] - **crypto**: add getIntOption function to reduce dupl (Daniel Bevenius) [#20247](https://github.com/nodejs/node/pull/20247) +* [[`391d2f830a`](https://github.com/nodejs/node/commit/391d2f830a)] - **crypto**: simplify diffiehellman getFormat function (Daniel Bevenius) [#20246](https://github.com/nodejs/node/pull/20246) +* [[`3cf53b66c2`](https://github.com/nodejs/node/commit/3cf53b66c2)] - **deps**: patch V8 to 6.6.346.27 (Myles Borins) [#20480](https://github.com/nodejs/node/pull/20480) +* [[`da8bc6ab50`](https://github.com/nodejs/node/commit/da8bc6ab50)] - **deps**: cherry-pick 76cab5f from upstream V8 (Michaël Zasso) [#20350](https://github.com/nodejs/node/pull/20350) +* [[`05ce635e9a`](https://github.com/nodejs/node/commit/05ce635e9a)] - **doc**: match console.count()/countReset() signatures (Lambdac0re) [#20599](https://github.com/nodejs/node/pull/20599) +* [[`e995ae5992`](https://github.com/nodejs/node/commit/e995ae5992)] - **doc**: clarify `this` in event listeners (daGo) [#20537](https://github.com/nodejs/node/pull/20537) +* [[`bd27a59865`](https://github.com/nodejs/node/commit/bd27a59865)] - **doc**: move tunniclm to Emeritus (Rich Trott) [#20533](https://github.com/nodejs/node/pull/20533) +* [[`ec65fe48d8`](https://github.com/nodejs/node/commit/ec65fe48d8)] - **doc**: add trace category for fs sync methods (Chin Huang) [#20526](https://github.com/nodejs/node/pull/20526) +* [[`8148fca730`](https://github.com/nodejs/node/commit/8148fca730)] - **doc**: update "Who to cc..." in COLLABORATOR\_GUIDE (Vse Mozhet Byt) [#20564](https://github.com/nodejs/node/pull/20564) +* [[`70586c0334`](https://github.com/nodejs/node/commit/70586c0334)] - **doc**: excise "periodically" before "emit events" (Jesse W. Collins) [#20581](https://github.com/nodejs/node/pull/20581) +* [[`01560b69a7`](https://github.com/nodejs/node/commit/01560b69a7)] - **doc**: edit text about revoking deprecations (Rich Trott) [#20519](https://github.com/nodejs/node/pull/20519) +* [[`eed3f10615`](https://github.com/nodejs/node/commit/eed3f10615)] - **doc**: edit text for DEP0013 (Rich Trott) [#20519](https://github.com/nodejs/node/pull/20519) +* [[`b2b4871c15`](https://github.com/nodejs/node/commit/b2b4871c15)] - **doc**: minor edit to DEP0065 (Rich Trott) [#20519](https://github.com/nodejs/node/pull/20519) +* [[`73f5ea9bd9`](https://github.com/nodejs/node/commit/73f5ea9bd9)] - **doc**: fix minor typographical error in DEP0079 text (Rich Trott) [#20519](https://github.com/nodejs/node/pull/20519) +* [[`faa81937a5`](https://github.com/nodejs/node/commit/faa81937a5)] - **doc**: edit text for DEP0082 (Rich Trott) [#20519](https://github.com/nodejs/node/pull/20519) +* [[`f796b0856c`](https://github.com/nodejs/node/commit/f796b0856c)] - **doc**: fix text for DEP0085 (Rich Trott) [#20519](https://github.com/nodejs/node/pull/20519) +* [[`74c74db35e`](https://github.com/nodejs/node/commit/74c74db35e)] - **doc**: edit text for DEP0094 (Rich Trott) [#20519](https://github.com/nodejs/node/pull/20519) +* [[`c6e4ffa429`](https://github.com/nodejs/node/commit/c6e4ffa429)] - **doc**: edit text for DEP0012 (Rich Trott) [#20519](https://github.com/nodejs/node/pull/20519) +* [[`adf5b80b20`](https://github.com/nodejs/node/commit/adf5b80b20)] - **doc**: edit text for DEP0101 (Rich Trott) [#20519](https://github.com/nodejs/node/pull/20519) +* [[`67e44bf588`](https://github.com/nodejs/node/commit/67e44bf588)] - **doc**: edit text for DEP0104 (Rich Trott) [#20519](https://github.com/nodejs/node/pull/20519) +* [[`0e8805186f`](https://github.com/nodejs/node/commit/0e8805186f)] - **doc**: add parameters for Http2Session:stream event (Ujjwal Sharma) [#20547](https://github.com/nodejs/node/pull/20547) +* [[`98ccaead0d`](https://github.com/nodejs/node/commit/98ccaead0d)] - **doc**: clearer doc-only deprecations (Ruben Bridgewater) [#20381](https://github.com/nodejs/node/pull/20381) +* [[`bea4ffcc97`](https://github.com/nodejs/node/commit/bea4ffcc97)] - **doc**: update one more command in crypto.md (Shobhit Chittora) [#20500](https://github.com/nodejs/node/pull/20500) +* [[`018b5ad800`](https://github.com/nodejs/node/commit/018b5ad800)] - **doc**: add snake\_case section for C-like structs (Daniel Bevenius) [#20423](https://github.com/nodejs/node/pull/20423) +* [[`8bd45d8212`](https://github.com/nodejs/node/commit/8bd45d8212)] - **doc**: updates crypto doc with openssl list -cipher-algorithms (Shobhit Chittora) [#20502](https://github.com/nodejs/node/pull/20502) +* [[`880772a7ff`](https://github.com/nodejs/node/commit/880772a7ff)] - **doc**: fix N-API property descriptor documentation (Gabriel Schulhof) [#20433](https://github.com/nodejs/node/pull/20433) +* [[`79e1260cd8`](https://github.com/nodejs/node/commit/79e1260cd8)] - **doc**: fix manpage warning (Jérémy Lal) [#20383](https://github.com/nodejs/node/pull/20383) +* [[`745e0a5583`](https://github.com/nodejs/node/commit/745e0a5583)] - **doc**: document using `domain` in REPL (Ayush Gupta) [#20382](https://github.com/nodejs/node/pull/20382) +* [[`b2e8b9c473`](https://github.com/nodejs/node/commit/b2e8b9c473)] - **doc**: fix mkdtemp() documentation (Rich Trott) [#20512](https://github.com/nodejs/node/pull/20512) +* [[`d7db306d3b`](https://github.com/nodejs/node/commit/d7db306d3b)] - **doc**: update examples for fs.access() (BeniCheni) [#20460](https://github.com/nodejs/node/pull/20460) +* [[`b2d6eb74d4`](https://github.com/nodejs/node/commit/b2d6eb74d4)] - **doc**: cleanup n-api.md doc (Michael Dawson) [#20430](https://github.com/nodejs/node/pull/20430) +* [[`e5537477d4`](https://github.com/nodejs/node/commit/e5537477d4)] - **doc**: update Collaborator Guide reference (Rich Trott) [#20473](https://github.com/nodejs/node/pull/20473) +* [[`391c420c3e`](https://github.com/nodejs/node/commit/391c420c3e)] - **doc**: synchronize argument names for appendFile() (Rich Trott) [#20489](https://github.com/nodejs/node/pull/20489) +* [[`8b17e7ae04`](https://github.com/nodejs/node/commit/8b17e7ae04)] - **doc**: update cli flag in crypto.md (Shobhit Chittora) [#20400](https://github.com/nodejs/node/pull/20400) +* [[`74685f1b8f`](https://github.com/nodejs/node/commit/74685f1b8f)] - **doc**: add missing periods in documentation.md (Vse Mozhet Byt) [#20469](https://github.com/nodejs/node/pull/20469) +* [[`b0ed31cf9c`](https://github.com/nodejs/node/commit/b0ed31cf9c)] - **doc**: update writing-and-running-benchmarks.md (xsbchen) [#20379](https://github.com/nodejs/node/pull/20379) +* [[`658fbdc105`](https://github.com/nodejs/node/commit/658fbdc105)] - **doc**: add http.ClientRequest maxHeadersCount (Daiki Arai) [#20361](https://github.com/nodejs/node/pull/20361) +* [[`7a769ebba8`](https://github.com/nodejs/node/commit/7a769ebba8)] - **doc**: add squash guideline to pull-requests doc (Rich Trott) [#20413](https://github.com/nodejs/node/pull/20413) +* [[`166df9e15c`](https://github.com/nodejs/node/commit/166df9e15c)] - **doc**: remove squash guideline from onboarding doc (Rich Trott) [#20413](https://github.com/nodejs/node/pull/20413) +* [[`56c27c6a2b`](https://github.com/nodejs/node/commit/56c27c6a2b)] - **doc**: add more missing backticks (Vse Mozhet Byt) [#20438](https://github.com/nodejs/node/pull/20438) +* [[`abf11550b2`](https://github.com/nodejs/node/commit/abf11550b2)] - **doc**: add missing periods or colons (Vse Mozhet Byt) [#20401](https://github.com/nodejs/node/pull/20401) +* [[`261776d6b4`](https://github.com/nodejs/node/commit/261776d6b4)] - **doc**: mitigate `marked` bug (Vse Mozhet Byt) [#20411](https://github.com/nodejs/node/pull/20411) +* [[`54e93315ed`](https://github.com/nodejs/node/commit/54e93315ed)] - **doc**: specify types of listener parameter (Vse Mozhet Byt) [#20405](https://github.com/nodejs/node/pull/20405) +* [[`fcc5492df2`](https://github.com/nodejs/node/commit/fcc5492df2)] - **doc**: clarify FileHandle text (Rich Trott) [#20450](https://github.com/nodejs/node/pull/20450) +* [[`5a839b9911`](https://github.com/nodejs/node/commit/5a839b9911)] - **doc**: remove unclear text from fs.write() (Rich Trott) [#20450](https://github.com/nodejs/node/pull/20450) +* [[`459c20c0b8`](https://github.com/nodejs/node/commit/459c20c0b8)] - **doc**: edit fs.createReadStream() highWaterMark (Rich Trott) [#20450](https://github.com/nodejs/node/pull/20450) +* [[`f36a5e3ba5`](https://github.com/nodejs/node/commit/f36a5e3ba5)] - **doc**: remove redundant table of contents for N-API (Ayush Gupta) [#20395](https://github.com/nodejs/node/pull/20395) +* [[`4bc87c185b`](https://github.com/nodejs/node/commit/4bc87c185b)] - **doc**: add parameters for settings events (Ujjwal Sharma) [#20371](https://github.com/nodejs/node/pull/20371) +* [[`d7557e111e`](https://github.com/nodejs/node/commit/d7557e111e)] - **doc**: refine napi\_get\_property\_names() doc (Gabriel Schulhof) [#20427](https://github.com/nodejs/node/pull/20427) +* [[`b61ae7fe09`](https://github.com/nodejs/node/commit/b61ae7fe09)] - **doc**: remove "has been known" tentativeness (Rich Trott) [#20412](https://github.com/nodejs/node/pull/20412) +* [[`de9d1f15de`](https://github.com/nodejs/node/commit/de9d1f15de)] - **doc**: remove parenthetical in onboarding-extras (Rich Trott) [#20393](https://github.com/nodejs/node/pull/20393) +* [[`5542a98aa4`](https://github.com/nodejs/node/commit/5542a98aa4)] - **doc**: improve process event headers (Ruben Bridgewater) [#20312](https://github.com/nodejs/node/pull/20312) +* [[`90026c3f3e`](https://github.com/nodejs/node/commit/90026c3f3e)] - **doc**: improve assert docs (Ruben Bridgewater) [#20313](https://github.com/nodejs/node/pull/20313) +* [[`57e5a3e15f`](https://github.com/nodejs/node/commit/57e5a3e15f)] - **doc**: remove redundant empty lines (Vse Mozhet Byt) [#20398](https://github.com/nodejs/node/pull/20398) +* [[`9cf3ae5bc3`](https://github.com/nodejs/node/commit/9cf3ae5bc3)] - **doc**: add missing backticks in n-api.md (Vse Mozhet Byt) [#20390](https://github.com/nodejs/node/pull/20390) +* [[`be34388a07`](https://github.com/nodejs/node/commit/be34388a07)] - **doc**: unify and dedupe returned values in timers.md (Vse Mozhet Byt) [#20310](https://github.com/nodejs/node/pull/20310) +* [[`9c11a18f70`](https://github.com/nodejs/node/commit/9c11a18f70)] - **doc**: remove eu-strip from tarball (jvelezpo) [#20304](https://github.com/nodejs/node/pull/20304) +* [[`b47044ac0f`](https://github.com/nodejs/node/commit/b47044ac0f)] - **doc**: improve parameters for Http2Session:goaway event (Ujjwal Sharma) +* [[`701f536ef4`](https://github.com/nodejs/node/commit/701f536ef4)] - **doc**: remove superfluous URL require statement (Mark Tiedemann) [#20364](https://github.com/nodejs/node/pull/20364) +* [[`d9bc9217a7`](https://github.com/nodejs/node/commit/d9bc9217a7)] - **doc**: fix typo in console.md (Daniel Hritzkiv) [#20349](https://github.com/nodejs/node/pull/20349) +* [[`cc09d7ec5b`](https://github.com/nodejs/node/commit/cc09d7ec5b)] - **doc**: remove console.table() as inspector-dependent (Rich Trott) [#20346](https://github.com/nodejs/node/pull/20346) +* [[`14188b1266`](https://github.com/nodejs/node/commit/14188b1266)] - **doc**: add Slack community to support options (Tracy) [#18191](https://github.com/nodejs/node/pull/18191) +* [[`3a3144cf04`](https://github.com/nodejs/node/commit/3a3144cf04)] - **doc**: remove os.uptime() Windows note (cjihrig) [#20308](https://github.com/nodejs/node/pull/20308) +* [[`c139d2ab8d`](https://github.com/nodejs/node/commit/c139d2ab8d)] - **doc**: fix unhandled to uncaught (Ruben Bridgewater) [#20293](https://github.com/nodejs/node/pull/20293) +* [[`7f6172b64b`](https://github.com/nodejs/node/commit/7f6172b64b)] - **doc**: improve docs for Http2Session:frameError (Ujjwal Sharma) [#20236](https://github.com/nodejs/node/pull/20236) +* [[`c9b202f817`](https://github.com/nodejs/node/commit/c9b202f817)] - **doc**: add emitter.off() to events.md (Ajido) [#20291](https://github.com/nodejs/node/pull/20291) +* [[`3bf736e569`](https://github.com/nodejs/node/commit/3bf736e569)] - **doc**: update pull request template in guide (Zachary Vacura) [#20277](https://github.com/nodejs/node/pull/20277) +* [[`171cbb1c64`](https://github.com/nodejs/node/commit/171cbb1c64)] - **doc**: fix net.Socket link inconsistencies (Hackzzila) [#20271](https://github.com/nodejs/node/pull/20271) +* [[`26525ef5ab`](https://github.com/nodejs/node/commit/26525ef5ab)] - **doc**: fix typos in doc/changelogs/CHANGELOG\_V10.md (Vse Mozhet Byt) [#20265](https://github.com/nodejs/node/pull/20265) +* [[`3bc5353110`](https://github.com/nodejs/node/commit/3bc5353110)] - **doc**: fix spelling of API name in 10.0.0 changelog (Tobias Nießen) [#20257](https://github.com/nodejs/node/pull/20257) +* [[`e25f2c9e91`](https://github.com/nodejs/node/commit/e25f2c9e91)] - **errors**: remove dead code (Ruben Bridgewater) [#20483](https://github.com/nodejs/node/pull/20483) +* [[`b89d8178b4`](https://github.com/nodejs/node/commit/b89d8178b4)] - **errors**: minor (SystemError) refactoring (Ruben Bridgewater) [#20337](https://github.com/nodejs/node/pull/20337) +* [[`58a65d6689`](https://github.com/nodejs/node/commit/58a65d6689)] - **events**: optimize condition for optimal scenario (Anatoli Papirovski) [#20452](https://github.com/nodejs/node/pull/20452) +* [[`eb483dbac5`](https://github.com/nodejs/node/commit/eb483dbac5)] - **fs**: fchmod-\>fchown in promises/lchown (Сковорода Никита Андреевич) [#20407](https://github.com/nodejs/node/pull/20407) +* [[`eb724f00a3`](https://github.com/nodejs/node/commit/eb724f00a3)] - **fs**: remove broken code in promises/write (Сковорода Никита Андреевич) [#20407](https://github.com/nodejs/node/pull/20407) +* [[`0b5dd102e0`](https://github.com/nodejs/node/commit/0b5dd102e0)] - **fs**: move fs/promises to fs.promises (cjihrig) [#20504](https://github.com/nodejs/node/pull/20504) +* [[`e45e5b809d`](https://github.com/nodejs/node/commit/e45e5b809d)] - **fs**: point isFd to isUint32 (Daniel Bevenius) [#20330](https://github.com/nodejs/node/pull/20330) +* [[`f0b2b2605a`](https://github.com/nodejs/node/commit/f0b2b2605a)] - **http**: refactor outgoing headers processing (Anatoli Papirovski) [#20250](https://github.com/nodejs/node/pull/20250) +* [[`1385ffcccf`](https://github.com/nodejs/node/commit/1385ffcccf)] - **(SEMVER-MINOR)** **http**: added aborted property to request (Robert Nagy) [#20094](https://github.com/nodejs/node/pull/20094) +* [[`6acefc36ee`](https://github.com/nodejs/node/commit/6acefc36ee)] - **http2**: rename http2\_state class to Http2State (Daniel Bevenius) [#20423](https://github.com/nodejs/node/pull/20423) +* [[`42bbaa338d`](https://github.com/nodejs/node/commit/42bbaa338d)] - **http2**: reduce require calls in http2/core (Daniel Bevenius) [#20422](https://github.com/nodejs/node/pull/20422) +* [[`e397d19e58`](https://github.com/nodejs/node/commit/e397d19e58)] - **http2**: remove unnecessary v8 qualified names (Daniel Bevenius) [#20420](https://github.com/nodejs/node/pull/20420) +* [[`b2bbc3619e`](https://github.com/nodejs/node/commit/b2bbc3619e)] - **http2**: remove unused using declarations node\_http2 (Daniel Bevenius) [#20420](https://github.com/nodejs/node/pull/20420) +* [[`7d9f1f3971`](https://github.com/nodejs/node/commit/7d9f1f3971)] - **http2**: fix ping callback (Ruben Bridgewater) [#20311](https://github.com/nodejs/node/pull/20311) +* [[`46bd86235d`](https://github.com/nodejs/node/commit/46bd86235d)] - **http2**: fix responses to long payload reqs (Anatoli Papirovski) [#20084](https://github.com/nodejs/node/pull/20084) +* [[`0b16c2482d`](https://github.com/nodejs/node/commit/0b16c2482d)] - **https**: defines maxHeadersCount in the constructor (Daiki Arai) [#20359](https://github.com/nodejs/node/pull/20359) +* [[`1490164230`](https://github.com/nodejs/node/commit/1490164230)] - **inspector**: allow concurrent inspector sessions (Eugene Ostroukhov) [#20137](https://github.com/nodejs/node/pull/20137) +* [[`375994f940`](https://github.com/nodejs/node/commit/375994f940)] - **inspector**: Use default uv\_listen backlog size (Eugene Ostroukhov) [#20254](https://github.com/nodejs/node/pull/20254) +* [[`7b8e9ca7b8`](https://github.com/nodejs/node/commit/7b8e9ca7b8)] - **lib**: expose FixedQueue internally and fix nextTick bug (Anatoli Papirovski) [#20468](https://github.com/nodejs/node/pull/20468) +* [[`b6de6a7e35`](https://github.com/nodejs/node/commit/b6de6a7e35)] - **lib**: named anonymous functions (Carrie Coxwell) [#20408](https://github.com/nodejs/node/pull/20408) +* [[`9eacd66bcb`](https://github.com/nodejs/node/commit/9eacd66bcb)] - **lib**: make sure `console` is writable (Kyle Farnung) [#20185](https://github.com/nodejs/node/pull/20185) +* [[`17dbf6c77f`](https://github.com/nodejs/node/commit/17dbf6c77f)] - **n-api**: make test\_error functions static (Gabriel Schulhof) +* [[`ad793ab93c`](https://github.com/nodejs/node/commit/ad793ab93c)] - **n-api**: test and doc napi\_throw() of a primitive (Gabriel Schulhof) [#20428](https://github.com/nodejs/node/pull/20428) +* [[`1908668826`](https://github.com/nodejs/node/commit/1908668826)] - **n-api**: document the look of napi\_external values (Gabriel Schulhof) [#20426](https://github.com/nodejs/node/pull/20426) +* [[`7ac491b8ac`](https://github.com/nodejs/node/commit/7ac491b8ac)] - **n-api**: document that native strings are copied (Gabriel Schulhof) [#20425](https://github.com/nodejs/node/pull/20425) +* [[`705d9ecd13`](https://github.com/nodejs/node/commit/705d9ecd13)] - **n-api**: remove unused Test function (Daniel Bevenius) [#20320](https://github.com/nodejs/node/pull/20320) +* [[`8d24b6ed34`](https://github.com/nodejs/node/commit/8d24b6ed34)] - **n-api**: update cli documentation (Gabriel Schulhof) [#20301](https://github.com/nodejs/node/pull/20301) +* [[`cd83df386b`](https://github.com/nodejs/node/commit/cd83df386b)] - **(SEMVER-MINOR)** **n-api**: initialize a module via a special symbol (Gabriel Schulhof) [#20161](https://github.com/nodejs/node/pull/20161) +* [[`b5c1c146f5`](https://github.com/nodejs/node/commit/b5c1c146f5)] - **n-api,test**: remove superfluous persistent (Gabriel Schulhof) [#20299](https://github.com/nodejs/node/pull/20299) +* [[`2de3343474`](https://github.com/nodejs/node/commit/2de3343474)] - **n-api,test**: make method static (Gabriel Schulhof) [#20292](https://github.com/nodejs/node/pull/20292) +* [[`b239591ed8`](https://github.com/nodejs/node/commit/b239591ed8)] - **n-api,test**: make methods static (Gabriel Schulhof) [#20243](https://github.com/nodejs/node/pull/20243) +* [[`d3a219c6ec`](https://github.com/nodejs/node/commit/d3a219c6ec)] - **repl**: add spaces to load/save messages (cjihrig) [#20536](https://github.com/nodejs/node/pull/20536) +* [[`d357875ea1`](https://github.com/nodejs/node/commit/d357875ea1)] - **(SEMVER-MINOR)** **src**: add public API to expose the main V8 Platform (Allen Yonghuang Wang) [#20447](https://github.com/nodejs/node/pull/20447) +* [[`df2cddc9c7`](https://github.com/nodejs/node/commit/df2cddc9c7)] - **src**: removed unnecessary prototypes from Environment::SetProtoMethod (Brandon Ruggles) [#20321](https://github.com/nodejs/node/pull/20321) +* [[`54f30658a3`](https://github.com/nodejs/node/commit/54f30658a3)] - **src**: fix inconsistency in extern declaration (Yang Guo) [#20436](https://github.com/nodejs/node/pull/20436) +* [[`f5d42532a3`](https://github.com/nodejs/node/commit/f5d42532a3)] - **src**: refactor `BaseObject` internal field management (Anna Henningsen) [#20455](https://github.com/nodejs/node/pull/20455) +* [[`c21a52f415`](https://github.com/nodejs/node/commit/c21a52f415)] - **src**: access `ContextifyContext\*` more directly in property cbs (Anna Henningsen) [#20455](https://github.com/nodejs/node/pull/20455) +* [[`c0f153528e`](https://github.com/nodejs/node/commit/c0f153528e)] - **src**: remove `kFlagNoShutdown` flag (Anna Henningsen) [#20388](https://github.com/nodejs/node/pull/20388) +* [[`58be6efd29`](https://github.com/nodejs/node/commit/58be6efd29)] - **src**: avoid `std::make\_unique` (Anna Henningsen) [#20386](https://github.com/nodejs/node/pull/20386) +* [[`31812edb2d`](https://github.com/nodejs/node/commit/31812edb2d)] - **src**: remove unnecessary copy operations in tracing (Anna Henningsen) [#20356](https://github.com/nodejs/node/pull/20356) +* [[`e0d2bc5cce`](https://github.com/nodejs/node/commit/e0d2bc5cce)] - **src**: improve fatal exception (Ruben Bridgewater) [#20294](https://github.com/nodejs/node/pull/20294) +* [[`44fdd36b96`](https://github.com/nodejs/node/commit/44fdd36b96)] - **src**: remove SecureContext `\_external` getter (Anna Henningsen) [#20237](https://github.com/nodejs/node/pull/20237) +* [[`81de533836`](https://github.com/nodejs/node/commit/81de533836)] - **src**: create per-isolate strings after platform setup (Ulan Degenbaev) [#20175](https://github.com/nodejs/node/pull/20175) +* [[`b5bc6bd94b`](https://github.com/nodejs/node/commit/b5bc6bd94b)] - **src**: fix Systemtap node\_gc\_stop probe (William Cohen) [#20152](https://github.com/nodejs/node/pull/20152) +* [[`6bf816fde2`](https://github.com/nodejs/node/commit/6bf816fde2)] - **src**: limit foreground tasks draining loop (Ulan Degenbaev) [#19987](https://github.com/nodejs/node/pull/19987) +* [[`bd2e521096`](https://github.com/nodejs/node/commit/bd2e521096)] - **src**: rename return var in VerifySpkac functions (Daniel Bevenius) [#20218](https://github.com/nodejs/node/pull/20218) +* [[`a4dae6c226`](https://github.com/nodejs/node/commit/a4dae6c226)] - **src**: prefer false instead of bool zero (Daniel Bevenius) [#20218](https://github.com/nodejs/node/pull/20218) +* [[`4c4be85655`](https://github.com/nodejs/node/commit/4c4be85655)] - ***Revert*** "**stream**: prevent 'end' to be emitted after 'error'" (Brian White) [#20449](https://github.com/nodejs/node/pull/20449) +* [[`05b7b8d506`](https://github.com/nodejs/node/commit/05b7b8d506)] - **stream**: fix error handling with async iteration (Julien Fontanet) [#20329](https://github.com/nodejs/node/pull/20329) +* [[`fd912a37a0`](https://github.com/nodejs/node/commit/fd912a37a0)] - **stream**: only check options once in Duplex ctor (Daniel Bevenius) [#20353](https://github.com/nodejs/node/pull/20353) +* [[`e19200a666`](https://github.com/nodejs/node/commit/e19200a666)] - **test**: fix flaky http2-flow-control test (Anatoli Papirovski) [#20556](https://github.com/nodejs/node/pull/20556) +* [[`b2d3db433d`](https://github.com/nodejs/node/commit/b2d3db433d)] - **test**: use common.canCreateSymLink() consistently (cjihrig) [#20540](https://github.com/nodejs/node/pull/20540) +* [[`578e0546e0`](https://github.com/nodejs/node/commit/578e0546e0)] - **test**: fix test-cli-node-options.js on mips (Ruben Bridgewater) [#20377](https://github.com/nodejs/node/pull/20377) +* [[`601f138063`](https://github.com/nodejs/node/commit/601f138063)] - **test**: fix buffer writes on mips (Ruben Bridgewater) [#20377](https://github.com/nodejs/node/pull/20377) +* [[`1de67c71fb`](https://github.com/nodejs/node/commit/1de67c71fb)] - **test**: fix common.canCreateSymLink() on non-Windows (Masashi Hirano) [#20511](https://github.com/nodejs/node/pull/20511) +* [[`70b2e169b4`](https://github.com/nodejs/node/commit/70b2e169b4)] - **test**: fix up N-API error test (Gabriel Schulhof) [#20487](https://github.com/nodejs/node/pull/20487) +* [[`6052ccc009`](https://github.com/nodejs/node/commit/6052ccc009)] - **test**: rename misnamed test (Rich Trott) [#20532](https://github.com/nodejs/node/pull/20532) +* [[`80bdff0086`](https://github.com/nodejs/node/commit/80bdff0086)] - **test**: add fs/promises filehandle stat test (Masashi Hirano) [#20492](https://github.com/nodejs/node/pull/20492) +* [[`4dce39a919`](https://github.com/nodejs/node/commit/4dce39a919)] - **test**: use fs.copyFileSync() (Richard Lau) [#20340](https://github.com/nodejs/node/pull/20340) +* [[`b24ee078f6`](https://github.com/nodejs/node/commit/b24ee078f6)] - **test**: remove unnecessary strictEqual() argument from remoteClose() (Daylor Yanes) [#20343](https://github.com/nodejs/node/pull/20343) +* [[`2b8b40f800`](https://github.com/nodejs/node/commit/2b8b40f800)] - **test**: fix a TODO and remove obsolete TODOs (Ruben Bridgewater) [#20319](https://github.com/nodejs/node/pull/20319) +* [[`645a97a44e`](https://github.com/nodejs/node/commit/645a97a44e)] - **test**: verify arguments length in common.expectsError (Ruben Bridgewater) [#20311](https://github.com/nodejs/node/pull/20311) +* [[`b646566ab4`](https://github.com/nodejs/node/commit/b646566ab4)] - **test**: removed assert.strictEqual message (kailash k yogeshwar) [#20223](https://github.com/nodejs/node/pull/20223) +* [[`61a56fe437`](https://github.com/nodejs/node/commit/61a56fe437)] - **test**: added coverage for fs/promises API (Mithun Sasidharan) [#20219](https://github.com/nodejs/node/pull/20219) +* [[`769b6c8fd2`](https://github.com/nodejs/node/commit/769b6c8fd2)] - **test**: fix flaky child-process-exec-kill-throws (Santiago Gimeno) [#20213](https://github.com/nodejs/node/pull/20213) +* [[`99e0b913c6`](https://github.com/nodejs/node/commit/99e0b913c6)] - **test**: add checkMethods function for Certificate (Daniel Bevenius) [#20224](https://github.com/nodejs/node/pull/20224) +* [[`d4b19cf43f`](https://github.com/nodejs/node/commit/d4b19cf43f)] - **test,n-api**: re-write test\_error in C (Gabriel Schulhof) [#20244](https://github.com/nodejs/node/pull/20244) +* [[`e552158dd2`](https://github.com/nodejs/node/commit/e552158dd2)] - **timers**: named anonymous functions (Kyle Martin) [#20397](https://github.com/nodejs/node/pull/20397) +* [[`1109104206`](https://github.com/nodejs/node/commit/1109104206)] - **tls**: remove sharedCreds in Server constructor (Daniel Bevenius) [#20491](https://github.com/nodejs/node/pull/20491) +* [[`1ebec18624`](https://github.com/nodejs/node/commit/1ebec18624)] - **tls**: cleanup onhandshakestart callback (Anatoli Papirovski) [#20466](https://github.com/nodejs/node/pull/20466) +* [[`9b30bc4f81`](https://github.com/nodejs/node/commit/9b30bc4f81)] - **tls**: fix getEphemeralKeyInfo to support X25519 (Shigeki Ohtsu) [#20273](https://github.com/nodejs/node/pull/20273) +* [[`73cd2798df`](https://github.com/nodejs/node/commit/73cd2798df)] - **tls**: specify options.name in validateKeyCert (Daniel Bevenius) [#20284](https://github.com/nodejs/node/pull/20284) +* [[`f7267b4af0`](https://github.com/nodejs/node/commit/f7267b4af0)] - **tools**: add eslint check for skipIfEslintMissing (Richard Lau) [#20372](https://github.com/nodejs/node/pull/20372) +* [[`2a1efa26a7`](https://github.com/nodejs/node/commit/2a1efa26a7)] - **tools**: add v10 to alternative version docs menu (Vse Mozhet Byt) [#20586](https://github.com/nodejs/node/pull/20586) +* [[`a4d2089c76`](https://github.com/nodejs/node/commit/a4d2089c76)] - **tools**: remove redundant code in doc/html.js (Vse Mozhet Byt) [#20514](https://github.com/nodejs/node/pull/20514) +* [[`3912551252`](https://github.com/nodejs/node/commit/3912551252)] - **tools**: fix TypeError from `test.py --time` (Richard Lau) [#20368](https://github.com/nodejs/node/pull/20368) +* [[`b0c0352742`](https://github.com/nodejs/node/commit/b0c0352742)] - **tools**: dedupe property access in doc/type-parser (Vse Mozhet Byt) [#20387](https://github.com/nodejs/node/pull/20387) +* [[`ccf1b24af2`](https://github.com/nodejs/node/commit/ccf1b24af2)] - **tools**: remove redundant RegExp flag (Vse Mozhet Byt) [#20309](https://github.com/nodejs/node/pull/20309) +* [[`a12d13ad06`](https://github.com/nodejs/node/commit/a12d13ad06)] - **tools**: simplify HTML generation (Vse Mozhet Byt) [#20307](https://github.com/nodejs/node/pull/20307) +* [[`8ddbac2fd6`](https://github.com/nodejs/node/commit/8ddbac2fd6)] - **tools**: add log output to crashes (Ruben Bridgewater) [#20295](https://github.com/nodejs/node/pull/20295) +* [[`ab13f13a6c`](https://github.com/nodejs/node/commit/ab13f13a6c)] - **tools**: show stdout/stderr for timed out tests (Rich Trott) [#20260](https://github.com/nodejs/node/pull/20260) +* [[`b5584c448a`](https://github.com/nodejs/node/commit/b5584c448a)] - **tools**: modernize and optimize doc/addon-verify.js (Vse Mozhet Byt) [#20188](https://github.com/nodejs/node/pull/20188) +* [[`ff619d39e6`](https://github.com/nodejs/node/commit/ff619d39e6)] - **url**: fix WHATWG host formatting error (Yichao 'Peak' Ji) [#20493](https://github.com/nodejs/node/pull/20493) +* [[`1b9c40cc71`](https://github.com/nodejs/node/commit/1b9c40cc71)] - **util**: named anonymous functions (Carrie Coxwell) [#20408](https://github.com/nodejs/node/pull/20408) +* [[`e854c953fd`](https://github.com/nodejs/node/commit/e854c953fd)] - **util**: improve spliceOne perf (Anatoli Papirovski) [#20453](https://github.com/nodejs/node/pull/20453) +* [[`3962c734ae`](https://github.com/nodejs/node/commit/3962c734ae)] - **util**: fix isInsideNodeModules inside error (Anatoli Papirovski) [#20266](https://github.com/nodejs/node/pull/20266) + ## 2018-04-24, Version 10.0.0 (Current), @jasnell diff --git a/src/node_version.h b/src/node_version.h index 857f5e78791628..588e602d776c0b 100644 --- a/src/node_version.h +++ b/src/node_version.h @@ -23,13 +23,13 @@ #define SRC_NODE_VERSION_H_ #define NODE_MAJOR_VERSION 10 -#define NODE_MINOR_VERSION 0 -#define NODE_PATCH_VERSION 1 +#define NODE_MINOR_VERSION 1 +#define NODE_PATCH_VERSION 0 #define NODE_VERSION_IS_LTS 0 #define NODE_VERSION_LTS_CODENAME "" -#define NODE_VERSION_IS_RELEASE 0 +#define NODE_VERSION_IS_RELEASE 1 #ifndef NODE_STRINGIFY #define NODE_STRINGIFY(n) NODE_STRINGIFY_HELPER(n)