Skip to content

Commit b1c6a44

Browse files
aduh95danielleadams
authored andcommittedJan 12, 2021
url: refactor to use more primordials
PR-URL: #36316 Reviewed-By: Rich Trott <[email protected]>
1 parent 7aedda9 commit b1c6a44

File tree

1 file changed

+89
-59
lines changed

1 file changed

+89
-59
lines changed
 

‎lib/internal/url.js

+89-59
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
const {
44
Array,
5+
ArrayPrototypeJoin,
6+
ArrayPrototypeMap,
7+
ArrayPrototypePush,
8+
ArrayPrototypeReduce,
9+
ArrayPrototypeSlice,
10+
FunctionPrototypeBind,
511
Int8Array,
612
Number,
713
ObjectCreate,
@@ -10,9 +16,17 @@ const {
1016
ObjectGetOwnPropertySymbols,
1117
ObjectGetPrototypeOf,
1218
ObjectKeys,
19+
ReflectApply,
1320
ReflectGetOwnPropertyDescriptor,
1421
ReflectOwnKeys,
22+
RegExpPrototypeExec,
1523
String,
24+
StringPrototypeCharCodeAt,
25+
StringPrototypeIncludes,
26+
StringPrototypeReplace,
27+
StringPrototypeSlice,
28+
StringPrototypeSplit,
29+
StringPrototypeStartsWith,
1630
Symbol,
1731
SymbolIterator,
1832
SymbolToStringTag,
@@ -101,7 +115,7 @@ function toUSVString(val) {
101115
const str = `${val}`;
102116
// As of V8 5.5, `str.search()` (and `unpairedSurrogateRe[@@search]()`) are
103117
// slower than `unpairedSurrogateRe.exec()`.
104-
const match = unpairedSurrogateRe.exec(str);
118+
const match = RegExpPrototypeExec(unpairedSurrogateRe, str);
105119
if (!match)
106120
return str;
107121
return _toUSVString(str, match.index);
@@ -166,16 +180,16 @@ class URLSearchParams {
166180
}
167181
const convertedPair = [];
168182
for (const element of pair)
169-
convertedPair.push(toUSVString(element));
170-
pairs.push(convertedPair);
183+
ArrayPrototypePush(convertedPair, toUSVString(element));
184+
ArrayPrototypePush(pairs, convertedPair);
171185
}
172186

173187
this[searchParams] = [];
174188
for (const pair of pairs) {
175189
if (pair.length !== 2) {
176190
throw new ERR_INVALID_TUPLE('Each query pair', '[name, value]');
177191
}
178-
this[searchParams].push(pair[0], pair[1]);
192+
ArrayPrototypePush(this[searchParams], pair[0], pair[1]);
179193
}
180194
} else {
181195
// Record<USVString, USVString>
@@ -221,16 +235,21 @@ class URLSearchParams {
221235
const list = this[searchParams];
222236
const output = [];
223237
for (let i = 0; i < list.length; i += 2)
224-
output.push(`${innerInspect(list[i])} => ${innerInspect(list[i + 1])}`);
238+
ArrayPrototypePush(
239+
output,
240+
`${innerInspect(list[i])} => ${innerInspect(list[i + 1])}`);
225241

226-
const length = output.reduce(
242+
const length = ArrayPrototypeReduce(
243+
output,
227244
(prev, cur) => prev + removeColors(cur).length + separator.length,
228245
-separator.length
229246
);
230247
if (length > ctx.breakLength) {
231-
return `${this.constructor.name} {\n ${output.join(',\n ')} }`;
248+
return `${this.constructor.name} {\n` +
249+
` ${ArrayPrototypeJoin(output, ',\n ')} }`;
232250
} else if (output.length) {
233-
return `${this.constructor.name} { ${output.join(separator)} }`;
251+
return `${this.constructor.name} { ` +
252+
`${ArrayPrototypeJoin(output, separator)} }`;
234253
}
235254
return `${this.constructor.name} {}`;
236255
}
@@ -290,9 +309,9 @@ function onParsePortComplete(flags, protocol, username, password,
290309

291310
function onParseHostComplete(flags, protocol, username, password,
292311
host, port, path, query, fragment) {
293-
onParseHostnameComplete.apply(this, arguments);
312+
ReflectApply(onParseHostnameComplete, this, arguments);
294313
if (port !== null || ((flags & URL_FLAGS_IS_DEFAULT_SCHEME_PORT) !== 0))
295-
onParsePortComplete.apply(this, arguments);
314+
ReflectApply(onParsePortComplete, this, arguments);
296315
}
297316

298317
function onParsePathComplete(flags, protocol, username, password,
@@ -332,8 +351,8 @@ class URL {
332351
base_context = new URL(base)[context];
333352
}
334353
this[context] = new URLContext();
335-
parse(input, -1, base_context, undefined, onParseComplete.bind(this),
336-
onParseError);
354+
parse(input, -1, base_context, undefined,
355+
FunctionPrototypeBind(onParseComplete, this), onParseError);
337356
}
338357

339358
get [special]() {
@@ -461,8 +480,8 @@ ObjectDefineProperties(URL.prototype, {
461480
set(input) {
462481
// toUSVString is not needed.
463482
input = `${input}`;
464-
parse(input, -1, undefined, undefined, onParseComplete.bind(this),
465-
onParseError);
483+
parse(input, -1, undefined, undefined,
484+
FunctionPrototypeBind(onParseComplete, this), onParseError);
466485
}
467486
},
468487
origin: { // readonly
@@ -504,7 +523,7 @@ ObjectDefineProperties(URL.prototype, {
504523
return;
505524
const ctx = this[context];
506525
parse(scheme, kSchemeStart, null, ctx,
507-
onParseProtocolComplete.bind(this));
526+
FunctionPrototypeBind(onParseProtocolComplete, this));
508527
}
509528
},
510529
username: {
@@ -567,7 +586,8 @@ ObjectDefineProperties(URL.prototype, {
567586
// Cannot set the host if cannot-be-base is set
568587
return;
569588
}
570-
parse(host, kHost, null, ctx, onParseHostComplete.bind(this));
589+
parse(host, kHost, null, ctx,
590+
FunctionPrototypeBind(onParseHostComplete, this));
571591
}
572592
},
573593
hostname: {
@@ -604,7 +624,8 @@ ObjectDefineProperties(URL.prototype, {
604624
ctx.port = null;
605625
return;
606626
}
607-
parse(port, kPort, null, ctx, onParsePortComplete.bind(this));
627+
parse(port, kPort, null, ctx,
628+
FunctionPrototypeBind(onParsePortComplete, this));
608629
}
609630
},
610631
pathname: {
@@ -616,7 +637,7 @@ ObjectDefineProperties(URL.prototype, {
616637
return ctx.path[0];
617638
if (ctx.path.length === 0)
618639
return '';
619-
return `/${ctx.path.join('/')}`;
640+
return `/${ArrayPrototypeJoin(ctx.path, '/')}`;
620641
},
621642
set(path) {
622643
// toUSVString is not needed.
@@ -643,11 +664,12 @@ ObjectDefineProperties(URL.prototype, {
643664
ctx.query = null;
644665
ctx.flags &= ~URL_FLAGS_HAS_QUERY;
645666
} else {
646-
if (search[0] === '?') search = search.slice(1);
667+
if (search[0] === '?') search = StringPrototypeSlice(search, 1);
647668
ctx.query = '';
648669
ctx.flags |= URL_FLAGS_HAS_QUERY;
649670
if (search) {
650-
parse(search, kQuery, null, ctx, onParseSearchComplete.bind(this));
671+
parse(search, kQuery, null, ctx,
672+
FunctionPrototypeBind(onParseSearchComplete, this));
651673
}
652674
}
653675
initSearchParams(this[searchParams], search);
@@ -678,10 +700,11 @@ ObjectDefineProperties(URL.prototype, {
678700
ctx.flags &= ~URL_FLAGS_HAS_FRAGMENT;
679701
return;
680702
}
681-
if (hash[0] === '#') hash = hash.slice(1);
703+
if (hash[0] === '#') hash = StringPrototypeSlice(hash, 1);
682704
ctx.fragment = '';
683705
ctx.flags |= URL_FLAGS_HAS_FRAGMENT;
684-
parse(hash, kFragment, null, ctx, onParseHashComplete.bind(this));
706+
parse(hash, kFragment, null, ctx,
707+
FunctionPrototypeBind(onParseHashComplete, this));
685708
}
686709
},
687710
toJSON: {
@@ -730,7 +753,7 @@ function parseParams(qs) {
730753
let encodeCheck = 0;
731754
let i;
732755
for (i = 0; i < qs.length; ++i) {
733-
const code = qs.charCodeAt(i);
756+
const code = StringPrototypeCharCodeAt(qs, i);
734757

735758
// Try matching key/value pair separator
736759
if (code === CHAR_AMPERSAND) {
@@ -778,7 +801,7 @@ function parseParams(qs) {
778801
// Handle + and percent decoding.
779802
if (code === CHAR_PLUS) {
780803
if (lastPos < i)
781-
buf += qs.slice(lastPos, i);
804+
buf += StringPrototypeSlice(qs, lastPos, i);
782805
buf += ' ';
783806
lastPos = i + 1;
784807
} else if (!encoded) {
@@ -806,14 +829,14 @@ function parseParams(qs) {
806829
return out;
807830

808831
if (lastPos < i)
809-
buf += qs.slice(lastPos, i);
832+
buf += StringPrototypeSlice(qs, lastPos, i);
810833
if (encoded)
811834
buf = querystring.unescape(buf);
812-
out.push(buf);
835+
ArrayPrototypePush(out, buf);
813836

814837
// If `buf` is the key, add an empty value.
815838
if (!seenSep)
816-
out.push('');
839+
ArrayPrototypePush(out, '');
817840

818841
return out;
819842
}
@@ -927,7 +950,7 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', {
927950

928951
name = toUSVString(name);
929952
value = toUSVString(value);
930-
this[searchParams].push(name, value);
953+
ArrayPrototypePush(this[searchParams], name, value);
931954
update(this[context], this);
932955
},
933956

@@ -1041,7 +1064,7 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', {
10411064
// Otherwise, append a new name-value pair whose name is `name` and value
10421065
// is `value`, to `list`.
10431066
if (!found) {
1044-
list.push(name, value);
1067+
ArrayPrototypePush(list, name, value);
10451068
}
10461069

10471070
update(this[context], this);
@@ -1227,24 +1250,28 @@ defineIDLClass(URLSearchParamsIteratorPrototype, 'URLSearchParams Iterator', {
12271250
kind,
12281251
index
12291252
} = this[context];
1230-
const output = target[searchParams].slice(index).reduce((prev, cur, i) => {
1231-
const key = i % 2 === 0;
1232-
if (kind === 'key' && key) {
1233-
prev.push(cur);
1234-
} else if (kind === 'value' && !key) {
1235-
prev.push(cur);
1236-
} else if (kind === 'key+value' && !key) {
1237-
prev.push([target[searchParams][index + i - 1], cur]);
1238-
}
1239-
return prev;
1240-
}, []);
1253+
const output = ArrayPrototypeReduce(
1254+
ArrayPrototypeSlice(target[searchParams], index),
1255+
(prev, cur, i) => {
1256+
const key = i % 2 === 0;
1257+
if (kind === 'key' && key) {
1258+
ArrayPrototypePush(prev, cur);
1259+
} else if (kind === 'value' && !key) {
1260+
ArrayPrototypePush(prev, cur);
1261+
} else if (kind === 'key+value' && !key) {
1262+
ArrayPrototypePush(prev, [target[searchParams][index + i - 1], cur]);
1263+
}
1264+
return prev;
1265+
},
1266+
[]
1267+
);
12411268
const breakLn = inspect(output, innerOpts).includes('\n');
1242-
const outputStrs = output.map((p) => inspect(p, innerOpts));
1269+
const outputStrs = ArrayPrototypeMap(output, (p) => inspect(p, innerOpts));
12431270
let outputStr;
12441271
if (breakLn) {
1245-
outputStr = `\n ${outputStrs.join(',\n ')}`;
1272+
outputStr = `\n ${ArrayPrototypeJoin(outputStrs, ',\n ')}`;
12461273
} else {
1247-
outputStr = ` ${outputStrs.join(', ')}`;
1274+
outputStr = ` ${ArrayPrototypeJoin(outputStrs, ', ')}`;
12481275
}
12491276
return `${this[SymbolToStringTag]} {${outputStr} }`;
12501277
}
@@ -1272,8 +1299,9 @@ function domainToUnicode(domain) {
12721299
function urlToOptions(url) {
12731300
const options = {
12741301
protocol: url.protocol,
1275-
hostname: typeof url.hostname === 'string' && url.hostname.startsWith('[') ?
1276-
url.hostname.slice(1, -1) :
1302+
hostname: typeof url.hostname === 'string' &&
1303+
StringPrototypeStartsWith(url.hostname, '[') ?
1304+
StringPrototypeSlice(url.hostname, 1, -1) :
12771305
url.hostname,
12781306
hash: url.hash,
12791307
search: url.search,
@@ -1373,25 +1401,25 @@ const carriageReturnRegEx = /\r/g;
13731401
const tabRegEx = /\t/g;
13741402

13751403
function encodePathChars(filepath) {
1376-
if (filepath.includes('%'))
1377-
filepath = filepath.replace(percentRegEx, '%25');
1404+
if (StringPrototypeIncludes(filepath, '%'))
1405+
filepath = StringPrototypeReplace(filepath, percentRegEx, '%25');
13781406
// In posix, backslash is a valid character in paths:
1379-
if (!isWindows && filepath.includes('\\'))
1380-
filepath = filepath.replace(backslashRegEx, '%5C');
1381-
if (filepath.includes('\n'))
1382-
filepath = filepath.replace(newlineRegEx, '%0A');
1383-
if (filepath.includes('\r'))
1384-
filepath = filepath.replace(carriageReturnRegEx, '%0D');
1385-
if (filepath.includes('\t'))
1386-
filepath = filepath.replace(tabRegEx, '%09');
1407+
if (!isWindows && StringPrototypeIncludes(filepath, '\\'))
1408+
filepath = StringPrototypeReplace(filepath, backslashRegEx, '%5C');
1409+
if (StringPrototypeIncludes(filepath, '\n'))
1410+
filepath = StringPrototypeReplace(filepath, newlineRegEx, '%0A');
1411+
if (StringPrototypeIncludes(filepath, '\r'))
1412+
filepath = StringPrototypeReplace(filepath, carriageReturnRegEx, '%0D');
1413+
if (StringPrototypeIncludes(filepath, '\t'))
1414+
filepath = StringPrototypeReplace(filepath, tabRegEx, '%09');
13871415
return filepath;
13881416
}
13891417

13901418
function pathToFileURL(filepath) {
13911419
const outURL = new URL('file://');
1392-
if (isWindows && filepath.startsWith('\\\\')) {
1420+
if (isWindows && StringPrototypeStartsWith(filepath, '\\\\')) {
13931421
// UNC path format: \\server\share\resource
1394-
const paths = filepath.split('\\');
1422+
const paths = StringPrototypeSplit(filepath, '\\');
13951423
if (paths.length <= 3) {
13961424
throw new ERR_INVALID_ARG_VALUE(
13971425
'filepath',
@@ -1408,11 +1436,13 @@ function pathToFileURL(filepath) {
14081436
);
14091437
}
14101438
outURL.hostname = domainToASCII(hostname);
1411-
outURL.pathname = encodePathChars(paths.slice(3).join('/'));
1439+
outURL.pathname = encodePathChars(
1440+
ArrayPrototypeJoin(ArrayPrototypeSlice(paths, 3), '/'));
14121441
} else {
14131442
let resolved = path.resolve(filepath);
14141443
// path.resolve strips trailing slashes so we must add them back
1415-
const filePathLast = filepath.charCodeAt(filepath.length - 1);
1444+
const filePathLast = StringPrototypeCharCodeAt(filepath,
1445+
filepath.length - 1);
14161446
if ((filePathLast === CHAR_FORWARD_SLASH ||
14171447
(isWindows && filePathLast === CHAR_BACKWARD_SLASH)) &&
14181448
resolved[resolved.length - 1] !== path.sep)

0 commit comments

Comments
 (0)
Please sign in to comment.