diff --git a/benchmark/url/usvstring.js b/benchmark/url/usvstring.js deleted file mode 100644 index 93a50846fb999f..00000000000000 --- a/benchmark/url/usvstring.js +++ /dev/null @@ -1,27 +0,0 @@ -'use strict'; -const common = require('../common.js'); - -const inputs = { - valid: 'adsfadsfadsf', - validsurr: '\uda23\ude23\uda1f\udfaa\ud800\udfff\uda23\ude23\uda1f\udfaa' + - '\ud800\udfff', - someinvalid: 'asasfdfasd\uda23', - allinvalid: '\udc45\uda23 \udf00\udc00 \udfaa\uda12 \udc00\udfaa', - nonstring: { toString() { return 'asdf'; } }, -}; -const bench = common.createBenchmark(main, { - input: Object.keys(inputs), - n: [5e7], -}, { - flags: ['--expose-internals'], -}); - -function main({ input, n }) { - const { toUSVString } = require('internal/url'); - const str = inputs[input]; - - bench.start(); - for (let i = 0; i < n; i++) - toUSVString(str); - bench.end(n); -} diff --git a/benchmark/util/to-usv-string.js b/benchmark/util/to-usv-string.js deleted file mode 100644 index 22d23d3198d124..00000000000000 --- a/benchmark/util/to-usv-string.js +++ /dev/null @@ -1,21 +0,0 @@ -'use strict'; - -const common = require('../common'); - -const BASE = 'string\ud801'; - -const bench = common.createBenchmark(main, { - n: [1e5], - size: [10, 100, 500], -}); - -function main({ n, size }) { - const { toUSVString } = require('util'); - const str = BASE.repeat(size); - - bench.start(); - for (let i = 0; i < n; i++) { - toUSVString(str); - } - bench.end(n); -} diff --git a/lib/internal/file.js b/lib/internal/file.js index 1fc08c45a90f33..e35eb7bf70931f 100644 --- a/lib/internal/file.js +++ b/lib/internal/file.js @@ -4,6 +4,7 @@ const { DateNow, NumberIsNaN, ObjectDefineProperties, + StringPrototypeToWellFormed, SymbolToStringTag, } = primordials; @@ -15,7 +16,6 @@ const { customInspectSymbol: kInspect, kEnumerableProperty, kEmptyObject, - toUSVString, } = require('internal/util'); const { @@ -55,7 +55,7 @@ class File extends Blob { lastModified = DateNow(); } - this.#name = toUSVString(fileName); + this.#name = StringPrototypeToWellFormed(`${fileName}`); this.#lastModified = lastModified; } diff --git a/lib/internal/url.js b/lib/internal/url.js index a58f96aee7cc42..0bd7e44155973b 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -26,6 +26,7 @@ const { StringPrototypeIndexOf, StringPrototypeSlice, StringPrototypeStartsWith, + StringPrototypeToWellFormed, Symbol, SymbolIterator, SymbolToStringTag, @@ -42,7 +43,6 @@ const { const { getConstructorOf, removeColors, - toUSVString, kEnumerableProperty, SideEffectFreeRegExpPrototypeSymbolReplace, } = require('internal/util'); @@ -360,7 +360,11 @@ class URLSearchParams { throw new ERR_INVALID_TUPLE('Each query pair', '[name, value]'); } // Append (innerSequence[0], innerSequence[1]) to querys list. - ArrayPrototypePush(this.#searchParams, toUSVString(pair[0]), toUSVString(pair[1])); + ArrayPrototypePush( + this.#searchParams, + StringPrototypeToWellFormed(`${pair[0]}`), + StringPrototypeToWellFormed(`${pair[1]}`), + ); } else { if (((typeof pair !== 'object' && typeof pair !== 'function') || typeof pair[SymbolIterator] !== 'function')) { @@ -371,7 +375,7 @@ class URLSearchParams { for (const element of pair) { length++; - ArrayPrototypePush(this.#searchParams, toUSVString(element)); + ArrayPrototypePush(this.#searchParams, StringPrototypeToWellFormed(`${element}`)); } // If innerSequence's size is not 2, then throw a TypeError. @@ -389,8 +393,8 @@ class URLSearchParams { const key = keys[i]; const desc = ReflectGetOwnPropertyDescriptor(init, key); if (desc !== undefined && desc.enumerable) { - const typedKey = toUSVString(key); - const typedValue = toUSVString(init[key]); + const typedKey = StringPrototypeToWellFormed(key); + const typedValue = StringPrototypeToWellFormed(`${init[key]}`); // Two different keys may become the same USVString after normalization. // In that case, we retain the later one. Refer to WPT. @@ -407,7 +411,7 @@ class URLSearchParams { } } else { // https://url.spec.whatwg.org/#dom-urlsearchparams-urlsearchparams - init = toUSVString(init); + init = StringPrototypeToWellFormed(`${init}`); this.#searchParams = init ? parseParams(init) : []; } } @@ -462,8 +466,8 @@ class URLSearchParams { throw new ERR_MISSING_ARGS('name', 'value'); } - name = toUSVString(name); - value = toUSVString(value); + name = StringPrototypeToWellFormed(`${name}`); + value = StringPrototypeToWellFormed(`${value}`); ArrayPrototypePush(this.#searchParams, name, value); if (this.#context) { this.#context.search = this.toString(); @@ -479,10 +483,10 @@ class URLSearchParams { } const list = this.#searchParams; - name = toUSVString(name); + name = StringPrototypeToWellFormed(`${name}`); if (value !== undefined) { - value = toUSVString(value); + value = StringPrototypeToWellFormed(`${value}`); for (let i = 0; i < list.length;) { if (list[i] === name && list[i + 1] === value) { list.splice(i, 2); @@ -513,7 +517,7 @@ class URLSearchParams { } const list = this.#searchParams; - name = toUSVString(name); + name = StringPrototypeToWellFormed(`${name}`); for (let i = 0; i < list.length; i += 2) { if (list[i] === name) { return list[i + 1]; @@ -532,7 +536,7 @@ class URLSearchParams { const list = this.#searchParams; const values = []; - name = toUSVString(name); + name = StringPrototypeToWellFormed(`${name}`); for (let i = 0; i < list.length; i += 2) { if (list[i] === name) { values.push(list[i + 1]); @@ -550,10 +554,10 @@ class URLSearchParams { } const list = this.#searchParams; - name = toUSVString(name); + name = StringPrototypeToWellFormed(`${name}`); if (value !== undefined) { - value = toUSVString(value); + value = StringPrototypeToWellFormed(`${value}`); } for (let i = 0; i < list.length; i += 2) { @@ -576,8 +580,8 @@ class URLSearchParams { } const list = this.#searchParams; - name = toUSVString(name); - value = toUSVString(value); + name = StringPrototypeToWellFormed(`${name}`); + value = StringPrototypeToWellFormed(`${value}`); // If there are any name-value pairs whose name is `name`, in `list`, set // the value of the first such name-value pair to `value` and remove the @@ -765,7 +769,7 @@ class URL { throw new ERR_MISSING_ARGS('url'); } - // toUSVString is not needed. + // StringPrototypeToWellFormed is not needed. input = `${input}`; if (base !== undefined) { @@ -998,7 +1002,7 @@ class URL { } set search(value) { - const href = bindingUrl.update(this.#context.href, updateActions.kSearch, toUSVString(value)); + const href = bindingUrl.update(this.#context.href, updateActions.kSearch, StringPrototypeToWellFormed(`${value}`)); if (href) { this.#updateContext(href); } @@ -1289,7 +1293,7 @@ function domainToASCII(domain) { if (arguments.length < 1) throw new ERR_MISSING_ARGS('domain'); - // toUSVString is not needed. + // StringPrototypeToWellFormed is not needed. return bindingUrl.domainToASCII(`${domain}`); } @@ -1297,7 +1301,7 @@ function domainToUnicode(domain) { if (arguments.length < 1) throw new ERR_MISSING_ARGS('domain'); - // toUSVString is not needed. + // StringPrototypeToWellFormed is not needed. return bindingUrl.domainToUnicode(`${domain}`); } @@ -1493,7 +1497,6 @@ function getURLOrigin(url) { } module.exports = { - toUSVString, fileURLToPath, pathToFileURL, toPathIfFileURL, diff --git a/lib/internal/util.js b/lib/internal/util.js index c37ef7df4f357e..93a7422d3f4fe1 100644 --- a/lib/internal/util.js +++ b/lib/internal/util.js @@ -62,7 +62,6 @@ const { decorated_private_symbol, }, sleep: _sleep, - toUSVString: _toUSVString, } = internalBinding('util'); const { isNativeError } = internalBinding('types'); const { getOptionValue } = require('internal/options'); @@ -73,18 +72,6 @@ const experimentalWarnings = new SafeSet(); const colorRegExp = /\u001b\[\d\d?m/g; // eslint-disable-line no-control-regex -const unpairedSurrogateRe = - /(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])/; -function toUSVString(val) { - const str = `${val}`; - // As of V8 5.5, `str.search()` (and `unpairedSurrogateRe[@@search]()`) are - // slower than `unpairedSurrogateRe.exec()`. - const match = RegExpPrototypeExec(unpairedSurrogateRe, str); - if (!match) - return str; - return _toUSVString(str, match.index); -} - let uvBinding; function lazyUv() { @@ -910,7 +897,6 @@ module.exports = { sleep, spliceOne, setupCoverageHooks, - toUSVString, removeColors, // Symbol used to customize promisify conversion diff --git a/lib/util.js b/lib/util.js index 9ddb332f866355..633807c6419b83 100644 --- a/lib/util.js +++ b/lib/util.js @@ -44,6 +44,7 @@ const { ObjectValues, ReflectApply, StringPrototypePadStart, + StringPrototypeToWellFormed, } = primordials; const { @@ -75,7 +76,6 @@ const { getSystemErrorMap, getSystemErrorName: internalErrorName, promisify, - toUSVString, defineLazyProperties, } = require('internal/util'); @@ -411,7 +411,9 @@ module.exports = { log, promisify, stripVTControlCharacters, - toUSVString, + toUSVString(input) { + return StringPrototypeToWellFormed(`${input}`); + }, get transferableAbortSignal() { return lazyAbortController().transferableAbortSignal; }, diff --git a/src/node_util.cc b/src/node_util.cc index 1f86e47a69aeac..fbb71396912bc2 100644 --- a/src/node_util.cc +++ b/src/node_util.cc @@ -37,9 +37,6 @@ using v8::String; using v8::Uint32; using v8::Value; -// Used in ToUSVString(). -constexpr char16_t kUnicodeReplacementCharacter = 0xFFFD; - // If a UTF-16 character is a low/trailing surrogate. CHAR_TEST(16, IsUnicodeTrail, (ch & 0xFC00) == 0xDC00) @@ -240,40 +237,6 @@ static uint32_t FastGuessHandleType(Local receiver, const uint32_t fd) { CFunction fast_guess_handle_type_(CFunction::Make(FastGuessHandleType)); -static void ToUSVString(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); - CHECK_GE(args.Length(), 2); - CHECK(args[0]->IsString()); - CHECK(args[1]->IsNumber()); - - TwoByteValue value(env->isolate(), args[0]); - - int64_t start = args[1]->IntegerValue(env->context()).FromJust(); - CHECK_GE(start, 0); - - for (size_t i = start; i < value.length(); i++) { - char16_t c = value[i]; - if (!IsUnicodeSurrogate(c)) { - continue; - } else if (IsUnicodeSurrogateTrail(c) || i == value.length() - 1) { - value[i] = kUnicodeReplacementCharacter; - } else { - char16_t d = value[i + 1]; - if (IsUnicodeTrail(d)) { - i++; - } else { - value[i] = kUnicodeReplacementCharacter; - } - } - } - - args.GetReturnValue().Set( - String::NewFromTwoByte(env->isolate(), - *value, - v8::NewStringType::kNormal, - value.length()).ToLocalChecked()); -} - void RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(GetPromiseDetails); registry->Register(GetProxyDetails); @@ -288,7 +251,6 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(GuessHandleType); registry->Register(FastGuessHandleType); registry->Register(fast_guess_handle_type_.GetTypeInfo()); - registry->Register(ToUSVString); } void Initialize(Local target, @@ -389,8 +351,6 @@ void Initialize(Local target, "guessHandleType", GuessHandleType, &fast_guess_handle_type_); - - SetMethodNoSideEffect(context, target, "toUSVString", ToUSVString); } } // namespace util diff --git a/typings/internalBinding/util.d.ts b/typings/internalBinding/util.d.ts index 1ac9d3a39bbb31..9034b892b26549 100644 --- a/typings/internalBinding/util.d.ts +++ b/typings/internalBinding/util.d.ts @@ -43,5 +43,4 @@ export interface UtilBinding { shouldAbortOnUncaughtToggle: [shouldAbort: 0 | 1]; WeakReference: typeof InternalUtilBinding.WeakReference; guessHandleType(fd: number): 'TCP' | 'TTY' | 'UDP' | 'FILE' | 'PIPE' | 'UNKNOWN'; - toUSVString(str: string, start: number): string; } diff --git a/typings/primordials.d.ts b/typings/primordials.d.ts index ffce093458f2b5..ce6ca86f3e633d 100644 --- a/typings/primordials.d.ts +++ b/typings/primordials.d.ts @@ -420,6 +420,7 @@ declare namespace primordials { export const StringPrototypeToLocaleUpperCase: UncurryThis export const StringPrototypeToLowerCase: UncurryThis export const StringPrototypeToUpperCase: UncurryThis + export const StringPrototypeToWellFormed: UncurryThis export const StringPrototypeValueOf: UncurryThis export const StringPrototypeReplaceAll: UncurryThis export import Symbol = globalThis.Symbol;