diff --git a/.gitignore b/.gitignore index f9a92ffd54449b..f96c1c2b7238b6 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ !.mailmap !.nycrc !.remarkrc +!.travis.yml core vgcore.* diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000000000..21ec6dab70f994 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,27 @@ +language: cpp +sudo: false +cache: ccache +os: linux +matrix: + include: + - name: "Linter" + node_js: "latest" + env: + - NODE=$(which node) + script: + - make lint + # Lint the first commit in the PR. + - \[ -z "$TRAVIS_COMMIT_RANGE" \] || (echo -e '\nLinting the commit message according to the guidelines at https://goo.gl/p2fr5Q\n' && git log $TRAVIS_COMMIT_RANGE --pretty=format:'%h' --no-merges | tail -1 | xargs npx -q core-validate-commit --no-validate-metadata) + - name: "Test Suite" + addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - g++-4.9 + install: + - export CC='ccache gcc-4.9' CXX='ccache g++-4.9' JOBS=2 + - ./configure + - make -j2 V= + script: + - PARALLEL_ARGS='--flaky-tests=skip' make -j1 test diff --git a/BUILDING.md b/BUILDING.md index 1ecdc5abb17adc..08276975ae453b 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -205,6 +205,15 @@ To read the documentation: $ man doc/node.1 ``` +If you prefer to read the documentation in a browser, +run the following after `make doc` is finished: + +```console +$ make docopen +``` + +This will open a browser with the documentation. + To test if Node.js was built correctly: ```console @@ -433,3 +442,14 @@ To make `./myCustomModule.js` available via `require('myCustomModule')`. ```console > .\vcbuild link-module './myCustomModule.js' ``` + +## Note for downstream distributors of Node.js + +The Node.js ecosystem is reliant on ABI compatibility within a major +release. To maintain ABI compatibility it is required that production +builds of Node.js will be built against the same version of dependencies as the +project vendors. If Node.js is to be built against a different version of a +dependency please create a custom `NODE_MODULE_VERSION` to ensure ecosystem +compatibility. Please consult with the TSC by opening an issue at +https://github.com/nodejs/tsc/issues if you decide to create a custom +`NODE_MODULE_VERSION` so we can avoid duplication in the ecosystem. diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cb4882200cf85..f3a81c1f648ab5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,8 +27,9 @@ release. -8.14.0
-8.13.0

