diff --git a/deps/chakrashim/include/v8-version.h b/deps/chakrashim/include/v8-version.h index 8c4bc023770..c3bd1dfe2dd 100644 --- a/deps/chakrashim/include/v8-version.h +++ b/deps/chakrashim/include/v8-version.h @@ -11,7 +11,7 @@ #define V8_MAJOR_VERSION 6 #define V8_MINOR_VERSION 4 #define V8_BUILD_NUMBER 388 -#define V8_PATCH_LEVEL 42 +#define V8_PATCH_LEVEL 44 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h index 8c4bc023770..c3bd1dfe2dd 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 4 #define V8_BUILD_NUMBER 388 -#define V8_PATCH_LEVEL 42 +#define V8_PATCH_LEVEL 44 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) diff --git a/deps/v8/src/objects-inl.h b/deps/v8/src/objects-inl.h index 77ad0872686..1cbb2990574 100644 --- a/deps/v8/src/objects-inl.h +++ b/deps/v8/src/objects-inl.h @@ -2231,7 +2231,8 @@ int Map::NumberOfOwnDescriptors() const { void Map::SetNumberOfOwnDescriptors(int number) { - DCHECK(number <= instance_descriptors()->number_of_descriptors()); + CHECK_LE(static_cast(number), + static_cast(kMaxNumberOfDescriptors)); set_bit_field3(NumberOfOwnDescriptorsBits::update(bit_field3(), number)); } @@ -2239,8 +2240,9 @@ int Map::EnumLength() const { return EnumLengthBits::decode(bit_field3()); } void Map::SetEnumLength(int length) { if (length != kInvalidEnumCacheSentinel) { - DCHECK_GE(length, 0); - DCHECK(length <= NumberOfOwnDescriptors()); + DCHECK_LE(length, NumberOfOwnDescriptors()); + CHECK_LE(static_cast(length), + static_cast(kMaxNumberOfDescriptors)); } set_bit_field3(EnumLengthBits::update(bit_field3(), length)); } @@ -3002,9 +3004,9 @@ int Map::instance_size() const { } void Map::set_instance_size(int value) { - DCHECK_EQ(0, value & (kPointerSize - 1)); + CHECK_EQ(0, value & (kPointerSize - 1)); value >>= kPointerSizeLog2; - DCHECK(0 <= value && value < 256); + CHECK_LT(static_cast(value), 256); set_instance_size_in_words(value); } @@ -3015,8 +3017,7 @@ int Map::inobject_properties_start_or_constructor_function_index() const { void Map::set_inobject_properties_start_or_constructor_function_index( int value) { - DCHECK_LE(0, value); - DCHECK_LT(value, 256); + CHECK_LT(static_cast(value), 256); RELAXED_WRITE_BYTE_FIELD( this, kInObjectPropertiesStartOrConstructorFunctionIndexOffset, static_cast(value)); @@ -3028,7 +3029,7 @@ int Map::GetInObjectPropertiesStartInWords() const { } void Map::SetInObjectPropertiesStartInWords(int value) { - DCHECK(IsJSObjectMap()); + CHECK(IsJSObjectMap()); set_inobject_properties_start_or_constructor_function_index(value); } @@ -3044,7 +3045,7 @@ int Map::GetConstructorFunctionIndex() const { void Map::SetConstructorFunctionIndex(int value) { - DCHECK(IsPrimitiveMap()); + CHECK(IsPrimitiveMap()); set_inobject_properties_start_or_constructor_function_index(value); } @@ -3153,8 +3154,7 @@ int Map::used_or_unused_instance_size_in_words() const { } void Map::set_used_or_unused_instance_size_in_words(int value) { - DCHECK_LE(0, value); - DCHECK_LE(value, 255); + CHECK_LE(static_cast(value), 255); WRITE_BYTE_FIELD(this, kUsedOrUnusedInstanceSizeInWordsOffset, static_cast(value)); } @@ -3172,12 +3172,12 @@ int Map::UsedInstanceSize() const { void Map::SetInObjectUnusedPropertyFields(int value) { STATIC_ASSERT(JSObject::kFieldsAdded == JSObject::kHeaderSize / kPointerSize); if (!IsJSObjectMap()) { - DCHECK_EQ(0, value); + CHECK_EQ(0, value); set_used_or_unused_instance_size_in_words(0); DCHECK_EQ(0, UnusedPropertyFields()); return; } - DCHECK_LE(0, value); + CHECK_LE(0, value); DCHECK_LE(value, GetInObjectProperties()); int used_inobject_properties = GetInObjectProperties() - value; set_used_or_unused_instance_size_in_words( @@ -3187,8 +3187,7 @@ void Map::SetInObjectUnusedPropertyFields(int value) { void Map::SetOutOfObjectUnusedPropertyFields(int value) { STATIC_ASSERT(JSObject::kFieldsAdded == JSObject::kHeaderSize / kPointerSize); - DCHECK_LE(0, value); - DCHECK_LT(value, JSObject::kFieldsAdded); + CHECK_LT(static_cast(value), JSObject::kFieldsAdded); // For out of object properties "used_instance_size_in_words" byte encodes // the slack in the property array. set_used_or_unused_instance_size_in_words(value); @@ -3227,8 +3226,8 @@ void Map::AccountAddedOutOfObjectPropertyField(int unused_in_property_array) { if (unused_in_property_array < 0) { unused_in_property_array += JSObject::kFieldsAdded; } - DCHECK_GE(unused_in_property_array, 0); - DCHECK_LT(unused_in_property_array, JSObject::kFieldsAdded); + CHECK_LT(static_cast(unused_in_property_array), + JSObject::kFieldsAdded); set_used_or_unused_instance_size_in_words(unused_in_property_array); DCHECK_EQ(unused_in_property_array, UnusedPropertyFields()); } @@ -3358,7 +3357,7 @@ bool Map::should_be_fast_prototype_map() const { } void Map::set_elements_kind(ElementsKind elements_kind) { - DCHECK_LT(static_cast(elements_kind), kElementsKindCount); + CHECK_LT(static_cast(elements_kind), kElementsKindCount); DCHECK_LE(kElementsKindCount, 1 << Map::ElementsKindBits::kSize); set_bit_field2(Map::ElementsKindBits::update(bit_field2(), elements_kind)); DCHECK(this->elements_kind() == elements_kind); @@ -3700,7 +3699,7 @@ Object* Map::prototype_info() const { void Map::set_prototype_info(Object* value, WriteBarrierMode mode) { - DCHECK(is_prototype_map()); + CHECK(is_prototype_map()); WRITE_FIELD(this, Map::kTransitionsOrPrototypeInfoOffset, value); CONDITIONAL_WRITE_BARRIER( GetHeap(), this, Map::kTransitionsOrPrototypeInfoOffset, value, mode); @@ -3708,11 +3707,11 @@ void Map::set_prototype_info(Object* value, WriteBarrierMode mode) { void Map::SetBackPointer(Object* value, WriteBarrierMode mode) { - DCHECK(instance_type() >= FIRST_JS_RECEIVER_TYPE); - DCHECK(value->IsMap()); - DCHECK(GetBackPointer()->IsUndefined(GetIsolate())); - DCHECK(!value->IsMap() || - Map::cast(value)->GetConstructor() == constructor_or_backpointer()); + CHECK_GE(instance_type(), FIRST_JS_RECEIVER_TYPE); + CHECK(value->IsMap()); + CHECK(GetBackPointer()->IsUndefined(GetIsolate())); + CHECK_IMPLIES(value->IsMap(), Map::cast(value)->GetConstructor() == + constructor_or_backpointer()); set_constructor_or_backpointer(value, mode); } @@ -3743,7 +3742,7 @@ FunctionTemplateInfo* Map::GetFunctionTemplateInfo() const { void Map::SetConstructor(Object* constructor, WriteBarrierMode mode) { // Never overwrite a back pointer with a constructor. - DCHECK(!constructor_or_backpointer()->IsMap()); + CHECK(!constructor_or_backpointer()->IsMap()); set_constructor_or_backpointer(constructor, mode); } diff --git a/deps/v8/src/objects.cc b/deps/v8/src/objects.cc index 7b3c632a447..bd876e67d7b 100644 --- a/deps/v8/src/objects.cc +++ b/deps/v8/src/objects.cc @@ -13014,14 +13014,19 @@ MaybeHandle JSFunction::GetDerivedMap(Isolate* isolate, constructor_initial_map->UnusedPropertyFields(); int instance_size; int in_object_properties; - CalculateInstanceSizeForDerivedClass(function, instance_type, - embedder_fields, &instance_size, - &in_object_properties); + bool success = CalculateInstanceSizeForDerivedClass( + function, instance_type, embedder_fields, &instance_size, + &in_object_properties); int unused_property_fields = in_object_properties - pre_allocated; - Handle map = - Map::CopyInitialMap(constructor_initial_map, instance_size, - in_object_properties, unused_property_fields); + + Handle map; + if (success) { + map = Map::CopyInitialMap(constructor_initial_map, instance_size, + in_object_properties, unused_property_fields); + } else { + map = Map::CopyInitialMap(constructor_initial_map); + } map->set_new_target_is_base(false); JSFunction::SetInitialMap(function, map, prototype); @@ -13726,12 +13731,14 @@ void JSFunction::CalculateInstanceSizeHelper(InstanceType instance_type, requested_embedder_fields; } -void JSFunction::CalculateInstanceSizeForDerivedClass( +// static +bool JSFunction::CalculateInstanceSizeForDerivedClass( Handle function, InstanceType instance_type, int requested_embedder_fields, int* instance_size, int* in_object_properties) { Isolate* isolate = function->GetIsolate(); int expected_nof_properties = 0; + bool result = true; for (PrototypeIterator iter(isolate, function, kStartAtReceiver); !iter.IsAtEnd(); iter.Advance()) { Handle current = @@ -13745,6 +13752,11 @@ void JSFunction::CalculateInstanceSizeForDerivedClass( Compiler::Compile(func, Compiler::CLEAR_EXCEPTION)) { DCHECK(shared->is_compiled()); expected_nof_properties += shared->expected_nof_properties(); + } else if (!shared->is_compiled()) { + // In case there was a compilation error for the constructor we will + // throw an error during instantiation. Hence we directly return 0; + result = false; + break; } if (!IsDerivedConstructor(shared->kind())) { break; @@ -13753,6 +13765,7 @@ void JSFunction::CalculateInstanceSizeForDerivedClass( CalculateInstanceSizeHelper(instance_type, true, requested_embedder_fields, expected_nof_properties, instance_size, in_object_properties); + return result; } diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index a9be023ec83..521c0e65549 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -4082,7 +4082,7 @@ class JSFunction: public JSObject { DECL_CAST(JSFunction) // Calculate the instance size and in-object properties count. - static void CalculateInstanceSizeForDerivedClass( + static bool CalculateInstanceSizeForDerivedClass( Handle function, InstanceType instance_type, int requested_embedder_fields, int* instance_size, int* in_object_properties); diff --git a/deps/v8/src/profiler/heap-snapshot-generator.cc b/deps/v8/src/profiler/heap-snapshot-generator.cc index 1f6459c904f..6f3a952d1f7 100644 --- a/deps/v8/src/profiler/heap-snapshot-generator.cc +++ b/deps/v8/src/profiler/heap-snapshot-generator.cc @@ -1113,8 +1113,6 @@ void V8HeapExplorer::ExtractMapReferences(int entry, Map* map) { constructor_or_backpointer, Map::kConstructorOrBackPointerOffset); } else { - DCHECK(constructor_or_backpointer->IsJSFunction() || - constructor_or_backpointer->IsNull(map->GetIsolate())); SetInternalReference(map, entry, "constructor", constructor_or_backpointer, Map::kConstructorOrBackPointerOffset); } diff --git a/deps/v8/test/cctest/test-heap-profiler.cc b/deps/v8/test/cctest/test-heap-profiler.cc index a0796ccd56c..5a94708ba8e 100644 --- a/deps/v8/test/cctest/test-heap-profiler.cc +++ b/deps/v8/test/cctest/test-heap-profiler.cc @@ -3184,3 +3184,14 @@ TEST(SamplingHeapProfilerSampleDuringDeopt) { CHECK(profile); heap_profiler->StopSamplingHeapProfiler(); } + +TEST(HeapSnapshotPrototypeNotJSReceiver) { + LocalContext env; + v8::HandleScope scope(env->GetIsolate()); + v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler(); + CompileRun( + "function object() {}" + "object.prototype = 42;"); + const v8::HeapSnapshot* snapshot = heap_profiler->TakeHeapSnapshot(); + CHECK(ValidateSnapshot(snapshot)); +} diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-806388.js b/deps/v8/test/mjsunit/regress/regress-crbug-806388.js new file mode 100644 index 00000000000..b55b50107ec --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-806388.js @@ -0,0 +1,20 @@ +// Copyright 2018 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax --enable-slow-asserts --expose-gc + +class Derived extends Array { + constructor(a) { + // Syntax Error. + const a = 1; + } +} + +// Derived is not a subclass of RegExp +let o = Reflect.construct(RegExp, [], Derived); +o.lastIndex = 0x1234; +%HeapObjectVerify(o); + +gc(); +%HeapObjectVerify(o); diff --git a/lib/internal/constants.js b/lib/internal/constants.js new file mode 100644 index 00000000000..f0ffec7a447 --- /dev/null +++ b/lib/internal/constants.js @@ -0,0 +1,16 @@ +'use strict'; + +module.exports = { + // Alphabet chars. + CHAR_UPPERCASE_A: 65, /*A*/ + CHAR_LOWERCASE_A: 97, /*a*/ + CHAR_UPPERCASE_Z: 90, /*Z*/ + CHAR_LOWERCASE_Z: 122, /*z*/ + + // Non-alphabetic chars. + CHAR_DOT: 46, /*.*/ + CHAR_FORWARD_SLASH: 47, /*/*/ + CHAR_BACKWARD_SLASH: 92, /*\*/ + CHAR_COLON: 58, /*:*/ + CHAR_QUESTION_MARK: 63, /*?*/ +}; diff --git a/lib/path.js b/lib/path.js index eca4fcb9d21..248809b2e2f 100644 --- a/lib/path.js +++ b/lib/path.js @@ -22,6 +22,17 @@ 'use strict'; const errors = require('internal/errors'); +const { + CHAR_UPPERCASE_A, + CHAR_LOWERCASE_A, + CHAR_UPPERCASE_Z, + CHAR_LOWERCASE_Z, + CHAR_DOT, + CHAR_FORWARD_SLASH, + CHAR_BACKWARD_SLASH, + CHAR_COLON, + CHAR_QUESTION_MARK, +} = require('internal/constants'); function assertPath(path) { if (typeof path !== 'string') { @@ -39,17 +50,17 @@ function normalizeStringWin32(path, allowAboveRoot) { for (var i = 0; i <= path.length; ++i) { if (i < path.length) code = path.charCodeAt(i); - else if (code === 47/*/*/ || code === 92/*\*/) + else if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) break; else - code = 47/*/*/; - if (code === 47/*/*/ || code === 92/*\*/) { + code = CHAR_FORWARD_SLASH; + if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) { if (lastSlash === i - 1 || dots === 1) { // NOOP } else if (lastSlash !== i - 1 && dots === 2) { if (res.length < 2 || lastSegmentLength !== 2 || - res.charCodeAt(res.length - 1) !== 46/*.*/ || - res.charCodeAt(res.length - 2) !== 46/*.*/) { + res.charCodeAt(res.length - 1) !== CHAR_DOT || + res.charCodeAt(res.length - 2) !== CHAR_DOT) { if (res.length > 2) { const lastSlashIndex = res.lastIndexOf('\\'); if (lastSlashIndex !== res.length - 1) { @@ -88,7 +99,7 @@ function normalizeStringWin32(path, allowAboveRoot) { } lastSlash = i; dots = 0; - } else if (code === 46/*.*/ && dots !== -1) { + } else if (code === CHAR_DOT && dots !== -1) { ++dots; } else { dots = -1; @@ -107,17 +118,17 @@ function normalizeStringPosix(path, allowAboveRoot) { for (var i = 0; i <= path.length; ++i) { if (i < path.length) code = path.charCodeAt(i); - else if (code === 47/*/*/) + else if (code === CHAR_FORWARD_SLASH) break; else - code = 47/*/*/; - if (code === 47/*/*/) { + code = CHAR_FORWARD_SLASH; + if (code === CHAR_FORWARD_SLASH) { if (lastSlash === i - 1 || dots === 1) { // NOOP } else if (lastSlash !== i - 1 && dots === 2) { if (res.length < 2 || lastSegmentLength !== 2 || - res.charCodeAt(res.length - 1) !== 46/*.*/ || - res.charCodeAt(res.length - 2) !== 46/*.*/) { + res.charCodeAt(res.length - 1) !== CHAR_DOT || + res.charCodeAt(res.length - 2) !== CHAR_DOT) { if (res.length > 2) { const lastSlashIndex = res.lastIndexOf('/'); if (lastSlashIndex !== res.length - 1) { @@ -156,7 +167,7 @@ function normalizeStringPosix(path, allowAboveRoot) { } lastSlash = i; dots = 0; - } else if (code === 46/*.*/ && dots !== -1) { + } else if (code === CHAR_DOT && dots !== -1) { ++dots; } else { dots = -1; @@ -223,7 +234,7 @@ const win32 = { // Try to match a root if (len > 1) { - if (code === 47/*/*/ || code === 92/*\*/) { + if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) { // Possible UNC root // If we started with a separator, we know we at least have an @@ -231,14 +242,14 @@ const win32 = { isAbsolute = true; code = path.charCodeAt(1); - if (code === 47/*/*/ || code === 92/*\*/) { + if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) { // Matched double path separator at beginning var j = 2; var last = j; // Match 1 or more non-path separators for (; j < len; ++j) { code = path.charCodeAt(j); - if (code === 47/*/*/ || code === 92/*\*/) + if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) break; } if (j < len && j !== last) { @@ -248,7 +259,7 @@ const win32 = { // Match 1 or more path separators for (; j < len; ++j) { code = path.charCodeAt(j); - if (code !== 47/*/*/ && code !== 92/*\*/) + if (code !== CHAR_FORWARD_SLASH && code !== CHAR_BACKWARD_SLASH) break; } if (j < len && j !== last) { @@ -257,7 +268,10 @@ const win32 = { // Match 1 or more non-path separators for (; j < len; ++j) { code = path.charCodeAt(j); - if (code === 47/*/*/ || code === 92/*\*/) + const isPathSeparator = + code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH; + + if (isPathSeparator) break; } if (j === len) { @@ -276,16 +290,16 @@ const win32 = { } else { rootEnd = 1; } - } else if ((code >= 65/*A*/ && code <= 90/*Z*/) || - (code >= 97/*a*/ && code <= 122/*z*/)) { + } else if ((code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z) || + (code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z)) { // Possible device root - if (path.charCodeAt(1) === 58/*:*/) { + if (path.charCodeAt(1) === CHAR_COLON) { device = path.slice(0, 2); rootEnd = 2; if (len > 2) { code = path.charCodeAt(2); - if (code === 47/*/*/ || code === 92/*\*/) { + if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) { // Treat separator following drive name as an absolute path // indicator isAbsolute = true; @@ -294,7 +308,7 @@ const win32 = { } } } - } else if (code === 47/*/*/ || code === 92/*\*/) { + } else if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) { // `path` contains just a path separator rootEnd = 1; isAbsolute = true; @@ -343,7 +357,7 @@ const win32 = { // Try to match a root if (len > 1) { - if (code === 47/*/*/ || code === 92/*\*/) { + if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) { // Possible UNC root // If we started with a separator, we know we at least have an absolute @@ -351,14 +365,14 @@ const win32 = { isAbsolute = true; code = path.charCodeAt(1); - if (code === 47/*/*/ || code === 92/*\*/) { + if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) { // Matched double path separator at beginning var j = 2; var last = j; // Match 1 or more non-path separators for (; j < len; ++j) { code = path.charCodeAt(j); - if (code === 47/*/*/ || code === 92/*\*/) + if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) break; } if (j < len && j !== last) { @@ -368,7 +382,7 @@ const win32 = { // Match 1 or more path separators for (; j < len; ++j) { code = path.charCodeAt(j); - if (code !== 47/*/*/ && code !== 92/*\*/) + if (code !== CHAR_FORWARD_SLASH && code !== CHAR_BACKWARD_SLASH) break; } if (j < len && j !== last) { @@ -377,7 +391,7 @@ const win32 = { // Match 1 or more non-path separators for (; j < len; ++j) { code = path.charCodeAt(j); - if (code === 47/*/*/ || code === 92/*\*/) + if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) break; } if (j === len) { @@ -397,16 +411,16 @@ const win32 = { } else { rootEnd = 1; } - } else if ((code >= 65/*A*/ && code <= 90/*Z*/) || - (code >= 97/*a*/ && code <= 122/*z*/)) { + } else if ((code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z) || + (code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z)) { // Possible device root - if (path.charCodeAt(1) === 58/*:*/) { + if (path.charCodeAt(1) === CHAR_COLON) { device = path.slice(0, 2); rootEnd = 2; if (len > 2) { code = path.charCodeAt(2); - if (code === 47/*/*/ || code === 92/*\*/) { + if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) { // Treat separator following drive name as an absolute path // indicator isAbsolute = true; @@ -415,14 +429,15 @@ const win32 = { } } } - } else if (code === 47/*/*/ || code === 92/*\*/) { + } else if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) { // `path` contains just a path separator, exit early to avoid unnecessary // work return '\\'; } code = path.charCodeAt(len - 1); - var trailingSeparator = (code === 47/*/*/ || code === 92/*\*/); + var trailingSeparator = + (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH); var tail; if (rootEnd < len) tail = normalizeStringWin32(path.slice(rootEnd), !isAbsolute); @@ -462,15 +477,15 @@ const win32 = { if (len === 0) return false; var code = path.charCodeAt(0); - if (code === 47/*/*/ || code === 92/*\*/) { + if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) { return true; - } else if ((code >= 65/*A*/ && code <= 90/*Z*/) || - (code >= 97/*a*/ && code <= 122/*z*/)) { + } else if ((code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z) || + (code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z)) { // Possible device root - if (len > 2 && path.charCodeAt(1) === 58/*:*/) { + if (len > 2 && path.charCodeAt(1) === CHAR_COLON) { code = path.charCodeAt(2); - if (code === 47/*/*/ || code === 92/*\*/) + if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) return true; } } @@ -514,16 +529,16 @@ const win32 = { var needsReplace = true; var slashCount = 0; var code = firstPart.charCodeAt(0); - if (code === 47/*/*/ || code === 92/*\*/) { + if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) { ++slashCount; const firstLen = firstPart.length; if (firstLen > 1) { code = firstPart.charCodeAt(1); - if (code === 47/*/*/ || code === 92/*\*/) { + if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) { ++slashCount; if (firstLen > 2) { code = firstPart.charCodeAt(2); - if (code === 47/*/*/ || code === 92/*\*/) + if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) ++slashCount; else { // We matched a UNC path in the first part @@ -537,7 +552,7 @@ const win32 = { // Find any more consecutive slashes we need to replace for (; slashCount < joined.length; ++slashCount) { code = joined.charCodeAt(slashCount); - if (code !== 47/*/*/ && code !== 92/*\*/) + if (code !== CHAR_FORWARD_SLASH && code !== CHAR_BACKWARD_SLASH) break; } @@ -576,13 +591,13 @@ const win32 = { // Trim any leading backslashes var fromStart = 0; for (; fromStart < from.length; ++fromStart) { - if (from.charCodeAt(fromStart) !== 92/*\*/) + if (from.charCodeAt(fromStart) !== CHAR_BACKWARD_SLASH) break; } // Trim trailing backslashes (applicable to UNC paths only) var fromEnd = from.length; for (; fromEnd - 1 > fromStart; --fromEnd) { - if (from.charCodeAt(fromEnd - 1) !== 92/*\*/) + if (from.charCodeAt(fromEnd - 1) !== CHAR_BACKWARD_SLASH) break; } var fromLen = (fromEnd - fromStart); @@ -590,13 +605,13 @@ const win32 = { // Trim any leading backslashes var toStart = 0; for (; toStart < to.length; ++toStart) { - if (to.charCodeAt(toStart) !== 92/*\*/) + if (to.charCodeAt(toStart) !== CHAR_BACKWARD_SLASH) break; } // Trim trailing backslashes (applicable to UNC paths only) var toEnd = to.length; for (; toEnd - 1 > toStart; --toEnd) { - if (to.charCodeAt(toEnd - 1) !== 92/*\*/) + if (to.charCodeAt(toEnd - 1) !== CHAR_BACKWARD_SLASH) break; } var toLen = (toEnd - toStart); @@ -608,7 +623,7 @@ const win32 = { for (; i <= length; ++i) { if (i === length) { if (toLen > length) { - if (to.charCodeAt(toStart + i) === 92/*\*/) { + if (to.charCodeAt(toStart + i) === CHAR_BACKWARD_SLASH) { // We get here if `from` is the exact base path for `to`. // For example: from='C:\\foo\\bar'; to='C:\\foo\\bar\\baz' return toOrig.slice(toStart + i + 1); @@ -619,7 +634,7 @@ const win32 = { } } if (fromLen > length) { - if (from.charCodeAt(fromStart + i) === 92/*\*/) { + if (from.charCodeAt(fromStart + i) === CHAR_BACKWARD_SLASH) { // We get here if `to` is the exact base path for `from`. // For example: from='C:\\foo\\bar'; to='C:\\foo' lastCommonSep = i; @@ -635,7 +650,7 @@ const win32 = { var toCode = to.charCodeAt(toStart + i); if (fromCode !== toCode) break; - else if (fromCode === 92/*\*/) + else if (fromCode === CHAR_BACKWARD_SLASH) lastCommonSep = i; } @@ -651,7 +666,7 @@ const win32 = { // Generate the relative path based on the path difference between `to` and // `from` for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) { - if (i === fromEnd || from.charCodeAt(i) === 92/*\*/) { + if (i === fromEnd || from.charCodeAt(i) === CHAR_BACKWARD_SLASH) { if (out.length === 0) out += '..'; else @@ -665,7 +680,7 @@ const win32 = { return out + toOrig.slice(toStart + lastCommonSep, toEnd); else { toStart += lastCommonSep; - if (toOrig.charCodeAt(toStart) === 92/*\*/) + if (toOrig.charCodeAt(toStart) === CHAR_BACKWARD_SLASH) ++toStart; return toOrig.slice(toStart, toEnd); } @@ -685,22 +700,22 @@ const win32 = { if (resolvedPath.length >= 3) { var code = resolvedPath.charCodeAt(0); - if (code === 92/*\*/) { + if (code === CHAR_BACKWARD_SLASH) { // Possible UNC root - if (resolvedPath.charCodeAt(1) === 92/*\*/) { + if (resolvedPath.charCodeAt(1) === CHAR_BACKWARD_SLASH) { code = resolvedPath.charCodeAt(2); - if (code !== 63/*?*/ && code !== 46/*.*/) { + if (code !== CHAR_QUESTION_MARK && code !== CHAR_DOT) { // Matched non-long UNC root, convert the path to a long UNC path return '\\\\?\\UNC\\' + resolvedPath.slice(2); } } - } else if ((code >= 65/*A*/ && code <= 90/*Z*/) || - (code >= 97/*a*/ && code <= 122/*z*/)) { + } else if ((code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z) || + (code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z)) { // Possible device root - if (resolvedPath.charCodeAt(1) === 58/*:*/ && - resolvedPath.charCodeAt(2) === 92/*\*/) { + if (resolvedPath.charCodeAt(1) === CHAR_COLON && + resolvedPath.charCodeAt(2) === CHAR_BACKWARD_SLASH) { // Matched device root, convert the path to a long UNC path return '\\\\?\\' + resolvedPath; } @@ -723,20 +738,20 @@ const win32 = { // Try to match a root if (len > 1) { - if (code === 47/*/*/ || code === 92/*\*/) { + if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) { // Possible UNC root rootEnd = offset = 1; code = path.charCodeAt(1); - if (code === 47/*/*/ || code === 92/*\*/) { + if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) { // Matched double path separator at beginning var j = 2; var last = j; // Match 1 or more non-path separators for (; j < len; ++j) { code = path.charCodeAt(j); - if (code === 47/*/*/ || code === 92/*\*/) + if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) break; } if (j < len && j !== last) { @@ -745,7 +760,7 @@ const win32 = { // Match 1 or more path separators for (; j < len; ++j) { code = path.charCodeAt(j); - if (code !== 47/*/*/ && code !== 92/*\*/) + if (code !== CHAR_FORWARD_SLASH && code !== CHAR_BACKWARD_SLASH) break; } if (j < len && j !== last) { @@ -754,7 +769,7 @@ const win32 = { // Match 1 or more non-path separators for (; j < len; ++j) { code = path.charCodeAt(j); - if (code === 47/*/*/ || code === 92/*\*/) + if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) break; } if (j === len) { @@ -771,20 +786,20 @@ const win32 = { } } } - } else if ((code >= 65/*A*/ && code <= 90/*Z*/) || - (code >= 97/*a*/ && code <= 122/*z*/)) { + } else if ((code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z) || + (code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z)) { // Possible device root - if (path.charCodeAt(1) === 58/*:*/) { + if (path.charCodeAt(1) === CHAR_COLON) { rootEnd = offset = 2; if (len > 2) { code = path.charCodeAt(2); - if (code === 47/*/*/ || code === 92/*\*/) + if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) rootEnd = offset = 3; } } } - } else if (code === 47/*/*/ || code === 92/*\*/) { + } else if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) { // `path` contains just a path separator, exit early to avoid // unnecessary work return path; @@ -792,7 +807,7 @@ const win32 = { for (var i = len - 1; i >= offset; --i) { code = path.charCodeAt(i); - if (code === 47/*/*/ || code === 92/*\*/) { + if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) { if (!matchedSlash) { end = i; break; @@ -827,9 +842,9 @@ const win32 = { // disregarded if (path.length >= 2) { const drive = path.charCodeAt(0); - if ((drive >= 65/*A*/ && drive <= 90/*Z*/) || - (drive >= 97/*a*/ && drive <= 122/*z*/)) { - if (path.charCodeAt(1) === 58/*:*/) + if ((drive >= CHAR_UPPERCASE_A && drive <= CHAR_UPPERCASE_Z) || + (drive >= CHAR_LOWERCASE_A && drive <= CHAR_LOWERCASE_Z)) { + if (path.charCodeAt(1) === CHAR_COLON) start = 2; } } @@ -841,7 +856,7 @@ const win32 = { var firstNonSlashEnd = -1; for (i = path.length - 1; i >= start; --i) { const code = path.charCodeAt(i); - if (code === 47/*/*/ || code === 92/*\*/) { + if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) { // If we reached a path separator that was not part of a set of path // separators at the end of the string, stop now if (!matchedSlash) { @@ -881,7 +896,7 @@ const win32 = { } else { for (i = path.length - 1; i >= start; --i) { const code = path.charCodeAt(i); - if (code === 47/*/*/ || code === 92/*\*/) { + if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) { // If we reached a path separator that was not part of a set of path // separators at the end of the string, stop now if (!matchedSlash) { @@ -919,16 +934,16 @@ const win32 = { // disregarded if (path.length >= 2) { const code = path.charCodeAt(0); - if (path.charCodeAt(1) === 58/*:*/ && - ((code >= 65/*A*/ && code <= 90/*Z*/) || - (code >= 97/*a*/ && code <= 122/*z*/))) { + if (path.charCodeAt(1) === CHAR_COLON && + ((code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z) || + (code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z))) { start = startPart = 2; } } for (var i = path.length - 1; i >= start; --i) { const code = path.charCodeAt(i); - if (code === 47/*/*/ || code === 92/*\*/) { + if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) { // If we reached a path separator that was not part of a set of path // separators at the end of the string, stop now if (!matchedSlash) { @@ -943,7 +958,7 @@ const win32 = { matchedSlash = false; end = i + 1; } - if (code === 46/*.*/) { + if (code === CHAR_DOT) { // If this is our first dot, mark it as the start of our extension if (startDot === -1) startDot = i; @@ -992,19 +1007,19 @@ const win32 = { // Try to match a root if (len > 1) { - if (code === 47/*/*/ || code === 92/*\*/) { + if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) { // Possible UNC root code = path.charCodeAt(1); rootEnd = 1; - if (code === 47/*/*/ || code === 92/*\*/) { + if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) { // Matched double path separator at beginning var j = 2; var last = j; // Match 1 or more non-path separators for (; j < len; ++j) { code = path.charCodeAt(j); - if (code === 47/*/*/ || code === 92/*\*/) + if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) break; } if (j < len && j !== last) { @@ -1013,7 +1028,7 @@ const win32 = { // Match 1 or more path separators for (; j < len; ++j) { code = path.charCodeAt(j); - if (code !== 47/*/*/ && code !== 92/*\*/) + if (code !== CHAR_FORWARD_SLASH && code !== CHAR_BACKWARD_SLASH) break; } if (j < len && j !== last) { @@ -1022,7 +1037,7 @@ const win32 = { // Match 1 or more non-path separators for (; j < len; ++j) { code = path.charCodeAt(j); - if (code === 47/*/*/ || code === 92/*\*/) + if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) break; } if (j === len) { @@ -1037,15 +1052,15 @@ const win32 = { } } } - } else if ((code >= 65/*A*/ && code <= 90/*Z*/) || - (code >= 97/*a*/ && code <= 122/*z*/)) { + } else if ((code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z) || + (code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z)) { // Possible device root - if (path.charCodeAt(1) === 58/*:*/) { + if (path.charCodeAt(1) === CHAR_COLON) { rootEnd = 2; if (len > 2) { code = path.charCodeAt(2); - if (code === 47/*/*/ || code === 92/*\*/) { + if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) { if (len === 3) { // `path` contains just a drive root, exit early to avoid // unnecessary work @@ -1062,7 +1077,7 @@ const win32 = { } } } - } else if (code === 47/*/*/ || code === 92/*\*/) { + } else if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) { // `path` contains just a path separator, exit early to avoid // unnecessary work ret.root = ret.dir = path; @@ -1085,7 +1100,7 @@ const win32 = { // Get non-dir info for (; i >= rootEnd; --i) { code = path.charCodeAt(i); - if (code === 47/*/*/ || code === 92/*\*/) { + if (code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH) { // If we reached a path separator that was not part of a set of path // separators at the end of the string, stop now if (!matchedSlash) { @@ -1100,7 +1115,7 @@ const win32 = { matchedSlash = false; end = i + 1; } - if (code === 46/*.*/) { + if (code === CHAR_DOT) { // If this is our first dot, mark it as the start of our extension if (startDot === -1) startDot = i; @@ -1174,7 +1189,7 @@ const posix = { } resolvedPath = path + '/' + resolvedPath; - resolvedAbsolute = path.charCodeAt(0) === 47/*/*/; + resolvedAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH; } // At this point the path should be resolved to a full absolute path, but @@ -1202,8 +1217,9 @@ const posix = { if (path.length === 0) return '.'; - const isAbsolute = path.charCodeAt(0) === 47/*/*/; - const trailingSeparator = path.charCodeAt(path.length - 1) === 47/*/*/; + const isAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH; + const trailingSeparator = + path.charCodeAt(path.length - 1) === CHAR_FORWARD_SLASH; // Normalize the path path = normalizeStringPosix(path, !isAbsolute); @@ -1221,7 +1237,7 @@ const posix = { isAbsolute: function isAbsolute(path) { assertPath(path); - return path.length > 0 && path.charCodeAt(0) === 47/*/*/; + return path.length > 0 && path.charCodeAt(0) === CHAR_FORWARD_SLASH; }, @@ -1261,7 +1277,7 @@ const posix = { // Trim any leading backslashes var fromStart = 1; for (; fromStart < from.length; ++fromStart) { - if (from.charCodeAt(fromStart) !== 47/*/*/) + if (from.charCodeAt(fromStart) !== CHAR_FORWARD_SLASH) break; } var fromEnd = from.length; @@ -1270,7 +1286,7 @@ const posix = { // Trim any leading backslashes var toStart = 1; for (; toStart < to.length; ++toStart) { - if (to.charCodeAt(toStart) !== 47/*/*/) + if (to.charCodeAt(toStart) !== CHAR_FORWARD_SLASH) break; } var toEnd = to.length; @@ -1283,7 +1299,7 @@ const posix = { for (; i <= length; ++i) { if (i === length) { if (toLen > length) { - if (to.charCodeAt(toStart + i) === 47/*/*/) { + if (to.charCodeAt(toStart + i) === CHAR_FORWARD_SLASH) { // We get here if `from` is the exact base path for `to`. // For example: from='/foo/bar'; to='/foo/bar/baz' return to.slice(toStart + i + 1); @@ -1293,7 +1309,7 @@ const posix = { return to.slice(toStart + i); } } else if (fromLen > length) { - if (from.charCodeAt(fromStart + i) === 47/*/*/) { + if (from.charCodeAt(fromStart + i) === CHAR_FORWARD_SLASH) { // We get here if `to` is the exact base path for `from`. // For example: from='/foo/bar/baz'; to='/foo/bar' lastCommonSep = i; @@ -1309,7 +1325,7 @@ const posix = { var toCode = to.charCodeAt(toStart + i); if (fromCode !== toCode) break; - else if (fromCode === 47/*/*/) + else if (fromCode === CHAR_FORWARD_SLASH) lastCommonSep = i; } @@ -1317,7 +1333,7 @@ const posix = { // Generate the relative path based on the path difference between `to` // and `from` for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) { - if (i === fromEnd || from.charCodeAt(i) === 47/*/*/) { + if (i === fromEnd || from.charCodeAt(i) === CHAR_FORWARD_SLASH) { if (out.length === 0) out += '..'; else @@ -1331,7 +1347,7 @@ const posix = { return out + to.slice(toStart + lastCommonSep); else { toStart += lastCommonSep; - if (to.charCodeAt(toStart) === 47/*/*/) + if (to.charCodeAt(toStart) === CHAR_FORWARD_SLASH) ++toStart; return to.slice(toStart); } @@ -1348,12 +1364,12 @@ const posix = { if (path.length === 0) return '.'; var code = path.charCodeAt(0); - var hasRoot = (code === 47/*/*/); + var hasRoot = (code === CHAR_FORWARD_SLASH); var end = -1; var matchedSlash = true; for (var i = path.length - 1; i >= 1; --i) { code = path.charCodeAt(i); - if (code === 47/*/*/) { + if (code === CHAR_FORWARD_SLASH) { if (!matchedSlash) { end = i; break; @@ -1389,7 +1405,7 @@ const posix = { var firstNonSlashEnd = -1; for (i = path.length - 1; i >= 0; --i) { const code = path.charCodeAt(i); - if (code === 47/*/*/) { + if (code === CHAR_FORWARD_SLASH) { // If we reached a path separator that was not part of a set of path // separators at the end of the string, stop now if (!matchedSlash) { @@ -1428,7 +1444,7 @@ const posix = { return path.slice(start, end); } else { for (i = path.length - 1; i >= 0; --i) { - if (path.charCodeAt(i) === 47/*/*/) { + if (path.charCodeAt(i) === CHAR_FORWARD_SLASH) { // If we reached a path separator that was not part of a set of path // separators at the end of the string, stop now if (!matchedSlash) { @@ -1461,7 +1477,7 @@ const posix = { var preDotState = 0; for (var i = path.length - 1; i >= 0; --i) { const code = path.charCodeAt(i); - if (code === 47/*/*/) { + if (code === CHAR_FORWARD_SLASH) { // If we reached a path separator that was not part of a set of path // separators at the end of the string, stop now if (!matchedSlash) { @@ -1476,7 +1492,7 @@ const posix = { matchedSlash = false; end = i + 1; } - if (code === 46/*.*/) { + if (code === CHAR_DOT) { // If this is our first dot, mark it as the start of our extension if (startDot === -1) startDot = i; @@ -1519,7 +1535,7 @@ const posix = { if (path.length === 0) return ret; var code = path.charCodeAt(0); - var isAbsolute = (code === 47/*/*/); + var isAbsolute = (code === CHAR_FORWARD_SLASH); var start; if (isAbsolute) { ret.root = '/'; @@ -1540,7 +1556,7 @@ const posix = { // Get non-dir info for (; i >= start; --i) { code = path.charCodeAt(i); - if (code === 47/*/*/) { + if (code === CHAR_FORWARD_SLASH) { // If we reached a path separator that was not part of a set of path // separators at the end of the string, stop now if (!matchedSlash) { @@ -1555,7 +1571,7 @@ const posix = { matchedSlash = false; end = i + 1; } - if (code === 46/*.*/) { + if (code === CHAR_DOT) { // If this is our first dot, mark it as the start of our extension if (startDot === -1) startDot = i; diff --git a/lib/string_decoder.js b/lib/string_decoder.js index d955a663307..04d31b2607c 100644 --- a/lib/string_decoder.js +++ b/lib/string_decoder.js @@ -56,47 +56,61 @@ for (var i = 0; i < encodings.length; ++i) // StringDecoder provides an interface for efficiently splitting a series of // buffers into a series of JS strings without breaking apart multi-byte // characters. -class StringDecoder { - constructor(encoding) { - this.encoding = normalizeEncoding(encoding); - this[kNativeDecoder] = Buffer.alloc(kSize); - this[kNativeDecoder][kEncodingField] = encodingsMap[this.encoding]; - } - - write(buf) { - if (typeof buf === 'string') - return buf; - if (!ArrayBuffer.isView(buf)) - throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'buf', - ['Buffer', 'Uint8Array', 'ArrayBufferView']); - return decode(this[kNativeDecoder], buf); - } - - end(buf) { - let ret = ''; - if (buf !== undefined) - ret = this.write(buf); - if (this[kNativeDecoder][kBufferedBytes] > 0) - ret += flush(this[kNativeDecoder]); - return ret; - } +function StringDecoder(encoding) { + this.encoding = normalizeEncoding(encoding); + this[kNativeDecoder] = Buffer.alloc(kSize); + this[kNativeDecoder][kEncodingField] = encodingsMap[this.encoding]; +} - /* Everything below this line is undocumented legacy stuff. */ +StringDecoder.prototype.write = function write(buf) { + if (typeof buf === 'string') + return buf; + if (!ArrayBuffer.isView(buf)) + throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'buf', + ['Buffer', 'Uint8Array', 'ArrayBufferView']); + return decode(this[kNativeDecoder], buf); +}; - text(buf, offset) { - this[kNativeDecoder][kMissingBytes] = 0; - this[kNativeDecoder][kBufferedBytes] = 0; - return this.write(buf.slice(offset)); - } +StringDecoder.prototype.end = function end(buf) { + let ret = ''; + if (buf !== undefined) + ret = this.write(buf); + if (this[kNativeDecoder][kBufferedBytes] > 0) + ret += flush(this[kNativeDecoder]); + return ret; +}; - get lastTotal() { - return this[kNativeDecoder][kBufferedBytes] + this.lastNeed; - } +/* Everything below this line is undocumented legacy stuff. */ +StringDecoder.prototype.text = function text(buf, offset) { + this[kNativeDecoder][kMissingBytes] = 0; + this[kNativeDecoder][kBufferedBytes] = 0; + return this.write(buf.slice(offset)); +}; - get lastChar() { - return this[kNativeDecoder].subarray(kIncompleteCharactersStart, - kIncompleteCharactersEnd); +Object.defineProperties(StringDecoder.prototype, { + lastChar: { + configurable: true, + enumerable: true, + get() { + return this[kNativeDecoder].subarray(kIncompleteCharactersStart, + kIncompleteCharactersEnd); + } + }, + lastNeed: { + configurable: true, + enumerable: true, + get() { + return this[kNativeDecoder][kMissingBytes]; + } + }, + lastTotal: { + configurable: true, + enumerable: true, + get() { + return this[kNativeDecoder][kBufferedBytes] + + this[kNativeDecoder][kMissingBytes]; + } } -} +}); exports.StringDecoder = StringDecoder; diff --git a/node.gyp b/node.gyp index 70ed4df7637..0e981e8b401 100644 --- a/node.gyp +++ b/node.gyp @@ -97,6 +97,7 @@ 'lib/internal/crypto/random.js', 'lib/internal/crypto/sig.js', 'lib/internal/crypto/util.js', + 'lib/internal/constants.js', 'lib/internal/encoding.js', 'lib/internal/errors.js', 'lib/internal/freelist.js', diff --git a/test/parallel/test-string-decoder.js b/test/parallel/test-string-decoder.js index 21a0b6c3e38..0e7ea8ffdd5 100644 --- a/test/parallel/test-string-decoder.js +++ b/test/parallel/test-string-decoder.js @@ -29,6 +29,11 @@ const StringDecoder = require('string_decoder').StringDecoder; let decoder = new StringDecoder(); assert.strictEqual(decoder.encoding, 'utf8'); +// Should work without 'new' keyword +const decoder2 = {}; +StringDecoder.call(decoder2); +assert.strictEqual(decoder2.encoding, 'utf8'); + // UTF-8 test('utf-8', Buffer.from('$', 'utf-8'), '$'); test('utf-8', Buffer.from('¢', 'utf-8'), '¢'); @@ -84,6 +89,11 @@ test('utf16le', Buffer.from('3DD84DDC', 'hex'), '\ud83d\udc4d'); // thumbs up // Additional UTF-8 tests decoder = new StringDecoder('utf8'); assert.strictEqual(decoder.write(Buffer.from('E1', 'hex')), ''); + +// A quick test for lastNeed & lastTotal which are undocumented. +assert.strictEqual(decoder.lastNeed, 2); +assert.strictEqual(decoder.lastTotal, 3); + assert.strictEqual(decoder.end(), '\ufffd'); decoder = new StringDecoder('utf8');