Skip to content

Commit

Permalink
util: expose toUSVString
Browse files Browse the repository at this point in the history
Expose toUSVString so it can be used by user libraries.

PR-URL: #39814
Refs: nodejs/undici#986
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
  • Loading branch information
ronag authored and targos committed Sep 4, 2021
1 parent abfd71b commit 8eb1135
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 16 deletions.
12 changes: 12 additions & 0 deletions doc/api/util.md
Original file line number Diff line number Diff line change
Expand Up @@ -2468,6 +2468,18 @@ const util = require('util');
util.log('Timestamped message.');
```


### `util.toUSVString(string)`
<!-- YAML
added: REPLACEME
-->

* `string` {string}

Returns the `string` after replacing any surrogate code points
(or equivalently, any unpaired surrogate code units) with the
Unicode "replacement character" U+FFFD.

[Common System Errors]: errors.md#errors_common_system_errors
[Custom inspection functions on objects]: #util_custom_inspection_functions_on_objects
[Custom promisified functions]: #util_custom_promisified_functions
Expand Down
21 changes: 6 additions & 15 deletions lib/internal/url.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ const {
ReflectApply,
ReflectGetOwnPropertyDescriptor,
ReflectOwnKeys,
RegExpPrototypeExec,
String,
StringPrototypeCharCodeAt,
StringPrototypeIncludes,
Expand All @@ -40,7 +39,12 @@ const {
isHexTable
} = require('internal/querystring');

const { getConstructorOf, removeColors } = require('internal/util');
const {
getConstructorOf,
removeColors,
toUSVString,
} = require('internal/util');

const {
ERR_ARG_NOT_ITERABLE,
ERR_INVALID_ARG_TYPE,
Expand Down Expand Up @@ -76,7 +80,6 @@ const {
domainToASCII: _domainToASCII,
domainToUnicode: _domainToUnicode,
encodeAuth,
toUSVString: _toUSVString,
parse,
setURLConstructor,
URL_FLAGS_CANNOT_BE_BASE,
Expand Down Expand Up @@ -110,18 +113,6 @@ const IteratorPrototype = ObjectGetPrototypeOf(
ObjectGetPrototypeOf([][SymbolIterator]())
);

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);
}

// Refs: https://html.spec.whatwg.org/multipage/browsers.html#concept-origin-opaque
const kOpaqueOrigin = 'null';

Expand Down
18 changes: 18 additions & 0 deletions lib/internal/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,16 @@ const {
ObjectSetPrototypeOf,
Promise,
ReflectConstruct,
RegExpPrototypeExec,
Set,
Symbol,
SymbolFor,
} = primordials;

const {
toUSVString: _toUSVString,
} = internalBinding('url');

const {
codes: {
ERR_INVALID_ARG_TYPE,
Expand All @@ -44,6 +49,18 @@ const experimentalWarnings = new Set();

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() {
Expand Down Expand Up @@ -452,6 +469,7 @@ module.exports = {
promisify,
sleep,
spliceOne,
toUSVString,
removeColors,

// Symbol used to customize promisify conversion
Expand Down
4 changes: 3 additions & 1 deletion lib/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ const {
deprecate,
getSystemErrorMap,
getSystemErrorName: internalErrorName,
promisify
promisify,
toUSVString,
} = require('internal/util');

let internalDeepEqual;
Expand Down Expand Up @@ -358,6 +359,7 @@ module.exports = {
isPrimitive,
log,
promisify,
toUSVString,
TextDecoder,
TextEncoder,
types
Expand Down
2 changes: 2 additions & 0 deletions test/parallel/test-util.js
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ assert.strictEqual(util.isFunction(function() {}), true);
assert.strictEqual(util.isFunction(), false);
assert.strictEqual(util.isFunction('string'), false);

assert.strictEqual(util.toUSVString('string\ud801'), 'string\ufffd');

{
assert.strictEqual(util.types.isNativeError(new Error()), true);
assert.strictEqual(util.types.isNativeError(new TypeError()), true);
Expand Down

0 comments on commit 8eb1135

Please sign in to comment.