+8.14.1
+8.14.0
+8.13.0
8.12.0
8.11.4
8.11.3
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 5a935352a1f9f0..4c211405596cb4 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,8 +1,4 @@ # Code of Conduct -The Node.js Code of Conduct document has moved to -https://github.com/nodejs/admin/blob/master/CODE_OF_CONDUCT.md. Please update -links to this document accordingly. - -The Node.js Moderation policy can be found at -https://github.com/nodejs/admin/blob/master/Moderation-Policy.md +* [Node.js Code of Conduct](https://github.com/nodejs/admin/blob/master/CODE_OF_CONDUCT.md) +* [Node.js Moderation Policy](https://github.com/nodejs/admin/blob/master/Moderation-Policy.md) diff --git a/COLLABORATOR_GUIDE.md b/COLLABORATOR_GUIDE.md index 08b506f45683b8..a5c2741b990b97 100644 --- a/COLLABORATOR_GUIDE.md +++ b/COLLABORATOR_GUIDE.md @@ -23,7 +23,7 @@ * [Landing Pull Requests](#landing-pull-requests) - [Technical HOWTO](#technical-howto) - [Troubleshooting](#troubleshooting) - - [I Just Made a Mistake](#i-just-made-a-mistake) + - [I Made a Mistake](#i-made-a-mistake) - [Long Term Support](#long-term-support) - [What is LTS?](#what-is-lts) - [How does LTS work?](#how-does-lts-work) @@ -32,13 +32,10 @@ - [How can I help?](#how-can-i-help) - [How is an LTS release cut?](#how-is-an-lts-release-cut) -This document contains information for Collaborators of the Node.js -project regarding managing the project's code, documentation, and issue tracker. - -Collaborators should be familiar with the guidelines for new -contributors in [CONTRIBUTING.md](./CONTRIBUTING.md) and also -understand the project governance model as outlined in -[GOVERNANCE.md](./GOVERNANCE.md). +This document explains how Collaborators manage the Node.js project. +Collaborators should understand the +[guidelines for new contributors](CONTRIBUTING.md) and the +[project governance model](GOVERNANCE.md). ## Issues and Pull Requests @@ -638,7 +635,7 @@ make -j4 test git push upstream master ``` -### I Just Made a Mistake +### I Made a Mistake * Ping a TSC member. * `#node-dev` on freenode diff --git a/GOVERNANCE.md b/GOVERNANCE.md index 7b8903fa5c8bae..1ed1ffe3c44f45 100644 --- a/GOVERNANCE.md +++ b/GOVERNANCE.md @@ -40,7 +40,7 @@ be accepted unless: * Discussions and/or additional changes result in no Collaborators objecting to the change. Previously-objecting Collaborators do not necessarily have to - sign-off on the change, but they should not be opposed to it. + sign off on the change, but they should not be opposed to it. * The change is escalated to the TSC and the TSC votes to approve the change. This should only happen if disagreements between Collaborators cannot be resolved through discussion. @@ -115,7 +115,7 @@ The meeting chair is responsible for ensuring that minutes are taken and that a pull request with the minutes is submitted after the meeting. Due to the challenges of scheduling a global meeting with participants in -several timezones, the TSC will seek to resolve as many agenda items as possible +several time zones, the TSC will seek to resolve as many agenda items as possible outside of meetings using [the TSC issue tracker](https://github.com/nodejs/TSC/issues). The process in the issue tracker is: @@ -130,7 +130,7 @@ the issue tracker is: ## Consensus Seeking Process -The TSC follows a [Consensus Seeking][] decision making model as described by +The TSC follows a [Consensus Seeking][] decision-making model as described by the [TSC Charter][]. [TSC Charter]: https://github.com/nodejs/TSC/blob/master/TSC-Charter.md diff --git a/Makefile b/Makefile index fe7595bea70dee..799bb2640ea89a 100644 --- a/Makefile +++ b/Makefile @@ -762,12 +762,11 @@ PKG=$(TARNAME).pkg MACOSOUTDIR=out/macos release-only: - @if [ "$(DISTTYPE)" != "nightly" ] && [ "$(DISTTYPE)" != "next-nightly" ] && \ - `grep -q REPLACEME doc/api/*.md`; then \ + @if [ "$(DISTTYPE)" = "release" ] && `grep -q REPLACEME doc/api/*.md`; then \ echo 'Please update REPLACEME in Added: tags in doc/api/*.md (See doc/releases.md)' ; \ exit 1 ; \ fi - @if [ "$(DISTTYPE)" != "nightly" ] && [ "$(DISTTYPE)" != "next-nightly" ] && \ + @if [ "$(DISTTYPE)" = "release" ] && \ `grep -q DEP00XX doc/api/deprecations.md`; then \ echo 'Please update DEP00XX in doc/api/deprecations.md (See doc/releases.md)' ; \ exit 1 ; \ diff --git a/README.md b/README.md index 7f0c69c4a3cbe6..81c024a42fbca5 100644 --- a/README.md +++ b/README.md @@ -44,12 +44,13 @@ When looking for support, please first search for your question in these venues: * [Node.js Website][] * [Node.js Help][] * [Open or closed issues in the Node.js GitHub organization](https://github.com/issues?utf8=%E2%9C%93&q=sort%3Aupdated-desc+org%3Anodejs+is%3Aissue) -* [Questions tagged 'node.js' on StackOverflow][] -If you didn't find an answer in one of the venues above, you can: +If you didn't find an answer in one of the official resources above, you can +search these unofficial resources: -* Join the **unofficial** [#node.js channel on chat.freenode.net][]. See - for more information. +* [Questions tagged 'node.js' on StackOverflow][] +* [#node.js channel on chat.freenode.net][]. See for more + information. GitHub issues are meant for tracking enhancements and bugs, not general support. @@ -202,9 +203,8 @@ us a report nonetheless. ### Private disclosure preferred - [CVE-2016-7099](https://nodejs.org/en/blog/vulnerability/september-2016-security-releases/): - _Fix invalid wildcard certificate validation check_. This is a high severity - defect that would allow a malicious TLS server to serve an invalid wildcard - certificate for its hostname and be improperly validated by a Node.js client. + _Fix invalid wildcard certificate validation check_. This was a high-severity + defect. It caused Node.js TLS clients to accept invalid wildcard certificates. - [#5507](https://github.com/nodejs/node/pull/5507): _Fix a defect that makes the CacheBleed Attack possible_. Many, though not all, OpenSSL vulnerabilities @@ -212,8 +212,8 @@ us a report nonetheless. - [CVE-2016-2216](https://nodejs.org/en/blog/vulnerability/february-2016-security-releases/): _Fix defects in HTTP header parsing for requests and responses that can allow - response splitting_. While the impact of this vulnerability is application and - network dependent, it is remotely exploitable in the HTTP protocol. + response splitting_. This was a remotely-exploitable defect in the Node.js + HTTP implementation. When in doubt, please do send us a report. @@ -309,6 +309,8 @@ For more information about the governance of the Node.js project, see **Bryan English** <bryan@bryanenglish.com> (he/him) * [benjamingr](https://github.com/benjamingr) - **Benjamin Gruenbaum** <benjamingr@gmail.com> +* [BethGriggs](https://github.com/BethGriggs) - +**Beth Griggs** <Bethany.Griggs@uk.ibm.com> (she/her) * [bmeck](https://github.com/bmeck) - **Bradley Farias** <bradley.meck@gmail.com> * [bmeurer](https://github.com/bmeurer) - @@ -439,8 +441,6 @@ For more information about the governance of the Node.js project, see **Alexis Campailla** <orangemocha@nodejs.org> * [othiym23](https://github.com/othiym23) - **Forrest L Norvell** <ogd@aoaioxxysz.net> (he/him) -* [phillipj](https://github.com/phillipj) - -**Phillip Johnsen** <johphi@gmail.com> * [pmq20](https://github.com/pmq20) - **Minqi Pan** <pmq2001@gmail.com> * [princejwesley](https://github.com/princejwesley) - @@ -538,6 +538,8 @@ For more information about the governance of the Node.js project, see **Oleg Elifantiev** <oleg@elifantiev.ru> * [petkaantonov](https://github.com/petkaantonov) - **Petka Antonov** <petka_antonov@hotmail.com> +* [phillipj](https://github.com/phillipj) - +**Phillip Johnsen** <johphi@gmail.com> * [piscisaureus](https://github.com/piscisaureus) - **Bert Belder** <bertbelder@gmail.com> * [rlidwka](https://github.com/rlidwka) - diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h index 95cc3573a3f723..62c81f2ca057ad 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 2 #define V8_BUILD_NUMBER 414 -#define V8_PATCH_LEVEL 72 +#define V8_PATCH_LEVEL 75 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) diff --git a/deps/v8/src/base/debug/stack_trace_posix.cc b/deps/v8/src/base/debug/stack_trace_posix.cc index 87c0a73d191e65..681dfbf9728449 100644 --- a/deps/v8/src/base/debug/stack_trace_posix.cc +++ b/deps/v8/src/base/debug/stack_trace_posix.cc @@ -72,6 +72,7 @@ const char kMangledSymbolPrefix[] = "_Z"; const char kSymbolCharacters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; +#if HAVE_EXECINFO_H // Demangles C++ symbols in the given text. Example: // // "out/Debug/base_unittests(_ZN10StackTraceC1Ev+0x20) [0x817778c]" @@ -81,7 +82,6 @@ void DemangleSymbols(std::string* text) { // Note: code in this function is NOT async-signal safe (std::string uses // malloc internally). -#if HAVE_EXECINFO_H std::string::size_type search_from = 0; while (search_from < text->size()) { @@ -117,9 +117,8 @@ void DemangleSymbols(std::string* text) { search_from = mangled_start + 2; } } - -#endif // HAVE_EXECINFO_H } +#endif // HAVE_EXECINFO_H class BacktraceOutputHandler { public: @@ -129,6 +128,7 @@ class BacktraceOutputHandler { virtual ~BacktraceOutputHandler() {} }; +#if HAVE_EXECINFO_H void OutputPointer(void* pointer, BacktraceOutputHandler* handler) { // This should be more than enough to store a 64-bit number in hex: // 16 hex digits + 1 for null-terminator. @@ -139,7 +139,6 @@ void OutputPointer(void* pointer, BacktraceOutputHandler* handler) { handler->HandleOutput(buf); } -#if HAVE_EXECINFO_H void ProcessBacktrace(void* const* trace, size_t size, BacktraceOutputHandler* handler) { // NOTE: This code MUST be async-signal safe (it's used by in-process diff --git a/deps/v8/src/compiler/bytecode-graph-builder.cc b/deps/v8/src/compiler/bytecode-graph-builder.cc index 2d68ed8b0378eb..ca98a5fe28830b 100644 --- a/deps/v8/src/compiler/bytecode-graph-builder.cc +++ b/deps/v8/src/compiler/bytecode-graph-builder.cc @@ -475,7 +475,7 @@ Node* BytecodeGraphBuilder::Environment::Checkpoint( BytecodeGraphBuilder::BytecodeGraphBuilder( Zone* local_zone, Handle shared_info, Handle feedback_vector, BailoutId osr_offset, - JSGraph* jsgraph, CallFrequency invocation_frequency, + JSGraph* jsgraph, CallFrequency& invocation_frequency, SourcePositionTable* source_positions, int inlining_id, JSTypeHintLowering::Flags flags, bool stack_check) : local_zone_(local_zone), diff --git a/deps/v8/src/compiler/bytecode-graph-builder.h b/deps/v8/src/compiler/bytecode-graph-builder.h index 0ec8a1f473c55c..7609ec7279eda6 100644 --- a/deps/v8/src/compiler/bytecode-graph-builder.h +++ b/deps/v8/src/compiler/bytecode-graph-builder.h @@ -28,7 +28,7 @@ class BytecodeGraphBuilder { BytecodeGraphBuilder( Zone* local_zone, Handle shared, Handle feedback_vector, BailoutId osr_offset, - JSGraph* jsgraph, CallFrequency invocation_frequency, + JSGraph* jsgraph, CallFrequency& invocation_frequency, SourcePositionTable* source_positions, int inlining_id = SourcePosition::kNotInlined, JSTypeHintLowering::Flags flags = JSTypeHintLowering::kNoFlags, diff --git a/deps/v8/src/compiler/js-inlining.cc b/deps/v8/src/compiler/js-inlining.cc index b74f94fa72cdf7..abce004367e332 100644 --- a/deps/v8/src/compiler/js-inlining.cc +++ b/deps/v8/src/compiler/js-inlining.cc @@ -539,9 +539,10 @@ Reduction JSInliner::ReduceJSCall(Node* node) { if (info_->is_bailout_on_uninitialized()) { flags |= JSTypeHintLowering::kBailoutOnUninitialized; } + CallFrequency frequency = call.frequency(); BytecodeGraphBuilder graph_builder( zone(), shared_info, feedback_vector, BailoutId::None(), jsgraph(), - call.frequency(), source_positions_, inlining_id, flags, false); + frequency, source_positions_, inlining_id, flags, false); graph_builder.CreateGraph(); // Extract the inlinee start/end nodes. diff --git a/deps/v8/src/compiler/js-operator.cc b/deps/v8/src/compiler/js-operator.cc index 2a680cd6769ad7..6ea5b850c6910a 100644 --- a/deps/v8/src/compiler/js-operator.cc +++ b/deps/v8/src/compiler/js-operator.cc @@ -731,7 +731,8 @@ const Operator* JSOperatorBuilder::CallForwardVarargs(size_t arity, parameters); // parameter } -const Operator* JSOperatorBuilder::Call(size_t arity, CallFrequency frequency, +const Operator* JSOperatorBuilder::Call(size_t arity, + CallFrequency const& frequency, VectorSlotPair const& feedback, ConvertReceiverMode convert_mode) { CallParameters parameters(arity, frequency, feedback, convert_mode); @@ -751,7 +752,8 @@ const Operator* JSOperatorBuilder::CallWithArrayLike(CallFrequency frequency) { } const Operator* JSOperatorBuilder::CallWithSpread( - uint32_t arity, CallFrequency frequency, VectorSlotPair const& feedback) { + uint32_t arity, CallFrequency const& frequency, + VectorSlotPair const& feedback) { CallParameters parameters(arity, frequency, feedback, ConvertReceiverMode::kAny); return new (zone()) Operator1( // -- diff --git a/deps/v8/src/compiler/js-operator.h b/deps/v8/src/compiler/js-operator.h index 5ea288f355eeba..0bf2c589818566 100644 --- a/deps/v8/src/compiler/js-operator.h +++ b/deps/v8/src/compiler/js-operator.h @@ -192,7 +192,7 @@ CallForwardVarargsParameters const& CallForwardVarargsParametersOf( // used as a parameter by JSCall and JSCallWithSpread operators. class CallParameters final { public: - CallParameters(size_t arity, CallFrequency frequency, + CallParameters(size_t arity, CallFrequency const& frequency, VectorSlotPair const& feedback, ConvertReceiverMode convert_mode) : bit_field_(ArityField::encode(arity) | @@ -201,7 +201,7 @@ class CallParameters final { feedback_(feedback) {} size_t arity() const { return ArityField::decode(bit_field_); } - CallFrequency frequency() const { return frequency_; } + CallFrequency const& frequency() const { return frequency_; } ConvertReceiverMode convert_mode() const { return ConvertReceiverModeField::decode(bit_field_); } @@ -647,12 +647,12 @@ class V8_EXPORT_PRIVATE JSOperatorBuilder final const Operator* CallForwardVarargs(size_t arity, uint32_t start_index); const Operator* Call( - size_t arity, CallFrequency frequency = CallFrequency(), + size_t arity, CallFrequency const& frequency = CallFrequency(), VectorSlotPair const& feedback = VectorSlotPair(), ConvertReceiverMode convert_mode = ConvertReceiverMode::kAny); const Operator* CallWithArrayLike(CallFrequency frequency); const Operator* CallWithSpread( - uint32_t arity, CallFrequency frequency = CallFrequency(), + uint32_t arity, CallFrequency const& frequency = CallFrequency(), VectorSlotPair const& feedback = VectorSlotPair()); const Operator* CallRuntime(Runtime::FunctionId id); const Operator* CallRuntime(Runtime::FunctionId id, size_t arity); diff --git a/deps/v8/src/compiler/pipeline.cc b/deps/v8/src/compiler/pipeline.cc index 4b91e9fc4a22fc..e5aac506e67b60 100644 --- a/deps/v8/src/compiler/pipeline.cc +++ b/deps/v8/src/compiler/pipeline.cc @@ -890,10 +890,11 @@ struct GraphBuilderPhase { if (data->info()->is_bailout_on_uninitialized()) { flags |= JSTypeHintLowering::kBailoutOnUninitialized; } + CallFrequency frequency = CallFrequency(1.0f); BytecodeGraphBuilder graph_builder( temp_zone, data->info()->shared_info(), handle(data->info()->closure()->feedback_vector()), - data->info()->osr_offset(), data->jsgraph(), CallFrequency(1.0f), + data->info()->osr_offset(), data->jsgraph(), frequency, data->source_positions(), SourcePosition::kNotInlined, flags); graph_builder.CreateGraph(); } diff --git a/deps/v8/src/compiler/store-store-elimination.cc b/deps/v8/src/compiler/store-store-elimination.cc index 71aa2110bb7808..eaa74328f09c71 100644 --- a/deps/v8/src/compiler/store-store-elimination.cc +++ b/deps/v8/src/compiler/store-store-elimination.cc @@ -251,6 +251,9 @@ void StoreStoreElimination::Run(JSGraph* js_graph, Zone* temp_zone) { } } +#if V8_OS_AIX +ALLOW_UNUSED_TYPE +#endif bool RedundantStoreFinder::IsEffectful(Node* node) { return (node->op()->EffectInputCount() >= 1); } @@ -552,6 +555,9 @@ bool UnobservableStore::operator==(const UnobservableStore other) const { return (id_ == other.id_) && (offset_ == other.offset_); } +#if V8_OS_AIX +ALLOW_UNUSED_TYPE +#endif bool UnobservableStore::operator!=(const UnobservableStore other) const { return !(*this == other); } diff --git a/deps/v8/src/conversions.cc b/deps/v8/src/conversions.cc index 8956a261688b1b..1071c1f2a1b312 100644 --- a/deps/v8/src/conversions.cc +++ b/deps/v8/src/conversions.cc @@ -53,11 +53,17 @@ class StringCharacterStreamIterator { }; +#if V8_OS_AIX +ALLOW_UNUSED_TYPE +#endif StringCharacterStreamIterator::StringCharacterStreamIterator( StringCharacterStream* stream) : stream_(stream) { ++(*this); } +#if V8_OS_AIX +ALLOW_UNUSED_TYPE +#endif uint16_t StringCharacterStreamIterator::operator*() const { return current_; } diff --git a/deps/v8/testing/gtest.gyp b/deps/v8/testing/gtest.gyp index a94ee884fe9f51..0eb93a05b591fd 100644 --- a/deps/v8/testing/gtest.gyp +++ b/deps/v8/testing/gtest.gyp @@ -96,6 +96,10 @@ }], ], }], + ['OS=="aix"', { + 'cflags': [ '-Wno-nonnull-compare', + '-Wno-address' ], + }], ], 'msvs_disabled_warnings': [4800], }, diff --git a/doc/STYLE_GUIDE.md b/doc/STYLE_GUIDE.md index 93d4b3a806aa01..68c7016d0372e5 100644 --- a/doc/STYLE_GUIDE.md +++ b/doc/STYLE_GUIDE.md @@ -70,6 +70,8 @@ * Use official styling for capitalization in products and projects. * OK: JavaScript, Google's V8 * NOT OK: Javascript, Google's v8 +* Use _Node.js_ and not _Node_, _NodeJS_, or similar variants. + * When referring to the executable, _`node`_ is acceptable. See also API documentation structure overview in [doctools README][]. diff --git a/doc/api/_toc.md b/doc/api/_toc.md index 420fb362fa537a..12e0aa326e9cd1 100644 --- a/doc/api/_toc.md +++ b/doc/api/_toc.md @@ -55,4 +55,3 @@
* [GitHub Repo & Issue Tracker](https://github.com/nodejs/node) -* [Mailing List](https://groups.google.com/group/nodejs) diff --git a/doc/api/addons.md b/doc/api/addons.md index d2f312b06e72fb..4a68b151e4fafa 100644 --- a/doc/api/addons.md +++ b/doc/api/addons.md @@ -246,7 +246,7 @@ napi_value Method(napi_env env, napi_callback_info args) { napi_value greeting; napi_status status; - status = napi_create_string_utf8(env, "hello", 6, &greeting); + status = napi_create_string_utf8(env, "hello", NAPI_AUTO_LENGTH, &greeting); if (status != napi_ok) return nullptr; return greeting; } diff --git a/doc/api/assert.md b/doc/api/assert.md index 2ed2c45c810647..5df4edbf81dce4 100644 --- a/doc/api/assert.md +++ b/doc/api/assert.md @@ -37,8 +37,8 @@ const assert = require('assert').strict; > Stability: 0 - Deprecated: Use strict mode instead. When accessing `assert` directly instead of using the `strict` property, the -[Abstract Equality Comparison][] will be used for any function without a -"strict" in its name (e.g. [`assert.deepEqual()`][]). +[Abstract Equality Comparison][] will be used for any function without "strict" +in its name, such as [`assert.deepEqual()`][]. It can be accessed using: @@ -47,11 +47,9 @@ const assert = require('assert'); ``` It is recommended to use the [`strict mode`][] instead as the -[Abstract Equality Comparison][] can often have surprising results. Especially -in case of [`assert.deepEqual()`][] as the used comparison rules there are very -lax. - -E.g. +[Abstract Equality Comparison][] can often have surprising results. This is +especially true for [`assert.deepEqual()`][], where the comparison rules are +lax: ```js // WARNING: This does not throw an AssertionError! @@ -863,11 +861,12 @@ For more information, see [`assert.notDeepStrictEqual()`]: #assert_assert_notdeepstrictequal_actual_expected_message [`assert.notStrictEqual()`]: #assert_assert_notstrictequal_actual_expected_message [`assert.ok()`]: #assert_assert_ok_value_message +[`assert.rejects()`]: #assert_assert_rejects_block_error_message [`assert.strictEqual()`]: #assert_assert_strictequal_actual_expected_message [`assert.throws()`]: #assert_assert_throws_block_error_message -[`assert.rejects()`]: #assert_assert_rejects_block_error_message [`strict mode`]: #assert_strict_mode [Abstract Equality Comparison]: https://tc39.github.io/ecma262/#sec-abstract-equality-comparison +[Object wrappers]: https://developer.mozilla.org/en-US/docs/Glossary/Primitive#Primitive_wrapper_objects_in_JavaScript [Object.prototype.toString()]: https://tc39.github.io/ecma262/#sec-object.prototype.tostring [SameValueZero]: https://tc39.github.io/ecma262/#sec-samevaluezero [Strict Equality Comparison]: https://tc39.github.io/ecma262/#sec-strict-equality-comparison @@ -875,4 +874,3 @@ For more information, see [enumerable "own" properties]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties [mdn-equality-guide]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness [prototype-spec]: https://tc39.github.io/ecma262/#sec-ordinary-object-internal-methods-and-internal-slots -[Object wrappers]: https://developer.mozilla.org/en-US/docs/Glossary/Primitive#Primitive_wrapper_objects_in_JavaScript diff --git a/doc/api/async_hooks.md b/doc/api/async_hooks.md index 2b92e4e6b5adbc..f8dd64aad24ef3 100644 --- a/doc/api/async_hooks.md +++ b/doc/api/async_hooks.md @@ -236,8 +236,8 @@ resource's constructor. ```text FSEVENTWRAP, FSREQWRAP, GETADDRINFOREQWRAP, GETNAMEINFOREQWRAP, HTTPPARSER, JSSTREAM, PIPECONNECTWRAP, PIPEWRAP, PROCESSWRAP, QUERYWRAP, SHUTDOWNWRAP, -SIGNALWRAP, STATWATCHER, TCPCONNECTWRAP, TCPSERVER, TCPWRAP, TIMERWRAP, TTYWRAP, -UDPSENDWRAP, UDPWRAP, WRITEWRAP, ZLIB, SSLCONNECTION, PBKDF2REQUEST, +SIGNALWRAP, STATWATCHER, TCPCONNECTWRAP, TCPSERVERWRAP, TCPWRAP, TIMERWRAP, +TTYWRAP, UDPSENDWRAP, UDPWRAP, WRITEWRAP, ZLIB, SSLCONNECTION, PBKDF2REQUEST, RANDOMBYTESREQUEST, TLSWRAP, Timeout, Immediate, TickObject ``` diff --git a/doc/api/buffer.md b/doc/api/buffer.md index 4155b70d1c6069..9016f8f6a96919 100644 --- a/doc/api/buffer.md +++ b/doc/api/buffer.md @@ -15,9 +15,9 @@ With [`TypedArray`] now available, the `Buffer` class implements the Instances of the `Buffer` class are similar to arrays of integers but correspond to fixed-sized, raw memory allocations outside the V8 heap. The size of the `Buffer` is established when it is created and cannot be -resized. +changed. -The `Buffer` class is a global within Node.js, making it unlikely that one +The `Buffer` class is within the global scope, making it unlikely that one would need to ever use `require('buffer').Buffer`. Examples: @@ -483,8 +483,8 @@ changes: * `string` {string} String to encode. * `encoding` {string} The encoding of `string`. **Default:** `'utf8'`. -Creates a new `Buffer` containing the given JavaScript string `string`. If -provided, the `encoding` parameter identifies the character encoding of `string`. +Creates a new `Buffer` containing `string`. The `encoding` parameter identifies +the character encoding of `string`. Examples: @@ -891,8 +891,8 @@ added: v5.10.0 * `string` {string} A string to encode. * `encoding` {string} The encoding of `string`. **Default:** `'utf8'`. -Creates a new `Buffer` containing the given JavaScript string `string`. If -provided, the `encoding` parameter identifies the character encoding of `string`. +Creates a new `Buffer` containing `string`. The `encoding` parameter identifies +the character encoding of `string`. Examples: @@ -2742,9 +2742,9 @@ This value may depend on the JS engine that is being used. [`buf.length`]: #buffer_buf_length [`buf.slice()`]: #buffer_buf_slice_start_end [`buf.values()`]: #buffer_buf_values -[`buffer.kMaxLength`]: #buffer_buffer_kmaxlength [`buffer.constants.MAX_LENGTH`]: #buffer_buffer_constants_max_length [`buffer.constants.MAX_STRING_LENGTH`]: #buffer_buffer_constants_max_string_length +[`buffer.kMaxLength`]: #buffer_buffer_kmaxlength [`util.inspect()`]: util.html#util_util_inspect_object_options [RFC1345]: https://tools.ietf.org/html/rfc1345 [RFC4648, Section 5]: https://tools.ietf.org/html/rfc4648#section-5 diff --git a/doc/api/child_process.md b/doc/api/child_process.md index 98b1ae55781434..4873d4681a7755 100755 --- a/doc/api/child_process.md +++ b/doc/api/child_process.md @@ -26,10 +26,12 @@ ls.on('close', (code) => { ``` By default, pipes for `stdin`, `stdout`, and `stderr` are established between -the parent Node.js process and the spawned child. It is possible to stream data -through these pipes in a non-blocking way. *Note, however, that some programs -use line-buffered I/O internally. While that does not affect Node.js, it can -mean that data sent to the child process may not be immediately consumed.* +the parent Node.js process and the spawned child. These pipes have +limited (and platform-specific) capacity. If the child process writes to +stdout in excess of that limit without the output being captured, the child +process will block waiting for the pipe buffer to accept more data. This is +identical to the behavior of pipes in the shell. Use the `{ stdio: 'ignore' }` +option if the output will not be consumed. The [`child_process.spawn()`][] method spawns the child process asynchronously, without blocking the Node.js event loop. The [`child_process.spawnSync()`][] @@ -1378,13 +1380,6 @@ unavailable. [`ChildProcess`]: #child_process_child_process [`Error`]: errors.html#errors_class_error [`EventEmitter`]: events.html#events_class_eventemitter -[`subprocess.connected`]: #child_process_subprocess_connected -[`subprocess.disconnect()`]: #child_process_subprocess_disconnect -[`subprocess.kill()`]: #child_process_subprocess_kill_signal -[`subprocess.send()`]: #child_process_subprocess_send_message_sendhandle_options_callback -[`subprocess.stderr`]: #child_process_subprocess_stderr -[`subprocess.stdin`]: #child_process_subprocess_stdin -[`subprocess.stdout`]: #child_process_subprocess_stdout [`child_process.exec()`]: #child_process_child_process_exec_command_options_callback [`child_process.execFile()`]: #child_process_child_process_execfile_file_args_options_callback [`child_process.execFileSync()`]: #child_process_child_process_execfilesync_file_args_options @@ -1403,6 +1398,13 @@ unavailable. [`process.on('message')`]: process.html#process_event_message [`process.send()`]: process.html#process_process_send_message_sendhandle_options_callback [`stdio`]: #child_process_options_stdio +[`subprocess.connected`]: #child_process_subprocess_connected +[`subprocess.disconnect()`]: #child_process_subprocess_disconnect +[`subprocess.kill()`]: #child_process_subprocess_kill_signal +[`subprocess.send()`]: #child_process_subprocess_send_message_sendhandle_options_callback +[`subprocess.stderr`]: #child_process_subprocess_stderr +[`subprocess.stdin`]: #child_process_subprocess_stdin +[`subprocess.stdout`]: #child_process_subprocess_stdout [`util.promisify()`]: util.html#util_util_promisify_original [Default Windows Shell]: #child_process_default_windows_shell [Shell Requirements]: #child_process_shell_requirements diff --git a/doc/api/cli.md b/doc/api/cli.md index 2586d6fd2054bd..28668703f0672d 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -465,7 +465,7 @@ if they had been specified on the command line before the actual command line (so they can be overridden). Node will exit with an error if an option that is not allowed in the environment is used, such as `-p` or a script file. -Node options that are allowed are: +Node.js options that are allowed are: - `--enable-fips` - `--force-fips` - `--icu-data-dir` diff --git a/doc/api/cluster.md b/doc/api/cluster.md index 15ffb239ed3dd9..d49d6e11c77e6d 100644 --- a/doc/api/cluster.md +++ b/doc/api/cluster.md @@ -198,8 +198,8 @@ Within a worker, `process.on('message')` may also be used. See [`process` event: `'message'`][]. -As an example, here is a cluster that keeps count of the number of requests -in the master process using the message system: +Here is an example using the message system. It keeps a count in the master +process of the number of HTTP requests received by the workers: ```js const cluster = require('cluster'); @@ -873,6 +873,7 @@ socket.on('data', (id) => { [`ChildProcess.send()`]: child_process.html#child_process_subprocess_send_message_sendhandle_options_callback [`child_process.fork()`]: child_process.html#child_process_child_process_fork_modulepath_args_options +[`cluster.settings`]: #cluster_cluster_settings [`disconnect`]: child_process.html#child_process_subprocess_disconnect [`kill`]: process.html#process_process_kill_pid_signal [`process` event: `'message'`]: process.html#process_event_message @@ -881,4 +882,3 @@ socket.on('data', (id) => { [Child Process module]: child_process.html#child_process_child_process_fork_modulepath_args_options [child_process event: 'exit']: child_process.html#child_process_event_exit [child_process event: 'message']: child_process.html#child_process_event_message -[`cluster.settings`]: #cluster_cluster_settings diff --git a/doc/api/console.md b/doc/api/console.md index bb6fb789730e43..79d4408c9dadbd 100644 --- a/doc/api/console.md +++ b/doc/api/console.md @@ -240,6 +240,10 @@ undefined ### console.debug(data[, ...args]) * `data` {any} * `...args` {any} @@ -417,15 +421,110 @@ added: v0.1.100 The `console.warn()` function is an alias for [`console.error()`][]. +## Inspector only methods +The following methods are exposed by the V8 engine in the general API but do +not display anything unless used in conjunction with the [inspector][] +(`--inspect` flag). + +### console.dirxml(object) + +* `object` {string} + +This method does not display anything unless used in the inspector. The +`console.dirxml()` method displays in `stdout` an XML interactive tree +representation of the descendants of the specified `object` if possible, or the +JavaScript representation if not. Calling `console.dirxml()` on an HTML or XML +element is equivalent to calling `console.log()`. + +### console.markTimeline(label) + +* `label` {string} Defaults to `'default'`. + +This method does not display anything unless used in the inspector. The +`console.markTimeline()` method is the deprecated form of [`console.timeStamp()`][]. + +### console.profile([label]) + +* `label` {string} + +This method does not display anything unless used in the inspector. The +`console.profile()` method starts a JavaScript CPU profile with an optional +label until [`console.profileEnd()`][] is called. The profile is then added to +the **Profile** panel of the inspector. +```js +console.profile('MyLabel'); +// Some code +console.profileEnd(); +// Adds the profile 'MyLabel' to the Profiles panel of the inspector. +``` + +### console.profileEnd() + + +This method does not display anything unless used in the inspector. Stops the +current JavaScript CPU profiling session if one has been started and prints +the report to the **Profiles** panel of the inspector. See +[`console.profile()`][] for an example. + +### console.table(array[, columns]) + +* `array` {Array|Object} +* `columns` {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]) + +* `label` {string} + +This method does not display anything unless used in the inspector. The +`console.timeStamp()` method adds an event with the label `label` to the +**Timeline** panel of the inspector. + +### console.timeline([label]) + +* `label` {string} Defaults to `'default'`. + +This method does not display anything unless used in the inspector. The +`console.timeline()` method is the deprecated form of [`console.time()`][]. + +### console.timelineEnd([label]) + +* `label` {string} Defaults to `'default'`. + +This method does not display anything unless used in the inspector. The +`console.timelineEnd()` method is the deprecated form of [`console.timeEnd()`][]. + [`console.error()`]: #console_console_error_data_args [`console.group()`]: #console_console_group_label [`console.log()`]: #console_console_log_data_args +[`console.profile()`]: #console_console_profile_label +[`console.profileEnd()`]: #console_console_profileend [`console.time()`]: #console_console_time_label [`console.timeEnd()`]: #console_console_timeend_label +[`console.timeStamp()`]: #console_console_timestamp_label [`process.stderr`]: process.html#process_process_stderr [`process.stdout`]: process.html#process_process_stdout [`util.format()`]: util.html#util_util_format_format_args [`util.inspect()`]: util.html#util_util_inspect_object_options [customizing `util.inspect()` colors]: util.html#util_customizing_util_inspect_colors +[inspector]: debugger.html [note on process I/O]: process.html#process_a_note_on_process_i_o [web-api-assert]: https://developer.mozilla.org/en-US/docs/Web/API/console/assert diff --git a/doc/api/crypto.md b/doc/api/crypto.md index d5ee1baab9ef1b..e608f45a48cd0e 100644 --- a/doc/api/crypto.md +++ b/doc/api/crypto.md @@ -2324,8 +2324,8 @@ the `crypto`, `tls`, and `https` modules and are generally specific to OpenSSL. [`hmac.update()`]: #crypto_hmac_update_data_inputencoding [`sign.sign()`]: #crypto_sign_sign_privatekey_outputformat [`sign.update()`]: #crypto_sign_update_data_inputencoding -[`stream.transform` options]: stream.html#stream_new_stream_transform_options [`stream.Writable` options]: stream.html#stream_constructor_new_stream_writable_options +[`stream.transform` options]: stream.html#stream_new_stream_transform_options [`tls.createSecureContext()`]: tls.html#tls_tls_createsecurecontext_options [`verify.update()`]: #crypto_verify_update_data_inputencoding [`verify.verify()`]: #crypto_verify_verify_object_signature_signatureformat diff --git a/doc/api/dgram.md b/doc/api/dgram.md index 652e2baadcdf31..38d0ac988630a2 100644 --- a/doc/api/dgram.md +++ b/doc/api/dgram.md @@ -95,6 +95,24 @@ Tells the kernel to join a multicast group at the given `multicastAddress` and one interface and will add membership to it. To add membership to every available interface, call `addMembership` multiple times, once per interface. +When sharing a UDP socket across multiple `cluster` workers, the +`socket.addMembership()` function must be called only once or an +`EADDRINUSE` error will occur: + +```js +const cluster = require('cluster'); +const dgram = require('dgram'); +if (cluster.isMaster) { + cluster.fork(); // Works ok. + cluster.fork(); // Fails with EADDRINUSE. +} else { + const s = dgram.createSocket('udp4'); + s.bind(1234, () => { + s.addMembership('224.0.0.114'); + }); +} +``` + ### socket.address() + +* {boolean} + +The `message.complete` property will be `true` if a complete HTTP message has +been received and successfully parsed. + +This property is particularly useful as a means of determining if a client or +server fully transmitted a message before a connection was terminated: + +```js +const req = http.request({ + host: '127.0.0.1', + port: 8080, + method: 'POST' +}, (res) => { + res.resume(); + res.on('end', () => { + if (!res.complete) + console.error( + 'The connection was terminated while the message was still being sent'); + }); +}); +``` + ### message.destroy([error]) -- `options` {Object} - * `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`. +--> - `requestListener` {Function} * Returns: {http.Server} @@ -1991,8 +2008,8 @@ not abort the request or do anything besides add a `timeout` event. [`removeHeader(name)`]: #http_request_removeheader_name [`request.end()`]: #http_request_end_data_encoding_callback [`request.setTimeout()`]: #http_request_settimeout_timeout_callback -[`request.socket`]: #http_request_socket [`request.socket.getPeerCertificate()`]: tls.html#tls_tlssocket_getpeercertificate_detailed +[`request.socket`]: #http_request_socket [`request.write(data, encoding)`]: #http_request_write_chunk_encoding_callback [`response.end()`]: #http_response_end_data_encoding_callback [`response.setHeader()`]: #http_response_setheader_name_value diff --git a/doc/api/http2.md b/doc/api/http2.md index dfa3e78b9fbf8e..09bc31a57720ad 100644 --- a/doc/api/http2.md +++ b/doc/api/http2.md @@ -3367,20 +3367,20 @@ following additional properties: `Http2Session`. -[ALPN negotiation]: #http2_alpn_negotiation [ALPN Protocol ID]: https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids +[ALPN negotiation]: #http2_alpn_negotiation [Compatibility API]: #http2_compatibility_api [HTTP/1]: http.html -[HTTP/2]: https://tools.ietf.org/html/rfc7540 -[HTTP/2 Unencrypted]: https://http2.github.io/faq/#does-http2-require-encryption [HTTP/2 Headers Object]: #http2_headers_object [HTTP/2 Settings Object]: #http2_settings_object +[HTTP/2 Unencrypted]: https://http2.github.io/faq/#does-http2-require-encryption +[HTTP/2]: https://tools.ietf.org/html/rfc7540 [HTTPS]: https.html [Http2Session and Sockets]: #http2_http2session_and_sockets [Performance Observer]: perf_hooks.html -[Readable Stream]: stream.html#stream_class_stream_readable [RFC 7838]: https://tools.ietf.org/html/rfc7838 [RFC 8336]: https://tools.ietf.org/html/rfc8336 +[Readable Stream]: stream.html#stream_class_stream_readable [Using options.selectPadding]: #http2_using_options_selectpadding [Writable Stream]: stream.html#stream_writable_streams [`'checkContinue'`]: #http2_event_checkcontinue @@ -3394,15 +3394,15 @@ following additional properties: [`ServerHttp2Stream`]: #http2_class_serverhttp2stream [`TypeError`]: errors.html#errors_class_typeerror [`http2.SecureServer`]: #http2_class_http2secureserver -[`http2.createSecureServer()`]: #http2_http2_createsecureserver_options_onrequesthandler [`http2.Server`]: #http2_class_http2server +[`http2.createSecureServer()`]: #http2_http2_createsecureserver_options_onrequesthandler [`http2.createServer()`]: #http2_http2_createserver_options_onrequesthandler [`http2session.close()`]: #http2_http2session_close_callback [`http2stream.pushStream()`]: #http2_http2stream_pushstream_headers_options_callback [`net.Server.close()`]: net.html#net_server_close_callback -[`net.Socket`]: net.html#net_class_net_socket [`net.Socket.prototype.ref`]: net.html#net_socket_ref [`net.Socket.prototype.unref`]: net.html#net_socket_unref +[`net.Socket`]: net.html#net_class_net_socket [`net.connect()`]: net.html#net_net_connect [`request.socket.getPeerCertificate()`]: tls.html#tls_tlssocket_getpeercertificate_detailed [`response.end()`]: #http2_response_end_data_encoding_callback diff --git a/doc/api/https.md b/doc/api/https.md index f6c0da5cbb0a7d..5b25991ecf0d51 100644 --- a/doc/api/https.md +++ b/doc/api/https.md @@ -263,8 +263,8 @@ const req = https.request(options, (res) => { [`http.Server#setTimeout()`]: http.html#http_server_settimeout_msecs_callback [`http.Server#timeout`]: http.html#http_server_timeout [`http.Server`]: http.html#http_class_http_server -[`http.createServer()`]: http.html#httpcreateserveroptions-requestlistener [`http.close()`]: http.html#http_server_close_callback +[`http.createServer()`]: http.html#httpcreateserveroptions-requestlistener [`http.get()`]: http.html#http_http_get_options_callback [`http.request()`]: http.html#http_http_request_options_callback [`https.Agent`]: #https_class_https_agent diff --git a/doc/api/inspector.md b/doc/api/inspector.md index bd277ff0a8f090..b9db325f9a2c8a 100644 --- a/doc/api/inspector.md +++ b/doc/api/inspector.md @@ -121,7 +121,7 @@ session.post('Runtime.evaluate', { expression: '2 + 2' }, The latest version of the V8 inspector protocol is published on the [Chrome DevTools Protocol Viewer][]. -Node inspector supports all the Chrome DevTools Protocol domains declared +Node.js inspector supports all the Chrome DevTools Protocol domains declared by V8. Chrome DevTools Protocol domain provides an interface for interacting with one of the runtime agents used to inspect the application state and listen to the run-time events. @@ -162,8 +162,8 @@ session.post('Profiler.enable', () => { ``` -[`session.connect()`]: #inspector_session_connect [`Debugger.paused`]: https://chromedevtools.github.io/devtools-protocol/v8/Debugger/#event-paused [`EventEmitter`]: events.html#events_class_eventemitter -[Chrome DevTools Protocol Viewer]: https://chromedevtools.github.io/devtools-protocol/v8/ +[`session.connect()`]: #inspector_session_connect [CPU Profiler]: https://chromedevtools.github.io/devtools-protocol/v8/Profiler +[Chrome DevTools Protocol Viewer]: https://chromedevtools.github.io/devtools-protocol/v8/ diff --git a/doc/api/intl.md b/doc/api/intl.md index 147ef38664076e..36fdb6a74b0ec5 100644 --- a/doc/api/intl.md +++ b/doc/api/intl.md @@ -193,18 +193,18 @@ to be helpful: ["ICU Data"]: http://userguide.icu-project.org/icudata [`--icu-data-dir`]: cli.html#cli_icu_data_dir_file [`Date.prototype.toLocaleString()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString -[`Intl`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl [`Intl.DateTimeFormat`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat +[`Intl`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl [`NODE_ICU_DATA`]: cli.html#cli_node_icu_data_file [`Number.prototype.toLocaleString()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toLocaleString -[`require('buffer').transcode()`]: buffer.html#buffer_buffer_transcode_source_fromenc_toenc -[`require('util').TextDecoder`]: util.html#util_class_util_textdecoder [`String.prototype.localeCompare()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare [`String.prototype.normalize()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize [`String.prototype.toLowerCase()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase [`String.prototype.toUpperCase()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase -[BUILDING.md]: https://github.com/nodejs/node/blob/master/BUILDING.md +[`require('buffer').transcode()`]: buffer.html#buffer_buffer_transcode_source_fromenc_toenc +[`require('util').TextDecoder`]: util.html#util_class_util_textdecoder [BUILDING.md#full-icu]: https://github.com/nodejs/node/blob/master/BUILDING.md#build-with-full-icu-support-all-locales-supported-by-icu +[BUILDING.md]: https://github.com/nodejs/node/blob/master/BUILDING.md [ECMA-262]: https://tc39.github.io/ecma262/ [ECMA-402]: https://tc39.github.io/ecma402/ [ICU]: http://icu-project.org/ diff --git a/doc/api/modules.md b/doc/api/modules.md index 6bac6a8b23144b..64da839077d26f 100644 --- a/doc/api/modules.md +++ b/doc/api/modules.md @@ -375,8 +375,9 @@ example, then `require('./some-library')` would attempt to load: If the module identifier passed to `require()` is not a [core](#modules_core_modules) module, and does not begin with `'/'`, `'../'`, or `'./'`, then Node.js starts at the parent directory of the current module, and -adds `/node_modules`, and attempts to load the module from that location. Node -will not append `node_modules` to a path already ending in `node_modules`. +adds `/node_modules`, and attempts to load the module from that location. +Node.js will not append `node_modules` to a path already ending in +`node_modules`. If it is not found there, then it moves to the parent directory, and so on, until the root of the file system is reached. @@ -551,7 +552,22 @@ added: v0.1.13 * {Function} -To require modules. +Used to import modules, `JSON`, and local files. Modules can be imported +from `node_modules`. Local modules and JSON files can be imported using +a relative path (e.g. `./`, `./foo`, `./bar/baz`, `../foo`) that will be +resolved against the directory named by [`__dirname`][] (if defined) or +the current working directory. + +```js +// Importing a local module: +const myLocalModule = require('./path/myLocalModule'); + +// Importing a JSON file: +const jsonData = require('./path/filename.json'); + +// Importing a module from node_modules or Node.js built-in module: +const crypto = require('crypto'); +``` #### require.cache @@ -375,7 +375,7 @@ process.on('SIGTERM', handle); ``` * `SIGUSR1` is reserved by Node.js to start the [debugger][]. It's possible to - install a listener but doing so will _not_ stop the debugger from starting. + install a listener but doing so might interfere with the debugger. * `SIGTERM` and `SIGINT` have default handlers on non-Windows platforms that reset the terminal mode before exiting with code `128 + signal number`. If one of these signals has a listener installed, its default behavior will be @@ -499,6 +499,8 @@ $ bash -c 'exec -a customArgv0 ./node' added: v7.1.0 --> +* {Object} + If the Node.js process was spawned with an IPC channel (see the [Child Process][] documentation), the `process.channel` property is a reference to the IPC channel. If no IPC channel exists, this @@ -884,7 +886,7 @@ console.log(process.env.test); added: v0.7.7 --> -* {Object} +* {Array} The `process.execArgv` property returns the set of Node.js-specific command-line options passed when the Node.js process was launched. These options do not @@ -1210,6 +1212,8 @@ the debugger, see [Signal Events][]. added: v0.1.17 --> +* {Object} + The `process.mainModule` property provides an alternative way of retrieving [`require.main`][]. The difference is that if the main module changes at runtime, [`require.main`][] may still refer to the original main module in @@ -1439,6 +1443,8 @@ changes: description: The `lts` property is now supported. --> +* {Object} + The `process.release` property returns an Object containing metadata related to the current release, including URLs for the source tarball and headers-only tarball. @@ -1924,7 +1930,6 @@ cases: [`'rejectionHandled'`]: #process_event_rejectionhandled [`'uncaughtException'`]: #process_event_uncaughtexception [`ChildProcess.disconnect()`]: child_process.html#child_process_subprocess_disconnect -[`subprocess.kill()`]: child_process.html#child_process_subprocess_kill_signal [`ChildProcess.send()`]: child_process.html#child_process_subprocess_send_message_sendhandle_options_callback [`ChildProcess`]: child_process.html#child_process_class_childprocess [`Error`]: errors.html#errors_class_error @@ -1942,17 +1947,18 @@ cases: [`promise.catch()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch [`require.main`]: modules.html#modules_accessing_the_main_module [`setTimeout(fn, 0)`]: timers.html#timers_settimeout_callback_delay_args +[`subprocess.kill()`]: child_process.html#child_process_subprocess_kill_signal [Android building]: https://github.com/nodejs/node/blob/master/BUILDING.md#androidandroid-based-devices-eg-firefox-os [Child Process]: child_process.html [Cluster]: cluster.html -[debugger]: debugger.html [Duplex]: stream.html#stream_duplex_and_transform_streams [LTS]: https://github.com/nodejs/LTS/ -[note on process I/O]: process.html#process_a_note_on_process_i_o -[process_emit_warning]: #process_process_emitwarning_warning_type_code_ctor -[process_warning]: #process_event_warning [Readable]: stream.html#stream_readable_streams [Signal Events]: #process_signal_events [Stream compatibility]: stream.html#stream_compatibility_with_older_node_js_versions [TTY]: tty.html#tty_tty [Writable]: stream.html#stream_writable_streams +[debugger]: debugger.html +[note on process I/O]: process.html#process_a_note_on_process_i_o +[process_emit_warning]: #process_process_emitwarning_warning_type_code_ctor +[process_warning]: #process_event_warning diff --git a/doc/api/stream.md b/doc/api/stream.md index 5fa00932a5662b..db82c7c8184bcb 100644 --- a/doc/api/stream.md +++ b/doc/api/stream.md @@ -2258,12 +2258,12 @@ contain multi-byte characters. [`process.stderr`]: process.html#process_process_stderr [`process.stdin`]: process.html#process_process_stdin [`process.stdout`]: process.html#process_process_stdout +[`readable.push('')`]: #stream_readable_push [`stream.cork()`]: #stream_writable_cork [`stream.pipe()`]: #stream_readable_pipe_destination_options [`stream.uncork()`]: #stream_writable_uncork [`stream.unpipe()`]: #stream_readable_unpipe_destination [`stream.wrap()`]: #stream_readable_wrap_stream -[`readable.push('')`]: #stream_readable_push [`writable.cork()`]: #stream_writable_cork [`writable.uncork()`]: #stream_writable_uncork [`zlib.createDeflate()`]: zlib.html#zlib_zlib_createdeflate_options @@ -2283,21 +2283,21 @@ contain multi-byte characters. [fs read streams]: fs.html#fs_class_fs_readstream [fs write streams]: fs.html#fs_class_fs_writestream [http-incoming-message]: http.html#http_class_http_incomingmessage -[zlib]: zlib.html [hwm-gotcha]: #stream_highwatermark_discrepancy_after_calling_readable_setencoding +[readable-_destroy]: #stream_readable_destroy_err_callback +[readable-destroy]: #stream_readable_destroy_error +[stream-_final]: #stream_writable_final_callback [stream-_flush]: #stream_transform_flush_callback [stream-_read]: #stream_readable_read_size_1 [stream-_transform]: #stream_transform_transform_chunk_encoding_callback [stream-_write]: #stream_writable_write_chunk_encoding_callback_1 [stream-_writev]: #stream_writable_writev_chunks_callback -[stream-_final]: #stream_writable_final_callback [stream-end]: #stream_writable_end_chunk_encoding_callback [stream-pause]: #stream_readable_pause [stream-push]: #stream_readable_push_chunk_encoding [stream-read]: #stream_readable_read_size [stream-resume]: #stream_readable_resume [stream-write]: #stream_writable_write_chunk_encoding_callback -[readable-_destroy]: #stream_readable_destroy_err_callback -[readable-destroy]: #stream_readable_destroy_error [writable-_destroy]: #stream_writable_destroy_err_callback [writable-destroy]: #stream_writable_destroy_error +[zlib]: zlib.html diff --git a/doc/api/synopsis.md b/doc/api/synopsis.md index 508dde1ff483f8..88310e49e98650 100644 --- a/doc/api/synopsis.md +++ b/doc/api/synopsis.md @@ -14,7 +14,7 @@ An example of a [web server][] written with Node.js which responds with Commands displayed in this document are shown starting with `$` or `>` to replicate how they would appear in a user's terminal. -Do not include the `$` and `>` character they are there to +Do not include the `$` and `>` characters. They are there to indicate the start of each command. There are many tutorials and examples that follow this @@ -27,8 +27,8 @@ the output of the previous command. Firstly, make sure to have downloaded and installed Node.js. See [this guide][] for further install information. -Now, create an empty project folder called `projects`, navigate into it: -Project folder can be named base on user's current project title but +Now, create an empty project folder called `projects`, then navigate into it. +The project folder can be named based on the user's current project title, but this example will use `projects` as the project folder. Linux and Mac: @@ -60,7 +60,7 @@ hyphens (`-`) or underscores (`_`) to separate multiple words in filenames. Open `hello-world.js` in any preferred text editor and -paste in the following content. +paste in the following content: ```js const http = require('http'); @@ -100,5 +100,5 @@ the server is working. Many of the examples in the documentation can be run similarly. [Command Line Options]: cli.html#cli_command_line_options -[web server]: http.html [this guide]: https://nodejs.org/en/download/package-manager/ +[web server]: http.html diff --git a/doc/api/tls.md b/doc/api/tls.md index ff81999b1d8b74..d57f76439d2034 100644 --- a/doc/api/tls.md +++ b/doc/api/tls.md @@ -673,7 +673,6 @@ be returned for server sockets or disconnected client sockets. Example responses include: -* `SSLv3` * `TLSv1` * `TLSv1.1` * `TLSv1.2` @@ -1363,6 +1362,7 @@ where `secure_socket` has the same API as `pair.cleartext`. [`'secureConnect'`]: #tls_event_secureconnect [`'secureConnection'`]: #tls_event_secureconnection [`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 @@ -1385,6 +1385,7 @@ where `secure_socket` has the same API as `pair.cleartext`. [OpenSSL cipher list format documentation]: https://www.openssl.org/docs/man1.0.2/apps/ciphers.html#CIPHER-LIST-FORMAT [Perfect Forward Secrecy]: #tls_perfect_forward_secrecy [RFC 4492]: https://www.rfc-editor.org/rfc/rfc4492.txt +[RFC 5929]: https://tools.ietf.org/html/rfc5929 [SSL_CTX_set_timeout]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_CTX_set_timeout.html [SSL_METHODS]: https://www.openssl.org/docs/man1.0.2/ssl/ssl.html#DEALING-WITH-PROTOCOL-METHODS [Stream]: stream.html#stream_stream @@ -1394,5 +1395,3 @@ where `secure_socket` has the same API as `pair.cleartext`. [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/tty.md b/doc/api/tty.md index 8b757c0f02751a..d812568eb30e79 100644 --- a/doc/api/tty.md +++ b/doc/api/tty.md @@ -133,6 +133,6 @@ a TTY and `false` if it is not, including whenever `fd` is not a non-negative integer. [`net.Socket`]: net.html#net_class_net_socket +[`process.stderr`]: process.html#process_process_stderr [`process.stdin`]: process.html#process_process_stdin [`process.stdout`]: process.html#process_process_stdout -[`process.stderr`]: process.html#process_process_stderr diff --git a/doc/api/v8.md b/doc/api/v8.md index 81a8769dc6a14d..939613e4a48c4d 100644 --- a/doc/api/v8.md +++ b/doc/api/v8.md @@ -394,6 +394,7 @@ A subclass of [`Deserializer`][] corresponding to the format written by [`DefaultSerializer`]: #v8_class_v8_defaultserializer [`Deserializer`]: #v8_class_v8_deserializer [`Error`]: errors.html#errors_class_error +[`GetHeapSpaceStatistics`]: https://v8docs.nodesource.com/node-8.0/d5/dda/classv8_1_1_isolate.html#ac673576f24fdc7a33378f8f57e1d13a4 [`Serializer`]: #v8_class_v8_serializer [`deserializer._readHostObject()`]: #v8_deserializer_readhostobject [`deserializer.transferArrayBuffer()`]: #v8_deserializer_transferarraybuffer_id_arraybuffer @@ -403,8 +404,7 @@ A subclass of [`Deserializer`][] corresponding to the format written by [`serializer.releaseBuffer()`]: #v8_serializer_releasebuffer [`serializer.transferArrayBuffer()`]: #v8_serializer_transferarraybuffer_id_arraybuffer [`serializer.writeRawBytes()`]: #v8_serializer_writerawbytes_buffer +[`vm.Script`]: vm.html#vm_new_vm_script_code_options [HTML structured clone algorithm]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm [V8]: https://developers.google.com/v8/ -[`vm.Script`]: vm.html#vm_new_vm_script_code_options [here]: https://github.com/thlorenz/v8-flags/blob/master/flags-0.11.md -[`GetHeapSpaceStatistics`]: https://v8docs.nodesource.com/node-8.0/d5/dda/classv8_1_1_isolate.html#ac673576f24fdc7a33378f8f57e1d13a4 diff --git a/doc/api/zlib.md b/doc/api/zlib.md index 1bf6d2ccf11d01..2f7540596388e2 100644 --- a/doc/api/zlib.md +++ b/doc/api/zlib.md @@ -713,6 +713,7 @@ Decompress a chunk of data with [Unzip][]. [`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 [`TypedArray`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray +[`UV_THREADPOOL_SIZE`]: cli.html#cli_uv_threadpool_size_size [DeflateRaw]: #zlib_class_zlib_deflateraw [Deflate]: #zlib_class_zlib_deflate [Gunzip]: #zlib_class_zlib_gunzip @@ -721,6 +722,5 @@ Decompress a chunk of data with [Unzip][]. [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 [options]: #zlib_class_options [zlib documentation]: https://zlib.net/manual.html#Constants diff --git a/doc/changelogs/CHANGELOG_V8.md b/doc/changelogs/CHANGELOG_V8.md index a6f471aa38c8f8..242bec1616a77e 100644 --- a/doc/changelogs/CHANGELOG_V8.md +++ b/doc/changelogs/CHANGELOG_V8.md @@ -10,6 +10,7 @@ +8.14.1
8.14.0
8.13.0
8.12.0
@@ -59,6 +60,106 @@ [Node.js Long Term Support Plan](https://github.com/nodejs/LTS) and will be supported actively until April 2019 and maintained until December 2019. + +## 2018-12-18, Version 8.14.1 'Carbon' (LTS), @MylesBorins prepared by @BethGriggs + +### Notable changes + +* **assert**: + - revert breaking change (Ruben Bridgewater) [#24786](https://github.com/nodejs/node/pull/24786) +* **http2**: + - fix sequence of error/close events (Gerhard Stoebich) [#24789](https://github.com/nodejs/node/pull/24789) + +### Commits + +* [[`62fb5dbec5`](https://github.com/nodejs/node/commit/62fb5dbec5)] - **assert**: revert breaking change (Ruben Bridgewater) [#24786](https://github.com/nodejs/node/pull/24786) +* [[`a8402fe1c8`](https://github.com/nodejs/node/commit/a8402fe1c8)] - **build**: only check REPLACEME & DEP...X for releases (Rod Vagg) [#24575](https://github.com/nodejs/node/pull/24575) +* [[`26743369d3`](https://github.com/nodejs/node/commit/26743369d3)] - **build**: improve Travis CI settings (Timothy Gu) [#21459](https://github.com/nodejs/node/pull/21459) +* [[`1da04c208d`](https://github.com/nodejs/node/commit/1da04c208d)] - **build**: install markdown linter for travis (Richard Lau) [#21215](https://github.com/nodejs/node/pull/21215) +* [[`7612024939`](https://github.com/nodejs/node/commit/7612024939)] - **build**: initial .travis.yml implementation (Anna Henningsen) [#21059](https://github.com/nodejs/node/pull/21059) +* [[`f70e79a7b2`](https://github.com/nodejs/node/commit/f70e79a7b2)] - **build**: allow for overwriting of use\_openssl\_def (Shelley Vohr) [#23763](https://github.com/nodejs/node/pull/23763) +* [[`15d1f67c60`](https://github.com/nodejs/node/commit/15d1f67c60)] - **build,doc**: remove outdated `lint-md-build` (Michaël Zasso) [#22991](https://github.com/nodejs/node/pull/22991) +* [[`85a6daeaef`](https://github.com/nodejs/node/commit/85a6daeaef)] - **build,meta**: switch to gcc-4.9 on travis (Refael Ackermann) [#23778](https://github.com/nodejs/node/pull/23778) +* [[`313ef6fa73`](https://github.com/nodejs/node/commit/313ef6fa73)] - **build,tools**: tweak the travis config (Refael Ackermann) [#22417](https://github.com/nodejs/node/pull/22417) +* [[`22b41495ea`](https://github.com/nodejs/node/commit/22b41495ea)] - **child_process**: handle undefined/null for fork() args (Shobhit Chittora) [#22416](https://github.com/nodejs/node/pull/22416) +* [[`499605618b`](https://github.com/nodejs/node/commit/499605618b)] - **crypto**: add SET\_INTEGER\_CONSANT macro (Daniel Bevenius) [#23687](https://github.com/nodejs/node/pull/23687) +* [[`34d91296df`](https://github.com/nodejs/node/commit/34d91296df)] - **deps**: icu: apply workaround patch (Steven R. Loomis) [#23764](https://github.com/nodejs/node/pull/23764) +* [[`50347297a1`](https://github.com/nodejs/node/commit/50347297a1)] - **deps**: cherry-pick d2e0166 from V8 upstream (Vasili Skurydzin) [#23958](https://github.com/nodejs/node/pull/23958) +* [[`9bedae5266`](https://github.com/nodejs/node/commit/9bedae5266)] - **deps**: cherry-pick 6bc4bfe from V8 upstream (Vasili Skurydzin) [#23958](https://github.com/nodejs/node/pull/23958) +* [[`4f3c9e6aab`](https://github.com/nodejs/node/commit/4f3c9e6aab)] - **deps,v8**: fix gyp build on Aix platform (Vasili Skurydzin) [#23958](https://github.com/nodejs/node/pull/23958) +* [[`74c1074d53`](https://github.com/nodejs/node/commit/74c1074d53)] - **doc**: add description for inspector-only console methods. (Benjamin Zaslavsky) [#17004](https://github.com/nodejs/node/pull/17004) +* [[`692223182c`](https://github.com/nodejs/node/commit/692223182c)] - **doc**: fix api documentation of http.createServer (Ari Autio) [#24869](https://github.com/nodejs/node/pull/24869) +* [[`6d8c65e574`](https://github.com/nodejs/node/commit/6d8c65e574)] - **doc**: update to adding listens on SIGUSR1 (willhayslett) [#19709](https://github.com/nodejs/node/pull/19709) +* [[`33b7c50036`](https://github.com/nodejs/node/commit/33b7c50036)] - **doc**: remove "if provided" for optional arguments (Rich Trott) [#19690](https://github.com/nodejs/node/pull/19690) +* [[`216e7da8c5`](https://github.com/nodejs/node/commit/216e7da8c5)] - **doc**: do not identify string as "JavaScript string" (Rich Trott) [#19689](https://github.com/nodejs/node/pull/19689) +* [[`17e84217c7`](https://github.com/nodejs/node/commit/17e84217c7)] - **doc**: fix grammar error in process.md (Kenji Okamoto) [#19641](https://github.com/nodejs/node/pull/19641) +* [[`06daf5276f`](https://github.com/nodejs/node/commit/06daf5276f)] - **doc**: remove use of "random port" re dgram send (Thomas Hunter II) [#19620](https://github.com/nodejs/node/pull/19620) +* [[`bf95392e86`](https://github.com/nodejs/node/commit/bf95392e86)] - **doc**: improve assert legacy text (Rich Trott) [#19622](https://github.com/nodejs/node/pull/19622) +* [[`e48cc3c403`](https://github.com/nodejs/node/commit/e48cc3c403)] - **doc**: remove confusing note about child process stdio (Anna Henningsen) [#19552](https://github.com/nodejs/node/pull/19552) +* [[`9d249bf6d5`](https://github.com/nodejs/node/commit/9d249bf6d5)] - **doc**: add BethGriggs to collaborators (Beth Griggs) [#19610](https://github.com/nodejs/node/pull/19610) +* [[`c3ecf05b01`](https://github.com/nodejs/node/commit/c3ecf05b01)] - **doc**: document `make docopen` (Ayush Gupta) [#19321](https://github.com/nodejs/node/pull/19321) +* [[`8338700d05`](https://github.com/nodejs/node/commit/8338700d05)] - **doc**: add directory structure in writing-tests.md (juggernaut451) [#18802](https://github.com/nodejs/node/pull/18802) +* [[`63d8632611`](https://github.com/nodejs/node/commit/63d8632611)] - **doc**: add types for some `process` properties (Vse Mozhet Byt) [#19571](https://github.com/nodejs/node/pull/19571) +* [[`b2fc3b556c`](https://github.com/nodejs/node/commit/b2fc3b556c)] - **doc**: fix n-api example string (Steven R. Loomis) [#19205](https://github.com/nodejs/node/pull/19205) +* [[`d79e7d6e89`](https://github.com/nodejs/node/commit/d79e7d6e89)] - **doc**: minor improvements to buffer.md (Rich Trott) [#19547](https://github.com/nodejs/node/pull/19547) +* [[`06491482f8`](https://github.com/nodejs/node/commit/06491482f8)] - **doc**: update child\_process.md (Ari Leo Frankel) [#19075](https://github.com/nodejs/node/pull/19075) +* [[`4db289ca17`](https://github.com/nodejs/node/commit/4db289ca17)] - **doc**: move StackOverflow to unofficial section (josephleon) [#19416](https://github.com/nodejs/node/pull/19416) +* [[`f5683a9a6d`](https://github.com/nodejs/node/commit/f5683a9a6d)] - **doc**: correct async\_hooks resource names (Gerhard Stoebich) [#24684](https://github.com/nodejs/node/pull/24684) +* [[`ffe1f8033c`](https://github.com/nodejs/node/commit/ffe1f8033c)] - **doc**: sort bottom-of-file markdown links (Sam Roberts) [#24682](https://github.com/nodejs/node/pull/24682) +* [[`78d9a5e6e4`](https://github.com/nodejs/node/commit/78d9a5e6e4)] - **doc**: address bits of proof reading work (Jagannath Bhat) [#23978](https://github.com/nodejs/node/pull/23978) +* [[`d1eebb2e43`](https://github.com/nodejs/node/commit/d1eebb2e43)] - **doc**: revise COLLABORATOR\_GUIDE.md (Rich Trott) [#23990](https://github.com/nodejs/node/pull/23990) +* [[`003eb0c8e1`](https://github.com/nodejs/node/commit/003eb0c8e1)] - **doc**: simplify CODE\_OF\_CONDUCT.md (Rich Trott) [#23989](https://github.com/nodejs/node/pull/23989) +* [[`c1723c8bca`](https://github.com/nodejs/node/commit/c1723c8bca)] - **doc**: add branding to style guide (Rich Trott) [#23967](https://github.com/nodejs/node/pull/23967) +* [[`8bb67a1fb9`](https://github.com/nodejs/node/commit/8bb67a1fb9)] - **doc**: use Node.js instead of Node (Rich Trott) [#23967](https://github.com/nodejs/node/pull/23967) +* [[`73e0bb1f52`](https://github.com/nodejs/node/commit/73e0bb1f52)] - **doc**: fix typographical issues (Denis McDonald) [#23970](https://github.com/nodejs/node/pull/23970) +* [[`6d76f852a9`](https://github.com/nodejs/node/commit/6d76f852a9)] - **doc**: add documentation for http.IncomingMessage$complete (James M Snell) [#23914](https://github.com/nodejs/node/pull/23914) +* [[`3025f351db`](https://github.com/nodejs/node/commit/3025f351db)] - **doc**: remove mailing list (Rich Trott) [#23932](https://github.com/nodejs/node/pull/23932) +* [[`2459e150bb`](https://github.com/nodejs/node/commit/2459e150bb)] - **doc**: add note about ABI compatibility (Myles Borins) [#22237](https://github.com/nodejs/node/pull/22237) +* [[`27b35833bd`](https://github.com/nodejs/node/commit/27b35833bd)] - **doc**: make example more clarified in cluster.md (ZYSzys) [#23931](https://github.com/nodejs/node/pull/23931) +* [[`0d4de59967`](https://github.com/nodejs/node/commit/0d4de59967)] - **doc**: simplify valid security issue descriptions (Rich Trott) [#23881](https://github.com/nodejs/node/pull/23881) +* [[`9afdc09f98`](https://github.com/nodejs/node/commit/9afdc09f98)] - **doc**: simplify path.basename() on POSIX and Windows (ZYSzys) [#23864](https://github.com/nodejs/node/pull/23864) +* [[`3f2a01688d`](https://github.com/nodejs/node/commit/3f2a01688d)] - **doc**: add review suggestions to require() (erickwendel) [#23605](https://github.com/nodejs/node/pull/23605) +* [[`f037942fe7`](https://github.com/nodejs/node/commit/f037942fe7)] - **doc**: move @phillipj to emeriti (Phillip Johnsen) [#23790](https://github.com/nodejs/node/pull/23790) +* [[`e5f75cf82e`](https://github.com/nodejs/node/commit/e5f75cf82e)] - **doc**: add note about removeListener order (James M Snell) [#23762](https://github.com/nodejs/node/pull/23762) +* [[`0ff88a3510`](https://github.com/nodejs/node/commit/0ff88a3510)] - **doc**: document ACL limitation for fs.access on Windows (James M Snell) [#23772](https://github.com/nodejs/node/pull/23772) +* [[`32ae851710`](https://github.com/nodejs/node/commit/32ae851710)] - **doc**: document that addMembership must be called once in a cluster (James M Snell) [#23746](https://github.com/nodejs/node/pull/23746) +* [[`e2d2ce6706`](https://github.com/nodejs/node/commit/e2d2ce6706)] - **doc**: remove reference to sslv3 in tls.md (James M Snell) [#23745](https://github.com/nodejs/node/pull/23745) +* [[`4c24a82a65`](https://github.com/nodejs/node/commit/4c24a82a65)] - **http2**: fix sequence of error/close events (Gerhard Stoebich) [#24789](https://github.com/nodejs/node/pull/24789) +* [[`8afbd5ce41`](https://github.com/nodejs/node/commit/8afbd5ce41)] - **lib**: fix a typo in lib/timers "read through" (wangzengdi) [#19666](https://github.com/nodejs/node/pull/19666) +* [[`fa12532000`](https://github.com/nodejs/node/commit/fa12532000)] - **lib**: remove useless cwd in posix.resolve (ZYSzys) [#23902](https://github.com/nodejs/node/pull/23902) +* [[`e8dbd09414`](https://github.com/nodejs/node/commit/e8dbd09414)] - **src**: use "constants" string instead of creating new one (Ouyang Yadong) [#23894](https://github.com/nodejs/node/pull/23894) +* [[`394cb42962`](https://github.com/nodejs/node/commit/394cb42962)] - **test**: verify order of error in h2 server stream (Myles Borins) [#24685](https://github.com/nodejs/node/pull/24685) +* [[`5e09a3d4ed`](https://github.com/nodejs/node/commit/5e09a3d4ed)] - **test**: test process.setuid for bad argument types (Divyanshu Singh) [#19703](https://github.com/nodejs/node/pull/19703) +* [[`970164f3a8`](https://github.com/nodejs/node/commit/970164f3a8)] - **test**: improve assert message (fatahn) [#19629](https://github.com/nodejs/node/pull/19629) +* [[`086570e4e1`](https://github.com/nodejs/node/commit/086570e4e1)] - **test**: remove third argument from call to assert.strictEqual() (Forrest Wolf) [#19659](https://github.com/nodejs/node/pull/19659) +* [[`a7b3274af4`](https://github.com/nodejs/node/commit/a7b3274af4)] - **test**: fix flaky test-cluster-send-handle-twice (Rich Trott) [#19700](https://github.com/nodejs/node/pull/19700) +* [[`1bda58289a`](https://github.com/nodejs/node/commit/1bda58289a)] - **test**: rename regression tests more expressively (Ujjwal Sharma) [#19668](https://github.com/nodejs/node/pull/19668) +* [[`bd9cc92e8d`](https://github.com/nodejs/node/commit/bd9cc92e8d)] - **test**: remove 3rd argument from assert.strictEqual (Arian Santrach) [#19707](https://github.com/nodejs/node/pull/19707) +* [[`3ca10faf00`](https://github.com/nodejs/node/commit/3ca10faf00)] - **test**: use createReadStream instead of ReadStream (Daniel Bevenius) [#19636](https://github.com/nodejs/node/pull/19636) +* [[`8a546e822d`](https://github.com/nodejs/node/commit/8a546e822d)] - **test**: removed default message from assert.strictEqual (jaspal-yupana) [#19660](https://github.com/nodejs/node/pull/19660) +* [[`a62df1b379`](https://github.com/nodejs/node/commit/a62df1b379)] - **test**: refactor test-net-dns-error (Luigi Pinca) [#19640](https://github.com/nodejs/node/pull/19640) +* [[`8a0ecf4360`](https://github.com/nodejs/node/commit/8a0ecf4360)] - **test**: refactor test-http-expect-continue (Rich Trott) [#19625](https://github.com/nodejs/node/pull/19625) +* [[`0cbe813e90`](https://github.com/nodejs/node/commit/0cbe813e90)] - **test**: update link according to NIST bibliography (Tobias Nießen) [#19593](https://github.com/nodejs/node/pull/19593) +* [[`ea1fda6228`](https://github.com/nodejs/node/commit/ea1fda6228)] - **test**: remove third param from assert.strictEqual (davis.okoth@kemsa.co.ke) [#19536](https://github.com/nodejs/node/pull/19536) +* [[`18c4e5e886`](https://github.com/nodejs/node/commit/18c4e5e886)] - **test**: remove message from assert.strictEqual() (willhayslett) [#19525](https://github.com/nodejs/node/pull/19525) +* [[`146c488bf5`](https://github.com/nodejs/node/commit/146c488bf5)] - **test**: refactor parallel/test-tls-ca-concat.js (juggernaut451) [#19092](https://github.com/nodejs/node/pull/19092) +* [[`8fa5bd3761`](https://github.com/nodejs/node/commit/8fa5bd3761)] - **test**: rename regression tests file names (Ujjwal Sharma) [#19332](https://github.com/nodejs/node/pull/19332) +* [[`d34ade8755`](https://github.com/nodejs/node/commit/d34ade8755)] - **test**: fix strictEqual arguments order (Esteban Sotillo) [#23956](https://github.com/nodejs/node/pull/23956) +* [[`6ae07a9248`](https://github.com/nodejs/node/commit/6ae07a9248)] - **test**: add property for RangeError in test-buffer-copy (mritunjaygoutam12) [#23968](https://github.com/nodejs/node/pull/23968) +* [[`b1e6de80c1`](https://github.com/nodejs/node/commit/b1e6de80c1)] - **test**: fix regression when compiled with FIPS (Adam Majer) [#23871](https://github.com/nodejs/node/pull/23871) +* [[`d0368b8245`](https://github.com/nodejs/node/commit/d0368b8245)] - **test**: fix strictEqual() argument order (Loic) [#23829](https://github.com/nodejs/node/pull/23829) +* [[`3a864d716e`](https://github.com/nodejs/node/commit/3a864d716e)] - **test**: fix strictEqual() arguments order (Nolan Rigo) [#23800](https://github.com/nodejs/node/pull/23800) +* [[`e7a573a9e2`](https://github.com/nodejs/node/commit/e7a573a9e2)] - **test**: fix test-require-symlink on Windows (Bartosz Sosnowski) [#23691](https://github.com/nodejs/node/pull/23691) +* [[`ac91346776`](https://github.com/nodejs/node/commit/ac91346776)] - **test**: fix strictEqual() argument order (Romain Lanz) [#23768](https://github.com/nodejs/node/pull/23768) +* [[`0f98c4926a`](https://github.com/nodejs/node/commit/0f98c4926a)] - **test**: fix strictEqual() arguments order (Thomas GENTILHOMME) [#23771](https://github.com/nodejs/node/pull/23771) +* [[`73d19b1516`](https://github.com/nodejs/node/commit/73d19b1516)] - **test**: ensure openssl version prints correctly (Sam Roberts) [#23678](https://github.com/nodejs/node/pull/23678) +* [[`544e64d68d`](https://github.com/nodejs/node/commit/544e64d68d)] - **test**: fix assertion arguments order (Elian Gutierrez) [#23787](https://github.com/nodejs/node/pull/23787) +* [[`e84c01d1f3`](https://github.com/nodejs/node/commit/e84c01d1f3)] - **tools**: update alternative docs versions (Richard Lau) [#23980](https://github.com/nodejs/node/pull/23980) +* [[`02209c5fa7`](https://github.com/nodejs/node/commit/02209c5fa7)] - **tools**: clarify commit message linting (Rich Trott) [#23742](https://github.com/nodejs/node/pull/23742) +* [[`22043ccb84`](https://github.com/nodejs/node/commit/22043ccb84)] - **tools**: do not lint commit message if var undefined (Rich Trott) [#23725](https://github.com/nodejs/node/pull/23725) +* [[`2a8a28c436`](https://github.com/nodejs/node/commit/2a8a28c436)] - **tools**: make Travis commit linting more robust (Rich Trott) [#23397](https://github.com/nodejs/node/pull/23397) +* [[`c15d236545`](https://github.com/nodejs/node/commit/c15d236545)] - **tools**: apply linting to first commit in PRs (Rich Trott) [#22452](https://github.com/nodejs/node/pull/22452) + ## 2018-11-27, Version 8.14.0 'Carbon' (LTS), @rvagg diff --git a/doc/guides/node-postmortem-support.md b/doc/guides/node-postmortem-support.md index e29d9ca3a1fdf0..b3c493bb04eeaa 100644 --- a/doc/guides/node-postmortem-support.md +++ b/doc/guides/node-postmortem-support.md @@ -15,8 +15,8 @@ Node always includes these constants in the final build. ### Node Debug Symbols -Node prefixes all postmortem constants with `nodedbg_`, and they complement V8 -constants by providing ways to inspect Node-specific structures, like +Node.js prefixes all postmortem constants with `nodedbg_`, and they complement +V8 constants by providing ways to inspect Node.js-specific structures, like `node::Environment`, `node::BaseObject` and its descendants, classes from `src/utils.h` and others. Those constants are declared in `src/node_postmortem_metadata.cc`, and most of them are calculated at compile @@ -62,7 +62,7 @@ class ReqWrap : public AsyncWrap { ``` There are also tests on `test/cctest/test_node_postmortem_metadata.cc` to make -sure all Node postmortem metadata are calculated correctly. +sure all Node.js postmortem metadata are calculated correctly. ## Tools and References diff --git a/doc/guides/writing-tests.md b/doc/guides/writing-tests.md index ec9398dcb928ec..b5f641289f77b6 100644 --- a/doc/guides/writing-tests.md +++ b/doc/guides/writing-tests.md @@ -18,6 +18,13 @@ Add tests when: - Fixing regressions and bugs. - Expanding test coverage. +## Test directory structure + +See [directory structure overview][] for outline of existing test & locations. +When deciding on whether to expand an existing test file or create a new one, +consider going through the files related to the subsystem. +For example, look for `test-streams` when writing a test for `lib/streams.js`. + ## Test structure Let's analyze this basic test from the Node.js test suite: @@ -376,3 +383,4 @@ will depend on what is being tested if this is required or not. [all maintained branches]: https://github.com/nodejs/lts [node.green]: http://node.green/ [test fixture]: https://github.com/google/googletest/blob/master/googletest/docs/Primer.md#test-fixtures-using-the-same-data-configuration-for-multiple-tests +[directory structure overview]: https://github.com/nodejs/node/blob/master/test/README.md#test-directories diff --git a/doc/node.1 b/doc/node.1 index aa2d4f4f8afcf1..76b7455953d5af 100644 --- a/doc/node.1 +++ b/doc/node.1 @@ -71,7 +71,7 @@ Print node's version. .TP .BR \-h ", " \-\-help -Print node command line options. +Print Node.js command line options. The output of this option is less detailed than this document. .TP @@ -93,7 +93,7 @@ Open the REPL even if stdin does not appear to be a terminal. .TP .BR \-r ", " \-\-require " " \fImodule\fR Preload the specified module at startup. Follows `require()`'s module resolution -rules. \fImodule\fR may be either a path to a file, or a node module name. +rules. \fImodule\fR may be either a path to a file, or a Node.js module name. .TP .BR \-\-inspect \fI[=[host:]port]\fR @@ -294,7 +294,7 @@ When set to \fI1\fR, the http2 module is suppressed. .BR NODE_OPTIONS =\fIoptions...\fR A space-separated list of command line options. \fBoptions...\fR are interpreted as if they had been specified on the command line before the actual command line -(so they can be overridden). Node will exit with an error if an option that is +(so they can be overridden). Node.js will exit with an error if an option that is not allowed in the environment is used, such as \fB-p\fR or a script file. .TP @@ -366,9 +366,6 @@ Documentation: GitHub repository & Issue Tracker: .ur https://github.com/nodejs/node -Mailing list: -.ur http://groups.google.com/group/nodejs - IRC (general questions): .ur "chat.freenode.net #node.js" (unofficial) diff --git a/doc/releases.md b/doc/releases.md index 06dbf47bc7d227..e63130fb4a2017 100644 --- a/doc/releases.md +++ b/doc/releases.md @@ -269,8 +269,8 @@ Merge your release proposal branch into the stable branch that you are releasing Cherry-pick the release commit to `master`. After cherry-picking, edit `src/node_version.h` to ensure the version macros contain whatever values were previously on `master`. `NODE_VERSION_IS_RELEASE` should be `0`. -Run `make lint-md-build; make lint` before pushing to `master`, to make sure the -Changelog formatting passes the lint rules on `master`. +Run `make lint` before pushing to `master`, to make sure the Changelog +formatting passes the lint rules on `master`. ### 12. Promote and Sign the Release Builds diff --git a/lib/assert.js b/lib/assert.js index 594a5acfbde1e3..e29a381acb746d 100644 --- a/lib/assert.js +++ b/lib/assert.js @@ -782,7 +782,7 @@ function expectsNoError(stackStartFn, actual, error, message) { actual, expected: error, operator: stackStartFn.name, - message: `Got unwanted ${fnType}${details}\n${actual.message}`, + message: `Got unwanted ${fnType}${details}`, stackStartFn }); } diff --git a/lib/child_process.js b/lib/child_process.js index aa24c9f44ea0ab..a5134905975c89 100644 --- a/lib/child_process.js +++ b/lib/child_process.js @@ -65,6 +65,11 @@ exports.fork = function(modulePath /*, args, options*/) { args = arguments[pos++]; } + if (pos < arguments.length && + (arguments[pos] === undefined || arguments[pos] === null)) { + pos++; + } + if (pos < arguments.length && arguments[pos] != null) { if (typeof arguments[pos] !== 'object') { throw new TypeError('Incorrect value of args option'); diff --git a/lib/internal/http2/core.js b/lib/internal/http2/core.js index 4c184fcfe188df..055009d07c815b 100644 --- a/lib/internal/http2/core.js +++ b/lib/internal/http2/core.js @@ -1997,9 +1997,8 @@ class Http2Stream extends Duplex { // will destroy if it has been closed and there are no other open or // pending streams. session[kMaybeDestroy](); - process.nextTick(emit, this, 'close', code); callback(err); - + process.nextTick(emit, this, 'close', code); } // The Http2Stream can be destroyed if it has closed and if the readable // side has received the final chunk. diff --git a/lib/path.js b/lib/path.js index 17a7f0cadfce87..4b34ef2e4fa442 100644 --- a/lib/path.js +++ b/lib/path.js @@ -1156,16 +1156,13 @@ const posix = { resolve: function resolve() { var resolvedPath = ''; var resolvedAbsolute = false; - var cwd; for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { var path; if (i >= 0) path = arguments[i]; else { - if (cwd === undefined) - cwd = process.cwd(); - path = cwd; + path = process.cwd(); } assertPath(path); diff --git a/lib/timers.js b/lib/timers.js index e6655c2f527349..5631878dc24039 100644 --- a/lib/timers.js +++ b/lib/timers.js @@ -66,7 +66,7 @@ const TIMEOUT_MAX = 2147483647; // 2^31-1 // Therefore, it is very important that the timers implementation is performant // and efficient. // -// Note: It is suggested you first read though the lib/internal/linkedlist.js +// Note: It is suggested you first read through the lib/internal/linkedlist.js // linked list implementation, since timers depend on it extensively. It can be // somewhat counter-intuitive at first, as it is not actually a class. Instead, // it is a set of helpers that operate on an existing object. diff --git a/node.gyp b/node.gyp index cb0036629e21a1..ed20a490d9ee1d 100644 --- a/node.gyp +++ b/node.gyp @@ -164,9 +164,9 @@ [ 'OS=="win" and ' 'node_use_openssl=="true" and ' 'node_shared_openssl=="false"', { - 'use_openssl_def': 1, + 'use_openssl_def%': 1, }, { - 'use_openssl_def': 0, + 'use_openssl_def%': 0, }], ], }, diff --git a/src/node_crypto.cc b/src/node_crypto.cc index c3779c07cccb74..d0e17717d9c2cb 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -469,16 +469,16 @@ void SecureContext::Initialize(Environment* env, Local target) { env->SetProtoMethod(t, "getCertificate", SecureContext::GetCertificate); env->SetProtoMethod(t, "getIssuer", SecureContext::GetCertificate); - t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kTicketKeyReturnIndex"), - Integer::NewFromUnsigned(env->isolate(), kTicketKeyReturnIndex)); - t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kTicketKeyHMACIndex"), - Integer::NewFromUnsigned(env->isolate(), kTicketKeyHMACIndex)); - t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kTicketKeyAESIndex"), - Integer::NewFromUnsigned(env->isolate(), kTicketKeyAESIndex)); - t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kTicketKeyNameIndex"), - Integer::NewFromUnsigned(env->isolate(), kTicketKeyNameIndex)); - t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kTicketKeyIVIndex"), - Integer::NewFromUnsigned(env->isolate(), kTicketKeyIVIndex)); +#define SET_INTEGER_CONSTANTS(name, value) \ + t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), name), \ + Integer::NewFromUnsigned(env->isolate(), value)); + SET_INTEGER_CONSTANTS("kTicketKeyReturnIndex", kTicketKeyReturnIndex); + SET_INTEGER_CONSTANTS("kTicketKeyHMACIndex", kTicketKeyHMACIndex); + SET_INTEGER_CONSTANTS("kTicketKeyAESIndex", kTicketKeyAESIndex); + SET_INTEGER_CONSTANTS("kTicketKeyNameIndex", kTicketKeyNameIndex); + SET_INTEGER_CONSTANTS("kTicketKeyIVIndex", kTicketKeyIVIndex); + +#undef SET_INTEGER_CONSTANTS Local ctx_getter_templ = FunctionTemplate::New(env->isolate(), diff --git a/src/node_http2.cc b/src/node_http2.cc index f56489bc5a034e..ea94713ecbaefe 100644 --- a/src/node_http2.cc +++ b/src/node_http2.cc @@ -3289,7 +3289,7 @@ HTTP_STATUS_CODES(V) env->SetMethod(target, "packSettings", PackSettings); target->Set(context, - FIXED_ONE_BYTE_STRING(isolate, "constants"), + env->constants_string(), constants).FromJust(); target->Set(context, FIXED_ONE_BYTE_STRING(isolate, "nameForErrorCode"), diff --git a/src/node_version.h b/src/node_version.h index 251aa1f626378b..5d08e257e8ea90 100644 --- a/src/node_version.h +++ b/src/node_version.h @@ -29,7 +29,7 @@ #define NODE_VERSION_IS_LTS 1 #define NODE_VERSION_LTS_CODENAME "Carbon" -#define NODE_VERSION_IS_RELEASE 0 +#define NODE_VERSION_IS_RELEASE 1 #ifndef NODE_STRINGIFY #define NODE_STRINGIFY(n) NODE_STRINGIFY_HELPER(n) diff --git a/src/pipe_wrap.cc b/src/pipe_wrap.cc index 0f2259b789e464..9b1779b84561ad 100644 --- a/src/pipe_wrap.cc +++ b/src/pipe_wrap.cc @@ -117,7 +117,7 @@ void PipeWrap::Initialize(Local target, NODE_DEFINE_CONSTANT(constants, SERVER); NODE_DEFINE_CONSTANT(constants, IPC); target->Set(context, - FIXED_ONE_BYTE_STRING(env->isolate(), "constants"), + env->constants_string(), constants).FromJust(); } diff --git a/src/tcp_wrap.cc b/src/tcp_wrap.cc index 3ad0eb4e0ce4fe..65d5adabd86663 100644 --- a/src/tcp_wrap.cc +++ b/src/tcp_wrap.cc @@ -132,7 +132,7 @@ void TCPWrap::Initialize(Local target, NODE_DEFINE_CONSTANT(constants, SOCKET); NODE_DEFINE_CONSTANT(constants, SERVER); target->Set(context, - FIXED_ONE_BYTE_STRING(env->isolate(), "constants"), + env->constants_string(), constants).FromJust(); } diff --git a/test/fixtures/child-process-echo-options.js b/test/fixtures/child-process-echo-options.js new file mode 100644 index 00000000000000..04f3f8dcffe6a9 --- /dev/null +++ b/test/fixtures/child-process-echo-options.js @@ -0,0 +1 @@ +process.send({ env: process.env }); diff --git a/test/parallel/test-assert-async.js b/test/parallel/test-assert-async.js index c397a4db081d49..237df0bb66ab28 100644 --- a/test/parallel/test-assert-async.js +++ b/test/parallel/test-assert-async.js @@ -34,7 +34,7 @@ common.crashOnUnhandledRejection(); assert(err instanceof assert.AssertionError, `${err.name} is not instance of AssertionError`); assert.strictEqual(err.code, 'ERR_ASSERTION'); - assert(/^Got unwanted rejection\.\n$/.test(err.message)); + assert(/^Got unwanted rejection\.$/.test(err.message)); assert.strictEqual(err.operator, 'doesNotReject'); assert.ok(!err.stack.includes('at Function.doesNotReject')); return true; diff --git a/test/parallel/test-assert.js b/test/parallel/test-assert.js index 7335982a6c6dc5..acedd9ed4fd75b 100644 --- a/test/parallel/test-assert.js +++ b/test/parallel/test-assert.js @@ -460,7 +460,7 @@ common.expectsError( type: a.AssertionError, code: 'ERR_ASSERTION', operator: 'doesNotThrow', - message: 'Got unwanted exception: user message\n[object Object]' + message: 'Got unwanted exception: user message' } ); diff --git a/test/parallel/test-buffer-copy.js b/test/parallel/test-buffer-copy.js index 1b10dadb5b709b..f2c6f466d21515 100644 --- a/test/parallel/test-buffer-copy.js +++ b/test/parallel/test-buffer-copy.js @@ -1,10 +1,16 @@ 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const b = Buffer.allocUnsafe(1024); const c = Buffer.allocUnsafe(512); + +const errorProperty = { + type: RangeError, + message: 'out of range index' +}; + let cntr = 0; { @@ -96,9 +102,9 @@ bb.fill('hello crazy world'); assert.doesNotThrow(() => { b.copy(c, 0, 100, 10); }); // copy throws at negative sourceStart -assert.throws(function() { - Buffer.allocUnsafe(5).copy(Buffer.allocUnsafe(5), 0, -1); -}, RangeError); +common.expectsError( + () => Buffer.allocUnsafe(5).copy(Buffer.allocUnsafe(5), 0, -1), + errorProperty); { // check sourceEnd resets to targetEnd if former is greater than the latter @@ -111,7 +117,8 @@ assert.throws(function() { } // throw with negative sourceEnd -assert.throws(() => b.copy(c, 0, 0, -1), RangeError); +common.expectsError( + () => b.copy(c, 0, -1), errorProperty); // when sourceStart is greater than sourceEnd, zero copied assert.strictEqual(b.copy(c, 0, 100, 10), 0); diff --git a/test/parallel/test-child-process-fork-options.js b/test/parallel/test-child-process-fork-options.js new file mode 100644 index 00000000000000..5efb9bdbb49735 --- /dev/null +++ b/test/parallel/test-child-process-fork-options.js @@ -0,0 +1,37 @@ +'use strict'; +const common = require('../common'); +const fixtures = require('../common/fixtures'); + +// This test ensures that fork should parse options +// correctly if args is undefined or null + +const assert = require('assert'); +const { fork } = require('child_process'); + +const expectedEnv = { foo: 'bar' }; + +{ + const cp = fork(fixtures.path('child-process-echo-options.js'), undefined, + { env: Object.assign({}, process.env, expectedEnv) }); + + cp.on('message', common.mustCall(({ env }) => { + assert.strictEqual(env.foo, expectedEnv.foo); + })); + + cp.on('exit', common.mustCall((code) => { + assert.strictEqual(code, 0); + })); +} + +{ + const cp = fork(fixtures.path('child-process-echo-options.js'), null, + { env: Object.assign({}, process.env, expectedEnv) }); + + cp.on('message', common.mustCall(({ env }) => { + assert.strictEqual(env.foo, expectedEnv.foo); + })); + + cp.on('exit', common.mustCall((code) => { + assert.strictEqual(code, 0); + })); +} diff --git a/test/parallel/test-cluster-send-handle-twice.js b/test/parallel/test-cluster-send-handle-twice.js index fc0d4a03085aec..9eb87d826daa20 100644 --- a/test/parallel/test-cluster-send-handle-twice.js +++ b/test/parallel/test-cluster-send-handle-twice.js @@ -40,10 +40,10 @@ if (cluster.isMaster) { })); } } else { - const server = net.createServer(function(socket) { + const server = net.createServer(common.mustCall((socket) => { process.send('send-handle-1', socket); process.send('send-handle-2', socket); - }); + })); server.listen(0, function() { const client = net.connect({ @@ -51,10 +51,9 @@ if (cluster.isMaster) { port: server.address().port }); client.on('close', common.mustCall(() => { cluster.worker.disconnect(); })); - setTimeout(function() { client.end(); }, 50); + client.on('connect', () => { client.end(); }); }).on('error', function(e) { console.error(e); assert.fail('server.listen failed'); - cluster.worker.disconnect(); }); } diff --git a/test/parallel/test-crypto-authenticated.js b/test/parallel/test-crypto-authenticated.js index 221009cb4a7a25..6b41b2b3557419 100644 --- a/test/parallel/test-crypto-authenticated.js +++ b/test/parallel/test-crypto-authenticated.js @@ -68,9 +68,8 @@ const TEST_CASES = [ ct: 'dda53a4059aa17b88756984995f7bba3c636cc44', tag: 'd2a35e5c611e5e3d2258360241c5b045', tampered: false }, - // Following test cases are from - // http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/ - // proposedmodes/gcm/gcm-revised-spec.pdf + // Following test cases are from "The Galois/Counter Mode of Operation (GCM)" + // by D. McGrew and J. Viega, published by NIST. // Test case 1 { algo: 'aes-128-gcm', diff --git a/test/parallel/test-fs-mkdir-rmdir.js b/test/parallel/test-fs-mkdir-rmdir.js index 865a5dba951555..6ab2bfcd866837 100644 --- a/test/parallel/test-fs-mkdir-rmdir.js +++ b/test/parallel/test-fs-mkdir-rmdir.js @@ -31,8 +31,8 @@ fs.mkdir(d, 0o666, common.mustCall(function(err) { fs.mkdir(d, 0o666, common.mustCall(function(err) { assert.ok(err, 'got no error'); assert.ok(/^EEXIST/.test(err.message), 'got no EEXIST message'); - assert.strictEqual(err.code, 'EEXIST', 'got no EEXIST code'); - assert.strictEqual(err.path, d, 'got no proper path for EEXIST'); + assert.strictEqual(err.code, 'EEXIST'); + assert.strictEqual(err.path, d); fs.rmdir(d, assert.ifError); })); diff --git a/test/parallel/test-fs-read-stream.js b/test/parallel/test-fs-read-stream.js index 2600f74b5452cb..8527b86925e4f4 100644 --- a/test/parallel/test-fs-read-stream.js +++ b/test/parallel/test-fs-read-stream.js @@ -34,7 +34,7 @@ const rangeFile = fixtures.path('x.txt'); let paused = false; let bytesRead = 0; - const file = fs.ReadStream(fn); + const file = fs.createReadStream(fn); const fileSize = fs.statSync(fn).size; assert.strictEqual(file.bytesRead, 0); diff --git a/test/parallel/test-fs-truncate-GH-6233.js b/test/parallel/test-fs-truncate-clear-file-zero.js similarity index 81% rename from test/parallel/test-fs-truncate-GH-6233.js rename to test/parallel/test-fs-truncate-clear-file-zero.js index 87663c63616ffa..4f3dce90995d06 100644 --- a/test/parallel/test-fs-truncate-GH-6233.js +++ b/test/parallel/test-fs-truncate-clear-file-zero.js @@ -21,11 +21,15 @@ 'use strict'; const common = require('../common'); +const tmpdir = require('../common/tmpdir'); + +// This test ensures that `fs.truncate` opens the file with `r+` and not `w`, +// which had earlier resulted in the target file's content getting zeroed out. +// https://github.com/nodejs/node-v0.x-archive/issues/6233 + const assert = require('assert'); const fs = require('fs'); -const tmpdir = require('../common/tmpdir'); - const filename = `${tmpdir.path}/truncate-file.txt`; tmpdir.refresh(); @@ -42,8 +46,12 @@ tmpdir.refresh(); { fs.writeFileSync(filename, '0123456789'); assert.strictEqual(fs.readFileSync(filename).toString(), '0123456789'); - fs.truncate(filename, 5, common.mustCall(function(err) { - assert.ifError(err); - assert.strictEqual(fs.readFileSync(filename).toString(), '01234'); - })); + fs.truncate( + filename, + 5, + common.mustCall(function(err) { + assert.ifError(err); + assert.strictEqual(fs.readFileSync(filename).toString(), '01234'); + }) + ); } diff --git a/test/parallel/test-http-agent-error-on-idle.js b/test/parallel/test-http-agent-error-on-idle.js index fce5e8f0324f5c..7cf494816ae266 100644 --- a/test/parallel/test-http-agent-error-on-idle.js +++ b/test/parallel/test-http-agent-error-on-idle.js @@ -27,8 +27,8 @@ server.listen(0, () => { res.on('end', common.mustCall(() => { process.nextTick(common.mustCall(() => { const freeSockets = agent.freeSockets[socketKey]; - assert.strictEqual(freeSockets.length, 1, - `expect a free socket on ${socketKey}`); + //expect a free socket on socketKey + assert.strictEqual(freeSockets.length, 1); //generate a random error on the free socket const freeSocket = freeSockets[0]; @@ -40,8 +40,8 @@ server.listen(0, () => { })); function done() { - assert.strictEqual(Object.keys(agent.freeSockets).length, 0, - 'expect the freeSockets pool to be empty'); + //expect the freeSockets pool to be empty + assert.strictEqual(Object.keys(agent.freeSockets).length, 0); agent.destroy(); server.close(); diff --git a/test/parallel/test-http-client-timeout-agent.js b/test/parallel/test-http-client-timeout-agent.js index c0359666bad35a..1b628ea96798b1 100644 --- a/test/parallel/test-http-client-timeout-agent.js +++ b/test/parallel/test-http-client-timeout-agent.js @@ -91,6 +91,6 @@ server.listen(0, options.host, function() { process.on('exit', function() { console.error(`done=${requests_done} sent=${requests_sent}`); - assert.strictEqual(requests_done, requests_sent, - 'timeout on http request called too much'); + // check that timeout on http request was not called too much + assert.strictEqual(requests_done, requests_sent); }); diff --git a/test/parallel/test-http-destroyed-socket-write2.js b/test/parallel/test-http-destroyed-socket-write2.js index 99a0c4663a8ba3..48899415e37a4f 100644 --- a/test/parallel/test-http-destroyed-socket-write2.js +++ b/test/parallel/test-http-destroyed-socket-write2.js @@ -62,12 +62,13 @@ server.listen(0, function() { break; default: + // Write to a torn down client should RESET or ABORT assert.strictEqual(er.code, - 'ECONNRESET', - 'Write to a torn down client should RESET or ABORT'); + 'ECONNRESET'); break; } + assert.strictEqual(req.output.length, 0); assert.strictEqual(req.outputEncodings.length, 0); server.close(); diff --git a/test/parallel/test-http-expect-continue.js b/test/parallel/test-http-expect-continue.js index 7f97ce35927e99..7d910f0778e88a 100644 --- a/test/parallel/test-http-expect-continue.js +++ b/test/parallel/test-http-expect-continue.js @@ -20,70 +20,63 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); const http = require('http'); -let outstanding_reqs = 0; const test_req_body = 'some stuff...\n'; const test_res_body = 'other stuff!\n'; let sent_continue = false; let got_continue = false; -function handler(req, res) { - assert.strictEqual(sent_continue, true, - 'Full response sent before 100 Continue'); +const handler = common.mustCall((req, res) => { + assert.ok(sent_continue, 'Full response sent before 100 Continue'); console.error('Server sending full response...'); res.writeHead(200, { 'Content-Type': 'text/plain', 'ABCD': '1' }); res.end(test_res_body); -} +}); -const server = http.createServer(handler); -server.on('checkContinue', function(req, res) { +const server = http.createServer(); +server.on('checkContinue', common.mustCall((req, res) => { console.error('Server got Expect: 100-continue...'); res.writeContinue(); sent_continue = true; setTimeout(function() { handler(req, res); }, 100); -}); +})); server.listen(0); -server.on('listening', function() { +server.on('listening', common.mustCall(() => { const req = http.request({ - port: this.address().port, + port: server.address().port, method: 'POST', path: '/world', headers: { 'Expect': '100-continue' } }); console.error('Client sending request...'); - outstanding_reqs++; let body = ''; - req.on('continue', function() { + req.on('continue', common.mustCall(() => { console.error('Client got 100 Continue...'); got_continue = true; req.end(test_req_body); - }); - req.on('response', function(res) { - assert.strictEqual(got_continue, true, - 'Full response received before 100 Continue'); + })); + req.on('response', common.mustCall((res) => { + assert.ok(got_continue, 'Full response received before 100 Continue'); assert.strictEqual(200, res.statusCode, `Final status code was ${res.statusCode}, not 200.`); res.setEncoding('utf8'); res.on('data', function(chunk) { body += chunk; }); - res.on('end', function() { + res.on('end', common.mustCall(() => { console.error('Got full response.'); - assert.strictEqual(body, test_res_body, 'Response body doesn\'t match.'); + assert.strictEqual(body, test_res_body); assert.ok('abcd' in res.headers, 'Response headers missing.'); - outstanding_reqs--; - if (outstanding_reqs === 0) { - server.close(); - process.exit(); - } - }); - }); -}); + server.close(); + process.exit(); + })); + })); +})); diff --git a/test/parallel/test-http-parser-bad-ref.js b/test/parallel/test-http-parser-bad-ref.js index 6e9fb2f9ac6033..c9827b16c77d57 100644 --- a/test/parallel/test-http-parser-bad-ref.js +++ b/test/parallel/test-http-parser-bad-ref.js @@ -81,7 +81,7 @@ demoBug('POST /1/22 HTTP/1.1\r\n' + 'pong'); process.on('exit', function() { - assert.strictEqual(2, headersComplete); - assert.strictEqual(2, messagesComplete); + assert.strictEqual(headersComplete, 2); + assert.strictEqual(messagesComplete, 2); console.log('done!'); }); diff --git a/test/parallel/test-http-remove-header-stays-removed.js b/test/parallel/test-http-remove-header-stays-removed.js index 6617a1775441b7..337fcd3becd177 100644 --- a/test/parallel/test-http-remove-header-stays-removed.js +++ b/test/parallel/test-http-remove-header-stays-removed.js @@ -44,13 +44,13 @@ const server = http.createServer(function(request, response) { let response = ''; process.on('exit', function() { - assert.strictEqual('beep boop\n', response); + assert.strictEqual(response, 'beep boop\n'); console.log('ok'); }); server.listen(0, function() { http.get({ port: this.address().port }, function(res) { - assert.strictEqual(200, res.statusCode); + assert.strictEqual(res.statusCode, 200); assert.deepStrictEqual(res.headers, { date: 'coffee o clock' }); res.setEncoding('ascii'); diff --git a/test/parallel/test-http-res-write-after-end.js b/test/parallel/test-http-res-write-after-end.js index 32c6cf2e082668..523a037bcb2b9f 100644 --- a/test/parallel/test-http-res-write-after-end.js +++ b/test/parallel/test-http-res-write-after-end.js @@ -33,7 +33,8 @@ const server = http.Server(common.mustCall(function(req, res) { res.end(); const r = res.write('This should raise an error.'); - assert.strictEqual(r, true, 'write after end should return true'); + // write after end should return true + assert.strictEqual(r, true); })); server.listen(0, function() { diff --git a/test/parallel/test-http-upgrade-server.js b/test/parallel/test-http-upgrade-server.js index 71a075831603da..1eea329f42dfeb 100644 --- a/test/parallel/test-http-upgrade-server.js +++ b/test/parallel/test-http-upgrade-server.js @@ -98,20 +98,20 @@ function test_upgrade_with_listener() { conn.on('data', function(data) { state++; - assert.strictEqual('string', typeof data); + assert.strictEqual(typeof data, 'string'); if (state === 1) { - assert.strictEqual('HTTP/1.1 101', data.substr(0, 12)); - assert.strictEqual('WjN}|M(6', request_upgradeHead.toString('utf8')); + assert.strictEqual(data.substr(0, 12), 'HTTP/1.1 101'); + assert.strictEqual(request_upgradeHead.toString('utf8'), 'WjN}|M(6'); conn.write('test', 'utf8'); } else if (state === 2) { - assert.strictEqual('test', data); + assert.strictEqual(data, 'test'); conn.write('kill', 'utf8'); } }); conn.on('end', function() { - assert.strictEqual(2, state); + assert.strictEqual(state, 2); conn.end(); server.removeAllListeners('upgrade'); test_upgrade_no_listener(); @@ -157,8 +157,8 @@ function test_standard_http() { }); conn.once('data', function(data) { - assert.strictEqual('string', typeof data); - assert.strictEqual('HTTP/1.1 200', data.substr(0, 12)); + assert.strictEqual(typeof data, 'string'); + assert.strictEqual(data.substr(0, 12), 'HTTP/1.1 200'); conn.end(); }); @@ -180,7 +180,7 @@ server.listen(0, function() { Fin. -----------------------------------------------*/ process.on('exit', function() { - assert.strictEqual(3, requests_recv); - assert.strictEqual(3, requests_sent); + assert.strictEqual(requests_recv, 3); + assert.strictEqual(requests_sent, 3); assert.ok(test_upgrade_no_listener_ended); }); diff --git a/test/parallel/test-http-write-empty-string.js b/test/parallel/test-http-write-empty-string.js index 35a7aca61b4030..d4ab070667ef6d 100644 --- a/test/parallel/test-http-write-empty-string.js +++ b/test/parallel/test-http-write-empty-string.js @@ -42,13 +42,13 @@ server.listen(0, common.mustCall(function() { http.get({ port: this.address().port }, common.mustCall(function(res) { let response = ''; - assert.strictEqual(200, res.statusCode); + assert.strictEqual(res.statusCode, 200); res.setEncoding('ascii'); res.on('data', function(chunk) { response += chunk; }); res.on('end', common.mustCall(function() { - assert.strictEqual('1\n2\n3\n', response); + assert.strictEqual(response, '1\n2\n3\n'); })); })); })); diff --git a/test/parallel/test-http2-error-order.js b/test/parallel/test-http2-error-order.js new file mode 100644 index 00000000000000..8bf0f03dba8ea3 --- /dev/null +++ b/test/parallel/test-http2-error-order.js @@ -0,0 +1,43 @@ +'use strict'; + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); + +const assert = require('assert'); +const { createServer, connect } = require('http2'); + +const messages = []; +const expected = [ + 'Stream:created', + 'Stream:error', + 'Stream:close', + 'Request:error' +]; + +const server = createServer(); + +server.on('stream', (stream) => { + messages.push('Stream:created'); + stream + .on('close', () => messages.push('Stream:close')) + .on('error', (err) => messages.push('Stream:error')) + .respondWithFile('dont exist'); +}); + +server.listen(0); + +const client = connect(`http://localhost:${server.address().port}`); +const req = client.request(); + +req.on('response', common.mustNotCall()); + +req.on('error', () => { + messages.push('Request:error'); + client.close(); +}); + +client.on('close', common.mustCall(() => { + assert.deepStrictEqual(messages, expected); + server.close(); +})); diff --git a/test/parallel/test-http2-stream-destroy-event-order.js b/test/parallel/test-http2-stream-destroy-event-order.js index 7d4bcb102f0d0a..88e4a99f99eee3 100644 --- a/test/parallel/test-http2-stream-destroy-event-order.js +++ b/test/parallel/test-http2-stream-destroy-event-order.js @@ -1,4 +1,3 @@ -// Flags: --expose-http2 'use strict'; const common = require('../common'); @@ -10,8 +9,8 @@ let client; let req; const server = http2.createServer(); server.on('stream', common.mustCall((stream) => { - stream.on('close', common.mustCall(() => { - stream.on('error', common.mustCall(() => { + stream.on('error', common.mustCall(() => { + stream.on('close', common.mustCall(() => { server.close(); })); })); @@ -22,8 +21,8 @@ server.listen(0, common.mustCall(() => { client = http2.connect(`http://localhost:${server.address().port}`); req = client.request(); req.resume(); - req.on('close', common.mustCall(() => { - req.on('error', common.mustCall(() => { + req.on('error', common.mustCall(() => { + req.on('close', common.mustCall(() => { client.close(); })); })); diff --git a/test/parallel/test-http2-write-empty-string.js b/test/parallel/test-http2-write-empty-string.js index 6e6ce5254ddcfc..ea591176a47251 100644 --- a/test/parallel/test-http2-write-empty-string.js +++ b/test/parallel/test-http2-write-empty-string.js @@ -25,7 +25,7 @@ server.listen(0, common.mustCall(function() { let res = ''; req.on('response', common.mustCall(function(headers) { - assert.strictEqual(200, headers[':status']); + assert.strictEqual(headers[':status'], 200); })); req.on('data', (chunk) => { @@ -33,7 +33,7 @@ server.listen(0, common.mustCall(function() { }); req.on('end', common.mustCall(function() { - assert.strictEqual('1\n2\n3\n', res); + assert.strictEqual(res, '1\n2\n3\n'); client.close(); })); diff --git a/test/parallel/test-https-connect-address-family.js b/test/parallel/test-https-connect-address-family.js index 8b3584b3396551..65cd59313f109b 100644 --- a/test/parallel/test-https-connect-address-family.js +++ b/test/parallel/test-https-connect-address-family.js @@ -37,7 +37,7 @@ const https = require('https'); }; // Will fail with ECONNREFUSED if the address family is not honored. https.get(options, common.mustCall(function() { - assert.strictEqual('::1', this.socket.remoteAddress); + assert.strictEqual(this.socket.remoteAddress, hostAddrIPv6); this.destroy(); })); })); diff --git a/test/parallel/test-intl.js b/test/parallel/test-intl.js index 983685c32cff04..63227792d222ad 100644 --- a/test/parallel/test-intl.js +++ b/test/parallel/test-intl.js @@ -101,8 +101,18 @@ if (!common.hasIntl) { assert.strictEqual(localeString, '1/1/1970, 12:00:00 AM'); } // number format - const numberFormat = new Intl.NumberFormat(['en']).format(12345.67890); - assert.strictEqual(numberFormat, '12,345.679'); + { + const numberFormat = new Intl.NumberFormat(['en']).format(12345.67890); + assert.strictEqual(numberFormat, '12,345.679'); + } + // Significant Digits + { + const loc = ['en-US']; + const opts = { maximumSignificantDigits: 4 }; + const num = 10.001; + const numberFormat = new Intl.NumberFormat(loc, opts).format(num); + assert.strictEqual(numberFormat, '10'); + } const collOpts = { sensitivity: 'base', ignorePunctuation: true }; const coll = new Intl.Collator(['en'], collOpts); diff --git a/test/parallel/test-regress-GH-node-9326.js b/test/parallel/test-kill-segfault-freebsd.js similarity index 61% rename from test/parallel/test-regress-GH-node-9326.js rename to test/parallel/test-kill-segfault-freebsd.js index 78565e3f596594..8532f11c86b804 100644 --- a/test/parallel/test-regress-GH-node-9326.js +++ b/test/parallel/test-kill-segfault-freebsd.js @@ -1,5 +1,10 @@ 'use strict'; require('../common'); + +// This test ensures Node.js doesn't crash on hitting Ctrl+C in order to +// terminate the currently running process (especially on FreeBSD). +// https://github.com/nodejs/node-v0.x-archive/issues/9326 + const assert = require('assert'); const child_process = require('child_process'); diff --git a/test/parallel/test-net-dns-error.js b/test/parallel/test-net-dns-error.js index a5ae415592fed4..0d943bf6cd54a0 100644 --- a/test/parallel/test-net-dns-error.js +++ b/test/parallel/test-net-dns-error.js @@ -21,27 +21,20 @@ 'use strict'; const common = require('../common'); -const assert = require('assert'); +const assert = require('assert'); const net = require('net'); const host = '*'.repeat(256); +const errCode = common.isOpenBSD ? 'EAI_FAIL' : 'ENOTFOUND'; -let errCode = 'ENOTFOUND'; -if (common.isOpenBSD) - errCode = 'EAI_FAIL'; - -function do_not_call() { - throw new Error('This function should not have been called.'); -} - -const socket = net.connect(42, host, do_not_call); +const socket = net.connect(42, host, common.mustNotCall()); socket.on('error', common.mustCall(function(err) { assert.strictEqual(err.code, errCode); })); -socket.on('lookup', function(err, ip, type) { +socket.on('lookup', common.mustCall(function(err, ip, type) { assert(err instanceof Error); assert.strictEqual(err.code, errCode); assert.strictEqual(ip, undefined); assert.strictEqual(type, undefined); -}); +})); diff --git a/test/parallel/test-net-server-pause-on-connect.js b/test/parallel/test-net-server-pause-on-connect.js index 84cc91d56c3b08..59c39e8816cc5c 100644 --- a/test/parallel/test-net-server-pause-on-connect.js +++ b/test/parallel/test-net-server-pause-on-connect.js @@ -34,7 +34,7 @@ const server1ConnHandler = (socket) => { assert.fail('data event should not have happened yet'); } - assert.strictEqual(data.toString(), msg, 'invalid data received'); + assert.strictEqual(data.toString(), msg); socket.end(); server1.close(); }); @@ -46,12 +46,11 @@ const server1 = net.createServer({ pauseOnConnect: true }, server1ConnHandler); const server2ConnHandler = (socket) => { socket.on('data', function(data) { - assert.strictEqual(data.toString(), msg, 'invalid data received'); + assert.strictEqual(data.toString(), msg); socket.end(); server2.close(); - assert.strictEqual(server1Sock.bytesRead, 0, - 'no data should have been read yet'); + assert.strictEqual(server1Sock.bytesRead, 0); server1Sock.resume(); stopped = false; }); diff --git a/test/parallel/test-process-exit-GH-12322.js b/test/parallel/test-process-exit-GH-12322.js deleted file mode 100644 index 890dfd4df7bff4..00000000000000 --- a/test/parallel/test-process-exit-GH-12322.js +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; -require('../common'); - -process.on('exit', () => { - setTimeout(process.abort, 0); // Should not run. - for (const start = Date.now(); Date.now() - start < 10; /* Empty. */); -}); diff --git a/test/parallel/test-process-exit-handler.js b/test/parallel/test-process-exit-handler.js new file mode 100644 index 00000000000000..22d84f34349b73 --- /dev/null +++ b/test/parallel/test-process-exit-handler.js @@ -0,0 +1,11 @@ +'use strict'; +require('../common'); + +// This test ensures that no asynchronous operations are performed in the 'exit' +// handler. +// https://github.com/nodejs/node/issues/12322 + +process.on('exit', () => { + setTimeout(process.abort, 0); // Should not run. + for (const start = Date.now(); Date.now() - start < 10;); +}); diff --git a/test/parallel/test-process-setuid-setgid.js b/test/parallel/test-process-setuid-setgid.js index e0db8ee00222dd..54341b8564f242 100644 --- a/test/parallel/test-process-setuid-setgid.js +++ b/test/parallel/test-process-setuid-setgid.js @@ -33,6 +33,10 @@ if (common.isWindows) { return; } +assert.throws(() => { + process.setuid({}); +}, /^TypeError: setuid argument must be a number or a string$/); + assert.throws(() => { process.setuid('fhqwhgadshgnsdhjsdbkhsdabkfabkveybvf'); }, /^Error: setuid user id does not exist$/); diff --git a/test/parallel/test-process-versions.js b/test/parallel/test-process-versions.js index 29325d531cff27..48c0e1611e3f63 100644 --- a/test/parallel/test-process-versions.js +++ b/test/parallel/test-process-versions.js @@ -33,6 +33,10 @@ assert(/^\d+\.\d+\.\d+(?:\.\d+)?(?: \(candidate\))?$/ .test(process.versions.v8)); assert(/^\d+$/.test(process.versions.modules)); +if (common.hasCrypto) { + assert(/^\d+\.\d+\.\d+[a-z]?(-fips)?$/.test(process.versions.openssl)); +} + for (let i = 0; i < expected_keys.length; i++) { const key = expected_keys[i]; const descriptor = Object.getOwnPropertyDescriptor(process.versions, key); diff --git a/test/parallel/test-regress-GH-io-1068.js b/test/parallel/test-regress-GH-io-1068.js deleted file mode 100644 index a92bb3e75259f0..00000000000000 --- a/test/parallel/test-regress-GH-io-1068.js +++ /dev/null @@ -1,3 +0,0 @@ -'use strict'; -require('../common'); -process.stdin.emit('end'); diff --git a/test/parallel/test-require-symlink.js b/test/parallel/test-require-symlink.js index d245c21dd1fdb4..fa604aaf56bd76 100644 --- a/test/parallel/test-require-symlink.js +++ b/test/parallel/test-require-symlink.js @@ -58,7 +58,7 @@ const linkScriptTarget = path.join(dirName, 'symlinked.js'); test(); function test() { - fs.symlinkSync(linkTarget, linkDir); + fs.symlinkSync(linkTarget, linkDir, 'dir'); fs.symlinkSync(linkScriptTarget, linkScript); // load symlinked-module diff --git a/test/parallel/test-timers-regress-GH-9765.js b/test/parallel/test-timers-setimmediate-infinite-loop.js similarity index 100% rename from test/parallel/test-timers-regress-GH-9765.js rename to test/parallel/test-timers-setimmediate-infinite-loop.js diff --git a/test/parallel/test-tls-ca-concat.js b/test/parallel/test-tls-ca-concat.js index 3b4f3e7db74115..efec4e649c9506 100644 --- a/test/parallel/test-tls-ca-concat.js +++ b/test/parallel/test-tls-ca-concat.js @@ -1,5 +1,5 @@ 'use strict'; -require('../common'); +const common = require('../common'); const fixtures = require('../common/fixtures'); // Check ca option can contain concatenated certs by prepending an unrelated @@ -18,7 +18,7 @@ connect({ cert: keys.agent6.cert, key: keys.agent6.key, }, -}, function(err, pair, cleanup) { +}, common.mustCall((err, pair, cleanup) => { assert.ifError(err); return cleanup(); -}); +})); diff --git a/test/parallel/test-tls-pfx-authorizationerror.js b/test/parallel/test-tls-pfx-authorizationerror.js new file mode 100644 index 00000000000000..64b6e1485dc538 --- /dev/null +++ b/test/parallel/test-tls-pfx-authorizationerror.js @@ -0,0 +1,42 @@ +'use strict'; +const common = require('../common'); +if (!common.hasCrypto) + common.skip('node compiled without crypto.'); +const fixtures = require('../common/fixtures'); + +// This test ensures that TLS does not fail to read a self-signed certificate +// and thus throw an `authorizationError`. +// https://github.com/nodejs/node/issues/5100 + +const assert = require('assert'); +const tls = require('tls'); + +const pfx = fixtures.readKey('agent1-pfx.pem'); + +const server = tls + .createServer( + { + pfx: pfx, + passphrase: 'sample', + requestCert: true, + rejectUnauthorized: false + }, + common.mustCall(function(c) { + assert.strictEqual(c.authorizationError, null); + c.end(); + }) + ) + .listen(0, function() { + const client = tls.connect( + { + port: this.address().port, + pfx: pfx, + passphrase: 'sample', + rejectUnauthorized: false + }, + function() { + client.end(); + server.close(); + } + ); + }); diff --git a/test/parallel/test-tls-pfx-gh-5100-regr.js b/test/parallel/test-tls-pfx-gh-5100-regr.js deleted file mode 100644 index 199d4bdf22778c..00000000000000 --- a/test/parallel/test-tls-pfx-gh-5100-regr.js +++ /dev/null @@ -1,32 +0,0 @@ -'use strict'; - -const common = require('../common'); - -if (!common.hasCrypto) - common.skip('node compiled without crypto.'); - -const assert = require('assert'); -const tls = require('tls'); -const fixtures = require('../common/fixtures'); - -const pfx = fixtures.readKey('agent1-pfx.pem'); - -const server = tls.createServer({ - pfx: pfx, - passphrase: 'sample', - requestCert: true, - rejectUnauthorized: false -}, common.mustCall(function(c) { - assert.strictEqual(c.authorizationError, null); - c.end(); -})).listen(0, function() { - const client = tls.connect({ - port: this.address().port, - pfx: pfx, - passphrase: 'sample', - rejectUnauthorized: false - }, function() { - client.end(); - server.close(); - }); -}); diff --git a/test/parallel/test-tls-regr-gh-5108.js b/test/parallel/test-tls-tlswrap-segfault.js similarity index 81% rename from test/parallel/test-tls-regr-gh-5108.js rename to test/parallel/test-tls-tlswrap-segfault.js index 402a6014d1396c..eaa51ff51baa71 100644 --- a/test/parallel/test-tls-regr-gh-5108.js +++ b/test/parallel/test-tls-tlswrap-segfault.js @@ -1,19 +1,21 @@ 'use strict'; const common = require('../common'); - if (!common.hasCrypto) common.skip('missing crypto'); +const fixtures = require('../common/fixtures'); + +// This test ensures that Node.js doesn't incur a segfault while accessing +// TLSWrap fields after the parent handle was destroyed. +// https://github.com/nodejs/node/issues/5108 const assert = require('assert'); const tls = require('tls'); -const fixtures = require('../common/fixtures'); const options = { key: fixtures.readKey('agent1-key.pem'), cert: fixtures.readKey('agent1-cert.pem') }; - const server = tls.createServer(options, function(s) { s.end('hello'); }).listen(0, function() { @@ -26,7 +28,6 @@ const server = tls.createServer(options, function(s) { }); }); - function putImmediate(client) { setImmediate(function() { if (client.ssl) { diff --git a/test/parallel/test-tty-stdin-end.js b/test/parallel/test-tty-stdin-end.js new file mode 100644 index 00000000000000..c78f58446d03e9 --- /dev/null +++ b/test/parallel/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/parallel/test-regress-GH-io-1811.js b/test/parallel/test-zlib-kmaxlength-rangeerror.js similarity index 76% rename from test/parallel/test-regress-GH-io-1811.js rename to test/parallel/test-zlib-kmaxlength-rangeerror.js index a8966da10ba1f7..e8e47865f79604 100644 --- a/test/parallel/test-regress-GH-io-1811.js +++ b/test/parallel/test-zlib-kmaxlength-rangeerror.js @@ -1,6 +1,10 @@ 'use strict'; - require('../common'); + +// This test ensures that zlib throws a RangeError if the final buffer needs to +// be larger than kMaxLength and concatenation fails. +// https://github.com/nodejs/node/pull/1811 + const assert = require('assert'); // Change kMaxLength for zlib to trigger the error without having to allocate diff --git a/tools/doc/html.js b/tools/doc/html.js index 439fc057012ca7..f373206760b5df 100644 --- a/tools/doc/html.js +++ b/tools/doc/html.js @@ -168,6 +168,8 @@ function altDocs(filename) { } const versions = [ + { num: '11.x' }, + { num: '10.x', lts: true }, { num: '9.x' }, { num: '8.x', lts: true }, { num: '7.x' }, diff --git a/tools/icu/patches/62/source/i18n/decimfmt.cpp b/tools/icu/patches/62/source/i18n/decimfmt.cpp new file mode 100644 index 00000000000000..8ae773b75c2aa2 --- /dev/null +++ b/tools/icu/patches/62/source/i18n/decimfmt.cpp @@ -0,0 +1,1384 @@ +// © 2018 and later: Unicode, Inc. and others. +// License & terms of use: http://www.unicode.org/copyright.html + +#include "unicode/utypes.h" + +#if !UCONFIG_NO_FORMATTING + +// Allow implicit conversion from char16_t* to UnicodeString for this file: +// Helpful in toString methods and elsewhere. +#define UNISTR_FROM_STRING_EXPLICIT + +#include +#include +#include +#include "unicode/errorcode.h" +#include "unicode/decimfmt.h" +#include "number_decimalquantity.h" +#include "number_types.h" +#include "numparse_impl.h" +#include "number_mapper.h" +#include "number_patternstring.h" +#include "putilimp.h" +#include "number_utils.h" +#include "number_utypes.h" + +using namespace icu; +using namespace icu::number; +using namespace icu::number::impl; +using namespace icu::numparse; +using namespace icu::numparse::impl; +using ERoundingMode = icu::DecimalFormat::ERoundingMode; +using EPadPosition = icu::DecimalFormat::EPadPosition; + +// MSVC warns C4805 when comparing bool with UBool +// TODO: Move this macro into a better place? +#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN +#define UBOOL_TO_BOOL(b) static_cast(b) +#else +#define UBOOL_TO_BOOL(b) b +#endif + + +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DecimalFormat) + + +DecimalFormat::DecimalFormat(UErrorCode& status) + : DecimalFormat(nullptr, status) { + // Use the default locale and decimal pattern. + const char* localeName = Locale::getDefault().getName(); + LocalPointer ns(NumberingSystem::createInstance(status)); + UnicodeString patternString = utils::getPatternForStyle( + localeName, + ns->getName(), + CLDR_PATTERN_STYLE_DECIMAL, + status); + setPropertiesFromPattern(patternString, IGNORE_ROUNDING_IF_CURRENCY, status); + touch(status); +} + +DecimalFormat::DecimalFormat(const UnicodeString& pattern, UErrorCode& status) + : DecimalFormat(nullptr, status) { + setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status); + touch(status); +} + +DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt, + UErrorCode& status) + : DecimalFormat(symbolsToAdopt, status) { + setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status); + touch(status); +} + +DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt, + UNumberFormatStyle style, UErrorCode& status) + : DecimalFormat(symbolsToAdopt, status) { + // If choice is a currency type, ignore the rounding information. + if (style == UNumberFormatStyle::UNUM_CURRENCY || style == UNumberFormatStyle::UNUM_CURRENCY_ISO || + style == UNumberFormatStyle::UNUM_CURRENCY_ACCOUNTING || + style == UNumberFormatStyle::UNUM_CASH_CURRENCY || + style == UNumberFormatStyle::UNUM_CURRENCY_STANDARD || + style == UNumberFormatStyle::UNUM_CURRENCY_PLURAL) { + setPropertiesFromPattern(pattern, IGNORE_ROUNDING_ALWAYS, status); + } else { + setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status); + } + // Note: in Java, CurrencyPluralInfo is set in NumberFormat.java, but in C++, it is not set there, + // so we have to set it here. + if (style == UNumberFormatStyle::UNUM_CURRENCY_PLURAL) { + LocalPointer cpi( + new CurrencyPluralInfo(fields->symbols->getLocale(), status), + status); + if (U_FAILURE(status)) { return; } + fields->properties->currencyPluralInfo.fPtr.adoptInstead(cpi.orphan()); + } + touch(status); +} + +DecimalFormat::DecimalFormat(const DecimalFormatSymbols* symbolsToAdopt, UErrorCode& status) { + LocalPointer adoptedSymbols(symbolsToAdopt); + fields = new DecimalFormatFields(); + if (U_FAILURE(status)) { + return; + } + if (fields == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + return; + } + fields->properties.adoptInsteadAndCheckErrorCode(new DecimalFormatProperties(), status); + fields->exportedProperties.adoptInsteadAndCheckErrorCode(new DecimalFormatProperties(), status); + if (adoptedSymbols.isNull()) { + fields->symbols.adoptInsteadAndCheckErrorCode(new DecimalFormatSymbols(status), status); + } else { + fields->symbols.adoptInsteadAndCheckErrorCode(adoptedSymbols.orphan(), status); + } +} + +#if UCONFIG_HAVE_PARSEALLINPUT + +void DecimalFormat::setParseAllInput(UNumberFormatAttributeValue value) { + if (value == fields->properties->parseAllInput) { return; } + fields->properties->parseAllInput = value; +} + +#endif + +DecimalFormat& +DecimalFormat::setAttribute(UNumberFormatAttribute attr, int32_t newValue, UErrorCode& status) { + if (U_FAILURE(status)) { return *this; } + + switch (attr) { + case UNUM_LENIENT_PARSE: + setLenient(newValue != 0); + break; + + case UNUM_PARSE_INT_ONLY: + setParseIntegerOnly(newValue != 0); + break; + + case UNUM_GROUPING_USED: + setGroupingUsed(newValue != 0); + break; + + case UNUM_DECIMAL_ALWAYS_SHOWN: + setDecimalSeparatorAlwaysShown(newValue != 0); + break; + + case UNUM_MAX_INTEGER_DIGITS: + setMaximumIntegerDigits(newValue); + break; + + case UNUM_MIN_INTEGER_DIGITS: + setMinimumIntegerDigits(newValue); + break; + + case UNUM_INTEGER_DIGITS: + setMinimumIntegerDigits(newValue); + setMaximumIntegerDigits(newValue); + break; + + case UNUM_MAX_FRACTION_DIGITS: + setMaximumFractionDigits(newValue); + break; + + case UNUM_MIN_FRACTION_DIGITS: + setMinimumFractionDigits(newValue); + break; + + case UNUM_FRACTION_DIGITS: + setMinimumFractionDigits(newValue); + setMaximumFractionDigits(newValue); + break; + + case UNUM_SIGNIFICANT_DIGITS_USED: + setSignificantDigitsUsed(newValue != 0); + break; + + case UNUM_MAX_SIGNIFICANT_DIGITS: + setMaximumSignificantDigits(newValue); + break; + + case UNUM_MIN_SIGNIFICANT_DIGITS: + setMinimumSignificantDigits(newValue); + break; + + case UNUM_MULTIPLIER: + setMultiplier(newValue); + break; + + case UNUM_SCALE: + setMultiplierScale(newValue); + break; + + case UNUM_GROUPING_SIZE: + setGroupingSize(newValue); + break; + + case UNUM_ROUNDING_MODE: + setRoundingMode((DecimalFormat::ERoundingMode) newValue); + break; + + case UNUM_FORMAT_WIDTH: + setFormatWidth(newValue); + break; + + case UNUM_PADDING_POSITION: + /** The position at which padding will take place. */ + setPadPosition((DecimalFormat::EPadPosition) newValue); + break; + + case UNUM_SECONDARY_GROUPING_SIZE: + setSecondaryGroupingSize(newValue); + break; + +#if UCONFIG_HAVE_PARSEALLINPUT + case UNUM_PARSE_ALL_INPUT: + setParseAllInput((UNumberFormatAttributeValue) newValue); + break; +#endif + + case UNUM_PARSE_NO_EXPONENT: + setParseNoExponent((UBool) newValue); + break; + + case UNUM_PARSE_DECIMAL_MARK_REQUIRED: + setDecimalPatternMatchRequired((UBool) newValue); + break; + + case UNUM_CURRENCY_USAGE: + setCurrencyUsage((UCurrencyUsage) newValue, &status); + break; + + case UNUM_MINIMUM_GROUPING_DIGITS: + setMinimumGroupingDigits(newValue); + break; + + case UNUM_PARSE_CASE_SENSITIVE: + setParseCaseSensitive(static_cast(newValue)); + break; + + case UNUM_SIGN_ALWAYS_SHOWN: + setSignAlwaysShown(static_cast(newValue)); + break; + + case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS: + setFormatFailIfMoreThanMaxDigits(static_cast(newValue)); + break; + + default: + status = U_UNSUPPORTED_ERROR; + break; + } + return *this; +} + +int32_t DecimalFormat::getAttribute(UNumberFormatAttribute attr, UErrorCode& status) const { + if (U_FAILURE(status)) { return -1; } + switch (attr) { + case UNUM_LENIENT_PARSE: + return isLenient(); + + case UNUM_PARSE_INT_ONLY: + return isParseIntegerOnly(); + + case UNUM_GROUPING_USED: + return isGroupingUsed(); + + case UNUM_DECIMAL_ALWAYS_SHOWN: + return isDecimalSeparatorAlwaysShown(); + + case UNUM_MAX_INTEGER_DIGITS: + return getMaximumIntegerDigits(); + + case UNUM_MIN_INTEGER_DIGITS: + return getMinimumIntegerDigits(); + + case UNUM_INTEGER_DIGITS: + // TBD: what should this return? + return getMinimumIntegerDigits(); + + case UNUM_MAX_FRACTION_DIGITS: + return getMaximumFractionDigits(); + + case UNUM_MIN_FRACTION_DIGITS: + return getMinimumFractionDigits(); + + case UNUM_FRACTION_DIGITS: + // TBD: what should this return? + return getMinimumFractionDigits(); + + case UNUM_SIGNIFICANT_DIGITS_USED: + return areSignificantDigitsUsed(); + + case UNUM_MAX_SIGNIFICANT_DIGITS: + return getMaximumSignificantDigits(); + + case UNUM_MIN_SIGNIFICANT_DIGITS: + return getMinimumSignificantDigits(); + + case UNUM_MULTIPLIER: + return getMultiplier(); + + case UNUM_SCALE: + return getMultiplierScale(); + + case UNUM_GROUPING_SIZE: + return getGroupingSize(); + + case UNUM_ROUNDING_MODE: + return getRoundingMode(); + + case UNUM_FORMAT_WIDTH: + return getFormatWidth(); + + case UNUM_PADDING_POSITION: + return getPadPosition(); + + case UNUM_SECONDARY_GROUPING_SIZE: + return getSecondaryGroupingSize(); + + case UNUM_PARSE_NO_EXPONENT: + return isParseNoExponent(); + + case UNUM_PARSE_DECIMAL_MARK_REQUIRED: + return isDecimalPatternMatchRequired(); + + case UNUM_CURRENCY_USAGE: + return getCurrencyUsage(); + + case UNUM_MINIMUM_GROUPING_DIGITS: + return getMinimumGroupingDigits(); + + case UNUM_PARSE_CASE_SENSITIVE: + return isParseCaseSensitive(); + + case UNUM_SIGN_ALWAYS_SHOWN: + return isSignAlwaysShown(); + + case UNUM_FORMAT_FAIL_IF_MORE_THAN_MAX_DIGITS: + return isFormatFailIfMoreThanMaxDigits(); + + default: + status = U_UNSUPPORTED_ERROR; + break; + } + + return -1; /* undefined */ +} + +void DecimalFormat::setGroupingUsed(UBool enabled) { + if (UBOOL_TO_BOOL(enabled) == fields->properties->groupingUsed) { return; } + NumberFormat::setGroupingUsed(enabled); // to set field for compatibility + fields->properties->groupingUsed = enabled; + touchNoError(); +} + +void DecimalFormat::setParseIntegerOnly(UBool value) { + if (UBOOL_TO_BOOL(value) == fields->properties->parseIntegerOnly) { return; } + NumberFormat::setParseIntegerOnly(value); // to set field for compatibility + fields->properties->parseIntegerOnly = value; + touchNoError(); +} + +void DecimalFormat::setLenient(UBool enable) { + ParseMode mode = enable ? PARSE_MODE_LENIENT : PARSE_MODE_STRICT; + if (!fields->properties->parseMode.isNull() && mode == fields->properties->parseMode.getNoError()) { return; } + NumberFormat::setLenient(enable); // to set field for compatibility + fields->properties->parseMode = mode; + touchNoError(); +} + +DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt, + UParseError&, UErrorCode& status) + : DecimalFormat(symbolsToAdopt, status) { + // TODO: What is parseError for? + setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status); + touch(status); +} + +DecimalFormat::DecimalFormat(const UnicodeString& pattern, const DecimalFormatSymbols& symbols, + UErrorCode& status) + : DecimalFormat(new DecimalFormatSymbols(symbols), status) { + setPropertiesFromPattern(pattern, IGNORE_ROUNDING_IF_CURRENCY, status); + touch(status); +} + +DecimalFormat::DecimalFormat(const DecimalFormat& source) : NumberFormat(source) { + // Note: it is not safe to copy fields->formatter or fWarehouse directly because fields->formatter might have + // dangling pointers to fields inside fWarehouse. The safe thing is to re-construct fields->formatter from + // the property bag, despite being somewhat slower. + fields = new DecimalFormatFields(); + if (fields == nullptr) { + return; + } + fields->properties.adoptInstead(new DecimalFormatProperties(*source.fields->properties)); + fields->symbols.adoptInstead(new DecimalFormatSymbols(*source.fields->symbols)); + fields->exportedProperties.adoptInstead(new DecimalFormatProperties()); + if (fields->properties == nullptr || fields->symbols == nullptr || fields->exportedProperties == nullptr) { + return; + } + touchNoError(); +} + +DecimalFormat& DecimalFormat::operator=(const DecimalFormat& rhs) { + *fields->properties = *rhs.fields->properties; + fields->exportedProperties->clear(); + fields->symbols.adoptInstead(new DecimalFormatSymbols(*rhs.fields->symbols)); + touchNoError(); + return *this; +} + +DecimalFormat::~DecimalFormat() { + delete fields->atomicParser.exchange(nullptr); + delete fields->atomicCurrencyParser.exchange(nullptr); + delete fields; +} + +Format* DecimalFormat::clone() const { + return new DecimalFormat(*this); +} + +UBool DecimalFormat::operator==(const Format& other) const { + auto* otherDF = dynamic_cast(&other); + if (otherDF == nullptr) { + return false; + } + return *fields->properties == *otherDF->fields->properties && *fields->symbols == *otherDF->fields->symbols; +} + +UnicodeString& DecimalFormat::format(double number, UnicodeString& appendTo, FieldPosition& pos) const { + if (pos.getField() == FieldPosition::DONT_CARE && fastFormatDouble(number, appendTo)) { + return appendTo; + } + UErrorCode localStatus = U_ZERO_ERROR; + FormattedNumber output = fields->formatter->formatDouble(number, localStatus); + fieldPositionHelper(output, pos, appendTo.length(), localStatus); + auto appendable = UnicodeStringAppendable(appendTo); + output.appendTo(appendable); + return appendTo; +} + +UnicodeString& DecimalFormat::format(double number, UnicodeString& appendTo, FieldPosition& pos, + UErrorCode& status) const { + if (pos.getField() == FieldPosition::DONT_CARE && fastFormatDouble(number, appendTo)) { + return appendTo; + } + FormattedNumber output = fields->formatter->formatDouble(number, status); + fieldPositionHelper(output, pos, appendTo.length(), status); + auto appendable = UnicodeStringAppendable(appendTo); + output.appendTo(appendable); + return appendTo; +} + +UnicodeString& +DecimalFormat::format(double number, UnicodeString& appendTo, FieldPositionIterator* posIter, + UErrorCode& status) const { + if (posIter == nullptr && fastFormatDouble(number, appendTo)) { + return appendTo; + } + FormattedNumber output = fields->formatter->formatDouble(number, status); + fieldPositionIteratorHelper(output, posIter, appendTo.length(), status); + auto appendable = UnicodeStringAppendable(appendTo); + output.appendTo(appendable); + return appendTo; +} + +UnicodeString& DecimalFormat::format(int32_t number, UnicodeString& appendTo, FieldPosition& pos) const { + return format(static_cast (number), appendTo, pos); +} + +UnicodeString& DecimalFormat::format(int32_t number, UnicodeString& appendTo, FieldPosition& pos, + UErrorCode& status) const { + return format(static_cast (number), appendTo, pos, status); +} + +UnicodeString& +DecimalFormat::format(int32_t number, UnicodeString& appendTo, FieldPositionIterator* posIter, + UErrorCode& status) const { + return format(static_cast (number), appendTo, posIter, status); +} + +UnicodeString& DecimalFormat::format(int64_t number, UnicodeString& appendTo, FieldPosition& pos) const { + if (pos.getField() == FieldPosition::DONT_CARE && fastFormatInt64(number, appendTo)) { + return appendTo; + } + UErrorCode localStatus = U_ZERO_ERROR; + FormattedNumber output = fields->formatter->formatInt(number, localStatus); + fieldPositionHelper(output, pos, appendTo.length(), localStatus); + auto appendable = UnicodeStringAppendable(appendTo); + output.appendTo(appendable); + return appendTo; +} + +UnicodeString& DecimalFormat::format(int64_t number, UnicodeString& appendTo, FieldPosition& pos, + UErrorCode& status) const { + if (pos.getField() == FieldPosition::DONT_CARE && fastFormatInt64(number, appendTo)) { + return appendTo; + } + FormattedNumber output = fields->formatter->formatInt(number, status); + fieldPositionHelper(output, pos, appendTo.length(), status); + auto appendable = UnicodeStringAppendable(appendTo); + output.appendTo(appendable); + return appendTo; +} + +UnicodeString& +DecimalFormat::format(int64_t number, UnicodeString& appendTo, FieldPositionIterator* posIter, + UErrorCode& status) const { + if (posIter == nullptr && fastFormatInt64(number, appendTo)) { + return appendTo; + } + FormattedNumber output = fields->formatter->formatInt(number, status); + fieldPositionIteratorHelper(output, posIter, appendTo.length(), status); + auto appendable = UnicodeStringAppendable(appendTo); + output.appendTo(appendable); + return appendTo; +} + +UnicodeString& +DecimalFormat::format(StringPiece number, UnicodeString& appendTo, FieldPositionIterator* posIter, + UErrorCode& status) const { + FormattedNumber output = fields->formatter->formatDecimal(number, status); + fieldPositionIteratorHelper(output, posIter, appendTo.length(), status); + auto appendable = UnicodeStringAppendable(appendTo); + output.appendTo(appendable); + return appendTo; +} + +UnicodeString& DecimalFormat::format(const DecimalQuantity& number, UnicodeString& appendTo, + FieldPositionIterator* posIter, UErrorCode& status) const { + FormattedNumber output = fields->formatter->formatDecimalQuantity(number, status); + fieldPositionIteratorHelper(output, posIter, appendTo.length(), status); + auto appendable = UnicodeStringAppendable(appendTo); + output.appendTo(appendable); + return appendTo; +} + +UnicodeString& +DecimalFormat::format(const DecimalQuantity& number, UnicodeString& appendTo, FieldPosition& pos, + UErrorCode& status) const { + FormattedNumber output = fields->formatter->formatDecimalQuantity(number, status); + fieldPositionHelper(output, pos, appendTo.length(), status); + auto appendable = UnicodeStringAppendable(appendTo); + output.appendTo(appendable); + return appendTo; +} + +void DecimalFormat::parse(const UnicodeString& text, Formattable& output, + ParsePosition& parsePosition) const { + if (parsePosition.getIndex() < 0 || parsePosition.getIndex() >= text.length()) { + return; + } + + ErrorCode status; + ParsedNumber result; + // Note: if this is a currency instance, currencies will be matched despite the fact that we are not in the + // parseCurrency method (backwards compatibility) + int32_t startIndex = parsePosition.getIndex(); + const NumberParserImpl* parser = getParser(status); + if (U_FAILURE(status)) { return; } + parser->parse(text, startIndex, true, result, status); + // TODO: Do we need to check for fImpl->properties->parseAllInput (UCONFIG_HAVE_PARSEALLINPUT) here? + if (result.success()) { + parsePosition.setIndex(result.charEnd); + result.populateFormattable(output, parser->getParseFlags()); + } else { + parsePosition.setErrorIndex(startIndex + result.charEnd); + } +} + +CurrencyAmount* DecimalFormat::parseCurrency(const UnicodeString& text, ParsePosition& parsePosition) const { + if (parsePosition.getIndex() < 0 || parsePosition.getIndex() >= text.length()) { + return nullptr; + } + + ErrorCode status; + ParsedNumber result; + // Note: if this is a currency instance, currencies will be matched despite the fact that we are not in the + // parseCurrency method (backwards compatibility) + int32_t startIndex = parsePosition.getIndex(); + const NumberParserImpl* parser = getCurrencyParser(status); + if (U_FAILURE(status)) { return nullptr; } + parser->parse(text, startIndex, true, result, status); + // TODO: Do we need to check for fImpl->properties->parseAllInput (UCONFIG_HAVE_PARSEALLINPUT) here? + if (result.success()) { + parsePosition.setIndex(result.charEnd); + Formattable formattable; + result.populateFormattable(formattable, parser->getParseFlags()); + return new CurrencyAmount(formattable, result.currencyCode, status); + } else { + parsePosition.setErrorIndex(startIndex + result.charEnd); + return nullptr; + } +} + +const DecimalFormatSymbols* DecimalFormat::getDecimalFormatSymbols(void) const { + return fields->symbols.getAlias(); +} + +void DecimalFormat::adoptDecimalFormatSymbols(DecimalFormatSymbols* symbolsToAdopt) { + if (symbolsToAdopt == nullptr) { + return; // do not allow caller to set fields->symbols to NULL + } + fields->symbols.adoptInstead(symbolsToAdopt); + touchNoError(); +} + +void DecimalFormat::setDecimalFormatSymbols(const DecimalFormatSymbols& symbols) { + fields->symbols.adoptInstead(new DecimalFormatSymbols(symbols)); + touchNoError(); +} + +const CurrencyPluralInfo* DecimalFormat::getCurrencyPluralInfo(void) const { + return fields->properties->currencyPluralInfo.fPtr.getAlias(); +} + +void DecimalFormat::adoptCurrencyPluralInfo(CurrencyPluralInfo* toAdopt) { + fields->properties->currencyPluralInfo.fPtr.adoptInstead(toAdopt); + touchNoError(); +} + +void DecimalFormat::setCurrencyPluralInfo(const CurrencyPluralInfo& info) { + if (fields->properties->currencyPluralInfo.fPtr.isNull()) { + fields->properties->currencyPluralInfo.fPtr.adoptInstead(info.clone()); + } else { + *fields->properties->currencyPluralInfo.fPtr = info; // copy-assignment operator + } + touchNoError(); +} + +UnicodeString& DecimalFormat::getPositivePrefix(UnicodeString& result) const { + ErrorCode localStatus; + fields->formatter->getAffixImpl(true, false, result, localStatus); + return result; +} + +void DecimalFormat::setPositivePrefix(const UnicodeString& newValue) { + if (newValue == fields->properties->positivePrefix) { return; } + fields->properties->positivePrefix = newValue; + touchNoError(); +} + +UnicodeString& DecimalFormat::getNegativePrefix(UnicodeString& result) const { + ErrorCode localStatus; + fields->formatter->getAffixImpl(true, true, result, localStatus); + return result; +} + +void DecimalFormat::setNegativePrefix(const UnicodeString& newValue) { + if (newValue == fields->properties->negativePrefix) { return; } + fields->properties->negativePrefix = newValue; + touchNoError(); +} + +UnicodeString& DecimalFormat::getPositiveSuffix(UnicodeString& result) const { + ErrorCode localStatus; + fields->formatter->getAffixImpl(false, false, result, localStatus); + return result; +} + +void DecimalFormat::setPositiveSuffix(const UnicodeString& newValue) { + if (newValue == fields->properties->positiveSuffix) { return; } + fields->properties->positiveSuffix = newValue; + touchNoError(); +} + +UnicodeString& DecimalFormat::getNegativeSuffix(UnicodeString& result) const { + ErrorCode localStatus; + fields->formatter->getAffixImpl(false, true, result, localStatus); + return result; +} + +void DecimalFormat::setNegativeSuffix(const UnicodeString& newValue) { + if (newValue == fields->properties->negativeSuffix) { return; } + fields->properties->negativeSuffix = newValue; + touchNoError(); +} + +UBool DecimalFormat::isSignAlwaysShown() const { + return fields->properties->signAlwaysShown; +} + +void DecimalFormat::setSignAlwaysShown(UBool value) { + if (UBOOL_TO_BOOL(value) == fields->properties->signAlwaysShown) { return; } + fields->properties->signAlwaysShown = value; + touchNoError(); +} + +int32_t DecimalFormat::getMultiplier(void) const { + if (fields->properties->multiplier != 1) { + return fields->properties->multiplier; + } else if (fields->properties->magnitudeMultiplier != 0) { + return static_cast(uprv_pow10(fields->properties->magnitudeMultiplier)); + } else { + return 1; + } +} + +void DecimalFormat::setMultiplier(int32_t multiplier) { + if (multiplier == 0) { + multiplier = 1; // one being the benign default value for a multiplier. + } + + // Try to convert to a magnitude multiplier first + int delta = 0; + int value = multiplier; + while (value != 1) { + delta++; + int temp = value / 10; + if (temp * 10 != value) { + delta = -1; + break; + } + value = temp; + } + if (delta != -1) { + fields->properties->magnitudeMultiplier = delta; + fields->properties->multiplier = 1; + } else { + fields->properties->magnitudeMultiplier = 0; + fields->properties->multiplier = multiplier; + } + touchNoError(); +} + +int32_t DecimalFormat::getMultiplierScale() const { + return fields->properties->multiplierScale; +} + +void DecimalFormat::setMultiplierScale(int32_t newValue) { + if (newValue == fields->properties->multiplierScale) { return; } + fields->properties->multiplierScale = newValue; + touchNoError(); +} + +double DecimalFormat::getRoundingIncrement(void) const { + return fields->exportedProperties->roundingIncrement; +} + +void DecimalFormat::setRoundingIncrement(double newValue) { + if (newValue == fields->properties->roundingIncrement) { return; } + fields->properties->roundingIncrement = newValue; + touchNoError(); +} + +ERoundingMode DecimalFormat::getRoundingMode(void) const { + // UNumberFormatRoundingMode and ERoundingMode have the same values. + return static_cast(fields->exportedProperties->roundingMode.getNoError()); +} + +void DecimalFormat::setRoundingMode(ERoundingMode roundingMode) { + auto uRoundingMode = static_cast(roundingMode); + if (!fields->properties->roundingMode.isNull() && uRoundingMode == fields->properties->roundingMode.getNoError()) { + return; + } + NumberFormat::setMaximumIntegerDigits(roundingMode); // to set field for compatibility + fields->properties->roundingMode = uRoundingMode; + touchNoError(); +} + +int32_t DecimalFormat::getFormatWidth(void) const { + return fields->properties->formatWidth; +} + +void DecimalFormat::setFormatWidth(int32_t width) { + if (width == fields->properties->formatWidth) { return; } + fields->properties->formatWidth = width; + touchNoError(); +} + +UnicodeString DecimalFormat::getPadCharacterString() const { + if (fields->properties->padString.isBogus()) { + // Readonly-alias the static string kFallbackPaddingString + return {TRUE, kFallbackPaddingString, -1}; + } else { + return fields->properties->padString; + } +} + +void DecimalFormat::setPadCharacter(const UnicodeString& padChar) { + if (padChar == fields->properties->padString) { return; } + if (padChar.length() > 0) { + fields->properties->padString = UnicodeString(padChar.char32At(0)); + } else { + fields->properties->padString.setToBogus(); + } + touchNoError(); +} + +EPadPosition DecimalFormat::getPadPosition(void) const { + if (fields->properties->padPosition.isNull()) { + return EPadPosition::kPadBeforePrefix; + } else { + // UNumberFormatPadPosition and EPadPosition have the same values. + return static_cast(fields->properties->padPosition.getNoError()); + } +} + +void DecimalFormat::setPadPosition(EPadPosition padPos) { + auto uPadPos = static_cast(padPos); + if (!fields->properties->padPosition.isNull() && uPadPos == fields->properties->padPosition.getNoError()) { + return; + } + fields->properties->padPosition = uPadPos; + touchNoError(); +} + +UBool DecimalFormat::isScientificNotation(void) const { + return fields->properties->minimumExponentDigits != -1; +} + +void DecimalFormat::setScientificNotation(UBool useScientific) { + int32_t minExp = useScientific ? 1 : -1; + if (fields->properties->minimumExponentDigits == minExp) { return; } + if (useScientific) { + fields->properties->minimumExponentDigits = 1; + } else { + fields->properties->minimumExponentDigits = -1; + } + touchNoError(); +} + +int8_t DecimalFormat::getMinimumExponentDigits(void) const { + return static_cast(fields->properties->minimumExponentDigits); +} + +void DecimalFormat::setMinimumExponentDigits(int8_t minExpDig) { + if (minExpDig == fields->properties->minimumExponentDigits) { return; } + fields->properties->minimumExponentDigits = minExpDig; + touchNoError(); +} + +UBool DecimalFormat::isExponentSignAlwaysShown(void) const { + return fields->properties->exponentSignAlwaysShown; +} + +void DecimalFormat::setExponentSignAlwaysShown(UBool expSignAlways) { + if (UBOOL_TO_BOOL(expSignAlways) == fields->properties->exponentSignAlwaysShown) { return; } + fields->properties->exponentSignAlwaysShown = expSignAlways; + touchNoError(); +} + +int32_t DecimalFormat::getGroupingSize(void) const { + if (fields->properties->groupingSize < 0) { + return 0; + } + return fields->properties->groupingSize; +} + +void DecimalFormat::setGroupingSize(int32_t newValue) { + if (newValue == fields->properties->groupingSize) { return; } + fields->properties->groupingSize = newValue; + touchNoError(); +} + +int32_t DecimalFormat::getSecondaryGroupingSize(void) const { + int grouping2 = fields->properties->secondaryGroupingSize; + if (grouping2 < 0) { + return 0; + } + return grouping2; +} + +void DecimalFormat::setSecondaryGroupingSize(int32_t newValue) { + if (newValue == fields->properties->secondaryGroupingSize) { return; } + fields->properties->secondaryGroupingSize = newValue; + touchNoError(); +} + +int32_t DecimalFormat::getMinimumGroupingDigits() const { + return fields->properties->minimumGroupingDigits; +} + +void DecimalFormat::setMinimumGroupingDigits(int32_t newValue) { + if (newValue == fields->properties->minimumGroupingDigits) { return; } + fields->properties->minimumGroupingDigits = newValue; + touchNoError(); +} + +UBool DecimalFormat::isDecimalSeparatorAlwaysShown(void) const { + return fields->properties->decimalSeparatorAlwaysShown; +} + +void DecimalFormat::setDecimalSeparatorAlwaysShown(UBool newValue) { + if (UBOOL_TO_BOOL(newValue) == fields->properties->decimalSeparatorAlwaysShown) { return; } + fields->properties->decimalSeparatorAlwaysShown = newValue; + touchNoError(); +} + +UBool DecimalFormat::isDecimalPatternMatchRequired(void) const { + return fields->properties->decimalPatternMatchRequired; +} + +void DecimalFormat::setDecimalPatternMatchRequired(UBool newValue) { + if (UBOOL_TO_BOOL(newValue) == fields->properties->decimalPatternMatchRequired) { return; } + fields->properties->decimalPatternMatchRequired = newValue; + touchNoError(); +} + +UBool DecimalFormat::isParseNoExponent() const { + return fields->properties->parseNoExponent; +} + +void DecimalFormat::setParseNoExponent(UBool value) { + if (UBOOL_TO_BOOL(value) == fields->properties->parseNoExponent) { return; } + fields->properties->parseNoExponent = value; + touchNoError(); +} + +UBool DecimalFormat::isParseCaseSensitive() const { + return fields->properties->parseCaseSensitive; +} + +void DecimalFormat::setParseCaseSensitive(UBool value) { + if (UBOOL_TO_BOOL(value) == fields->properties->parseCaseSensitive) { return; } + fields->properties->parseCaseSensitive = value; + touchNoError(); +} + +UBool DecimalFormat::isFormatFailIfMoreThanMaxDigits() const { + return fields->properties->formatFailIfMoreThanMaxDigits; +} + +void DecimalFormat::setFormatFailIfMoreThanMaxDigits(UBool value) { + if (UBOOL_TO_BOOL(value) == fields->properties->formatFailIfMoreThanMaxDigits) { return; } + fields->properties->formatFailIfMoreThanMaxDigits = value; + touchNoError(); +} + +UnicodeString& DecimalFormat::toPattern(UnicodeString& result) const { + // Pull some properties from exportedProperties and others from properties + // to keep affix patterns intact. In particular, pull rounding properties + // so that CurrencyUsage is reflected properly. + // TODO: Consider putting this logic in number_patternstring.cpp instead. + ErrorCode localStatus; + DecimalFormatProperties tprops(*fields->properties); + bool useCurrency = ((!tprops.currency.isNull()) || !tprops.currencyPluralInfo.fPtr.isNull() || + !tprops.currencyUsage.isNull() || AffixUtils::hasCurrencySymbols( + tprops.positivePrefixPattern, localStatus) || AffixUtils::hasCurrencySymbols( + tprops.positiveSuffixPattern, localStatus) || AffixUtils::hasCurrencySymbols( + tprops.negativePrefixPattern, localStatus) || AffixUtils::hasCurrencySymbols( + tprops.negativeSuffixPattern, localStatus)); + if (useCurrency) { + tprops.minimumFractionDigits = fields->exportedProperties->minimumFractionDigits; + tprops.maximumFractionDigits = fields->exportedProperties->maximumFractionDigits; + tprops.roundingIncrement = fields->exportedProperties->roundingIncrement; + } + result = PatternStringUtils::propertiesToPatternString(tprops, localStatus); + return result; +} + +UnicodeString& DecimalFormat::toLocalizedPattern(UnicodeString& result) const { + ErrorCode localStatus; + result = toPattern(result); + result = PatternStringUtils::convertLocalized(result, *fields->symbols, true, localStatus); + return result; +} + +void DecimalFormat::applyPattern(const UnicodeString& pattern, UParseError&, UErrorCode& status) { + // TODO: What is parseError for? + applyPattern(pattern, status); +} + +void DecimalFormat::applyPattern(const UnicodeString& pattern, UErrorCode& status) { + setPropertiesFromPattern(pattern, IGNORE_ROUNDING_NEVER, status); + touch(status); +} + +void DecimalFormat::applyLocalizedPattern(const UnicodeString& localizedPattern, UParseError&, + UErrorCode& status) { + // TODO: What is parseError for? + applyLocalizedPattern(localizedPattern, status); +} + +void DecimalFormat::applyLocalizedPattern(const UnicodeString& localizedPattern, UErrorCode& status) { + if (U_SUCCESS(status)) { + UnicodeString pattern = PatternStringUtils::convertLocalized( + localizedPattern, *fields->symbols, false, status); + applyPattern(pattern, status); + } +} + +void DecimalFormat::setMaximumIntegerDigits(int32_t newValue) { + if (newValue == fields->properties->maximumIntegerDigits) { return; } + // For backwards compatibility, conflicting min/max need to keep the most recent setting. + int32_t min = fields->properties->minimumIntegerDigits; + if (min >= 0 && min > newValue) { + fields->properties->minimumIntegerDigits = newValue; + } + fields->properties->maximumIntegerDigits = newValue; + touchNoError(); +} + +void DecimalFormat::setMinimumIntegerDigits(int32_t newValue) { + if (newValue == fields->properties->minimumIntegerDigits) { return; } + // For backwards compatibility, conflicting min/max need to keep the most recent setting. + int32_t max = fields->properties->maximumIntegerDigits; + if (max >= 0 && max < newValue) { + fields->properties->maximumIntegerDigits = newValue; + } + fields->properties->minimumIntegerDigits = newValue; + touchNoError(); +} + +void DecimalFormat::setMaximumFractionDigits(int32_t newValue) { + if (newValue == fields->properties->maximumFractionDigits) { return; } + // For backwards compatibility, conflicting min/max need to keep the most recent setting. + int32_t min = fields->properties->minimumFractionDigits; + if (min >= 0 && min > newValue) { + fields->properties->minimumFractionDigits = newValue; + } + fields->properties->maximumFractionDigits = newValue; + touchNoError(); +} + +void DecimalFormat::setMinimumFractionDigits(int32_t newValue) { + if (newValue == fields->properties->minimumFractionDigits) { return; } + // For backwards compatibility, conflicting min/max need to keep the most recent setting. + int32_t max = fields->properties->maximumFractionDigits; + if (max >= 0 && max < newValue) { + fields->properties->maximumFractionDigits = newValue; + } + fields->properties->minimumFractionDigits = newValue; + touchNoError(); +} + +int32_t DecimalFormat::getMinimumSignificantDigits() const { + return fields->exportedProperties->minimumSignificantDigits; +} + +int32_t DecimalFormat::getMaximumSignificantDigits() const { + return fields->exportedProperties->maximumSignificantDigits; +} + +void DecimalFormat::setMinimumSignificantDigits(int32_t value) { + if (value == fields->properties->minimumSignificantDigits) { return; } + int32_t max = fields->properties->maximumSignificantDigits; + if (max >= 0 && max < value) { + fields->properties->maximumSignificantDigits = value; + } + fields->properties->minimumSignificantDigits = value; + touchNoError(); +} + +void DecimalFormat::setMaximumSignificantDigits(int32_t value) { + if (value == fields->properties->maximumSignificantDigits) { return; } + int32_t min = fields->properties->minimumSignificantDigits; + if (min >= 0 && min > value) { + fields->properties->minimumSignificantDigits = value; + } + fields->properties->maximumSignificantDigits = value; + touchNoError(); +} + +UBool DecimalFormat::areSignificantDigitsUsed() const { + return fields->properties->minimumSignificantDigits != -1 || fields->properties->maximumSignificantDigits != -1; +} + +void DecimalFormat::setSignificantDigitsUsed(UBool useSignificantDigits) { + if (areSignificantDigitsUsed()) return; + // These are the default values from the old implementation. + int32_t minSig = useSignificantDigits ? 1 : -1; + int32_t maxSig = useSignificantDigits ? 6 : -1; + if (fields->properties->minimumSignificantDigits == minSig && + fields->properties->maximumSignificantDigits == maxSig) { + return; + } + fields->properties->minimumSignificantDigits = minSig; + fields->properties->maximumSignificantDigits = maxSig; + touchNoError(); +} + +void DecimalFormat::setCurrency(const char16_t* theCurrency, UErrorCode& ec) { + CurrencyUnit currencyUnit(theCurrency, ec); + if (U_FAILURE(ec)) { return; } + if (!fields->properties->currency.isNull() && fields->properties->currency.getNoError() == currencyUnit) { + return; + } + NumberFormat::setCurrency(theCurrency, ec); // to set field for compatibility + fields->properties->currency = currencyUnit; + // TODO: Set values in fields->symbols, too? + touchNoError(); +} + +void DecimalFormat::setCurrency(const char16_t* theCurrency) { + ErrorCode localStatus; + setCurrency(theCurrency, localStatus); +} + +void DecimalFormat::setCurrencyUsage(UCurrencyUsage newUsage, UErrorCode* ec) { + if (U_FAILURE(*ec)) { + return; + } + if (!fields->properties->currencyUsage.isNull() && newUsage == fields->properties->currencyUsage.getNoError()) { + return; + } + fields->properties->currencyUsage = newUsage; + touch(*ec); +} + +UCurrencyUsage DecimalFormat::getCurrencyUsage() const { + // CurrencyUsage is not exported, so we have to get it from the input property bag. + // TODO: Should we export CurrencyUsage instead? + if (fields->properties->currencyUsage.isNull()) { + return UCURR_USAGE_STANDARD; + } + return fields->properties->currencyUsage.getNoError(); +} + +void +DecimalFormat::formatToDecimalQuantity(double number, DecimalQuantity& output, UErrorCode& status) const { + fields->formatter->formatDouble(number, status).getDecimalQuantity(output, status); +} + +void DecimalFormat::formatToDecimalQuantity(const Formattable& number, DecimalQuantity& output, + UErrorCode& status) const { + UFormattedNumberData obj; + number.populateDecimalQuantity(obj.quantity, status); + fields->formatter->formatImpl(&obj, status); + output = std::move(obj.quantity); +} + +const number::LocalizedNumberFormatter& DecimalFormat::toNumberFormatter() const { + return *fields->formatter; +} + +/** Rebuilds the formatter object from the property bag. */ +void DecimalFormat::touch(UErrorCode& status) { + if (fields->exportedProperties == nullptr) { + // fields->exportedProperties is null only when the formatter is not ready yet. + // The only time when this happens is during legacy deserialization. + return; + } + + // In C++, fields->symbols is the source of truth for the locale. + Locale locale = fields->symbols->getLocale(); + + // Note: The formatter is relatively cheap to create, and we need it to populate fields->exportedProperties, + // so automatically compute it here. The parser is a bit more expensive and is not needed until the + // parse method is called, so defer that until needed. + // TODO: Only update the pieces that changed instead of re-computing the whole formatter? + fields->formatter.adoptInstead( + new LocalizedNumberFormatter( + NumberPropertyMapper::create( + *fields->properties, *fields->symbols, fields->warehouse, *fields->exportedProperties, status).locale( + locale))); + + // Do this after fields->exportedProperties are set up + setupFastFormat(); + + // Delete the parsers if they were made previously + delete fields->atomicParser.exchange(nullptr); + delete fields->atomicCurrencyParser.exchange(nullptr); + + // In order for the getters to work, we need to populate some fields in NumberFormat. + NumberFormat::setCurrency(fields->exportedProperties->currency.get(status).getISOCurrency(), status); + NumberFormat::setMaximumIntegerDigits(fields->exportedProperties->maximumIntegerDigits); + NumberFormat::setMinimumIntegerDigits(fields->exportedProperties->minimumIntegerDigits); + NumberFormat::setMaximumFractionDigits(fields->exportedProperties->maximumFractionDigits); + NumberFormat::setMinimumFractionDigits(fields->exportedProperties->minimumFractionDigits); + // fImpl->properties, not fields->exportedProperties, since this information comes from the pattern: + NumberFormat::setGroupingUsed(fields->properties->groupingUsed); +} + +void DecimalFormat::touchNoError() { + UErrorCode localStatus = U_ZERO_ERROR; + touch(localStatus); +} + +void DecimalFormat::setPropertiesFromPattern(const UnicodeString& pattern, int32_t ignoreRounding, + UErrorCode& status) { + if (U_SUCCESS(status)) { + // Cast workaround to get around putting the enum in the public header file + auto actualIgnoreRounding = static_cast(ignoreRounding); + PatternParser::parseToExistingProperties(pattern, *fields->properties, actualIgnoreRounding, status); + } +} + +const numparse::impl::NumberParserImpl* DecimalFormat::getParser(UErrorCode& status) const { + if (U_FAILURE(status)) { return nullptr; } + + // First try to get the pre-computed parser + auto* ptr = fields->atomicParser.load(); + if (ptr != nullptr) { + return ptr; + } + + // Try computing the parser on our own + auto* temp = NumberParserImpl::createParserFromProperties(*fields->properties, *fields->symbols, false, status); + if (temp == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + // although we may still dereference, call sites should be guarded + } + + // Note: ptr starts as nullptr; during compare_exchange, it is set to what is actually stored in the + // atomic if another thread beat us to computing the parser object. + auto* nonConstThis = const_cast(this); + if (!nonConstThis->fields->atomicParser.compare_exchange_strong(ptr, temp)) { + // Another thread beat us to computing the parser + delete temp; + return ptr; + } else { + // Our copy of the parser got stored in the atomic + return temp; + } +} + +const numparse::impl::NumberParserImpl* DecimalFormat::getCurrencyParser(UErrorCode& status) const { + if (U_FAILURE(status)) { return nullptr; } + + // First try to get the pre-computed parser + auto* ptr = fields->atomicCurrencyParser.load(); + if (ptr != nullptr) { + return ptr; + } + + // Try computing the parser on our own + auto* temp = NumberParserImpl::createParserFromProperties(*fields->properties, *fields->symbols, true, status); + if (temp == nullptr) { + status = U_MEMORY_ALLOCATION_ERROR; + // although we may still dereference, call sites should be guarded + } + + // Note: ptr starts as nullptr; during compare_exchange, it is set to what is actually stored in the + // atomic if another thread beat us to computing the parser object. + auto* nonConstThis = const_cast(this); + if (!nonConstThis->fields->atomicCurrencyParser.compare_exchange_strong(ptr, temp)) { + // Another thread beat us to computing the parser + delete temp; + return ptr; + } else { + // Our copy of the parser got stored in the atomic + return temp; + } +} + +void +DecimalFormat::fieldPositionHelper(const number::FormattedNumber& formatted, FieldPosition& fieldPosition, + int32_t offset, UErrorCode& status) { + // always return first occurrence: + fieldPosition.setBeginIndex(0); + fieldPosition.setEndIndex(0); + bool found = formatted.nextFieldPosition(fieldPosition, status); + if (found && offset != 0) { + FieldPositionOnlyHandler fpoh(fieldPosition); + fpoh.shiftLast(offset); + } +} + +void +DecimalFormat::fieldPositionIteratorHelper(const number::FormattedNumber& formatted, FieldPositionIterator* fpi, + int32_t offset, UErrorCode& status) { + if (fpi != nullptr) { + FieldPositionIteratorHandler fpih(fpi, status); + fpih.setShift(offset); + formatted.getAllFieldPositionsImpl(fpih, status); + } +} + +// To debug fast-format, change void(x) to printf(x) +#define trace(x) void(x) + +void DecimalFormat::setupFastFormat() { + // Check the majority of properties: + if (!fields->properties->equalsDefaultExceptFastFormat()) { + trace("no fast format: equality\n"); + fields->canUseFastFormat = false; + return; + } + + // Now check the remaining properties. + // Nontrivial affixes: + UBool trivialPP = fields->properties->positivePrefixPattern.isEmpty(); + UBool trivialPS = fields->properties->positiveSuffixPattern.isEmpty(); + UBool trivialNP = fields->properties->negativePrefixPattern.isBogus() || ( + fields->properties->negativePrefixPattern.length() == 1 && + fields->properties->negativePrefixPattern.charAt(0) == u'-'); + UBool trivialNS = fields->properties->negativeSuffixPattern.isEmpty(); + if (!trivialPP || !trivialPS || !trivialNP || !trivialNS) { + trace("no fast format: affixes\n"); + fields->canUseFastFormat = false; + return; + } + + // Grouping (secondary grouping is forbidden in equalsDefaultExceptFastFormat): + bool groupingUsed = fields->properties->groupingUsed; + int32_t groupingSize = fields->properties->groupingSize; + bool unusualGroupingSize = groupingSize > 0 && groupingSize != 3; + const UnicodeString& groupingString = fields->symbols->getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol); + if (groupingUsed && (unusualGroupingSize || groupingString.length() != 1)) { + trace("no fast format: grouping\n"); + fields->canUseFastFormat = false; + return; + } + + // Integer length: + int32_t minInt = fields->exportedProperties->minimumIntegerDigits; + int32_t maxInt = fields->exportedProperties->maximumIntegerDigits; + // Fastpath supports up to only 10 digits (length of INT32_MIN) + if (minInt > 10) { + trace("no fast format: integer\n"); + fields->canUseFastFormat = false; + return; + } + + // Fraction length (no fraction part allowed in fast path): + int32_t minFrac = fields->exportedProperties->minimumFractionDigits; + if (minFrac > 0) { + trace("no fast format: fraction\n"); + fields->canUseFastFormat = false; + return; + } + + // Other symbols: + const UnicodeString& minusSignString = fields->symbols->getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol); + UChar32 codePointZero = fields->symbols->getCodePointZero(); + if (minusSignString.length() != 1 || U16_LENGTH(codePointZero) != 1) { + trace("no fast format: symbols\n"); + fields->canUseFastFormat = false; + return; + } + + // Good to go! + trace("can use fast format!\n"); + fields->canUseFastFormat = true; + fields->fastData.cpZero = static_cast(codePointZero); + fields->fastData.cpGroupingSeparator = groupingUsed && groupingSize == 3 ? groupingString.charAt(0) : 0; + fields->fastData.cpMinusSign = minusSignString.charAt(0); + fields->fastData.minInt = (minInt < 0 || minInt > 127) ? 0 : static_cast(minInt); + fields->fastData.maxInt = (maxInt < 0 || maxInt > 127) ? 127 : static_cast(maxInt); +} + +bool DecimalFormat::fastFormatDouble(double input, UnicodeString& output) const { + if (!fields->canUseFastFormat) { + return false; + } + if (std::isnan(input) + || std::trunc(input) != input + || input <= INT32_MIN + || input > INT32_MAX) { + return false; + } + doFastFormatInt32(static_cast(input), std::signbit(input), output); + return true; +} + +bool DecimalFormat::fastFormatInt64(int64_t input, UnicodeString& output) const { + if (!fields->canUseFastFormat) { + return false; + } + if (input <= INT32_MIN || input > INT32_MAX) { + return false; + } + doFastFormatInt32(static_cast(input), input < 0, output); + return true; +} + +void DecimalFormat::doFastFormatInt32(int32_t input, bool isNegative, UnicodeString& output) const { + U_ASSERT(fields->canUseFastFormat); + if (isNegative) { + output.append(fields->fastData.cpMinusSign); + U_ASSERT(input != INT32_MIN); // handled by callers + input = -input; + } + // Cap at int32_t to make the buffer small and operations fast. + // Longest string: "2,147,483,648" (13 chars in length) + static constexpr int32_t localCapacity = 13; + char16_t localBuffer[localCapacity]; + char16_t* ptr = localBuffer + localCapacity; + int8_t group = 0; + for (int8_t i = 0; i < fields->fastData.maxInt && (input != 0 || i < fields->fastData.minInt); i++) { + if (group++ == 3 && fields->fastData.cpGroupingSeparator != 0) { + *(--ptr) = fields->fastData.cpGroupingSeparator; + group = 1; + } + std::div_t res = std::div(input, 10); + *(--ptr) = static_cast(fields->fastData.cpZero + res.rem); + input = res.quot; + } + int32_t len = localCapacity - static_cast(ptr - localBuffer); + output.append(ptr, len); +} + + +#endif /* #if !UCONFIG_NO_FORMATTING */