Skip to content

Commit

Permalink
url: refactor to use more primordials
Browse files Browse the repository at this point in the history
PR-URL: #36316
Reviewed-By: Rich Trott <rtrott@gmail.com>
  • Loading branch information
aduh95 authored and targos committed May 25, 2021
1 parent 486757e commit 131b9cb
Showing 1 changed file with 89 additions and 59 deletions.
148 changes: 89 additions & 59 deletions lib/internal/url.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

const {
Array,
ArrayPrototypeJoin,
ArrayPrototypeMap,
ArrayPrototypePush,
ArrayPrototypeReduce,
ArrayPrototypeSlice,
FunctionPrototypeBind,
Int8Array,
Number,
ObjectCreate,
Expand All @@ -10,9 +16,17 @@ const {
ObjectGetOwnPropertySymbols,
ObjectGetPrototypeOf,
ObjectKeys,
ReflectApply,
ReflectGetOwnPropertyDescriptor,
ReflectOwnKeys,
RegExpPrototypeExec,
String,
StringPrototypeCharCodeAt,
StringPrototypeIncludes,
StringPrototypeReplace,
StringPrototypeSlice,
StringPrototypeSplit,
StringPrototypeStartsWith,
Symbol,
SymbolIterator,
SymbolToStringTag,
Expand Down Expand Up @@ -101,7 +115,7 @@ function toUSVString(val) {
const str = `${val}`;
// As of V8 5.5, `str.search()` (and `unpairedSurrogateRe[@@search]()`) are
// slower than `unpairedSurrogateRe.exec()`.
const match = unpairedSurrogateRe.exec(str);
const match = RegExpPrototypeExec(unpairedSurrogateRe, str);
if (!match)
return str;
return _toUSVString(str, match.index);
Expand Down Expand Up @@ -166,16 +180,16 @@ class URLSearchParams {
}
const convertedPair = [];
for (const element of pair)
convertedPair.push(toUSVString(element));
pairs.push(convertedPair);
ArrayPrototypePush(convertedPair, toUSVString(element));
ArrayPrototypePush(pairs, convertedPair);
}

this[searchParams] = [];
for (const pair of pairs) {
if (pair.length !== 2) {
throw new ERR_INVALID_TUPLE('Each query pair', '[name, value]');
}
this[searchParams].push(pair[0], pair[1]);
ArrayPrototypePush(this[searchParams], pair[0], pair[1]);
}
} else {
// Record<USVString, USVString>
Expand Down Expand Up @@ -221,16 +235,21 @@ class URLSearchParams {
const list = this[searchParams];
const output = [];
for (let i = 0; i < list.length; i += 2)
output.push(`${innerInspect(list[i])} => ${innerInspect(list[i + 1])}`);
ArrayPrototypePush(
output,
`${innerInspect(list[i])} => ${innerInspect(list[i + 1])}`);

const length = output.reduce(
const length = ArrayPrototypeReduce(
output,
(prev, cur) => prev + removeColors(cur).length + separator.length,
-separator.length
);
if (length > ctx.breakLength) {
return `${this.constructor.name} {\n ${output.join(',\n ')} }`;
return `${this.constructor.name} {\n` +
` ${ArrayPrototypeJoin(output, ',\n ')} }`;
} else if (output.length) {
return `${this.constructor.name} { ${output.join(separator)} }`;
return `${this.constructor.name} { ` +
`${ArrayPrototypeJoin(output, separator)} }`;
}
return `${this.constructor.name} {}`;
}
Expand Down Expand Up @@ -290,9 +309,9 @@ function onParsePortComplete(flags, protocol, username, password,

function onParseHostComplete(flags, protocol, username, password,
host, port, path, query, fragment) {
onParseHostnameComplete.apply(this, arguments);
ReflectApply(onParseHostnameComplete, this, arguments);
if (port !== null || ((flags & URL_FLAGS_IS_DEFAULT_SCHEME_PORT) !== 0))
onParsePortComplete.apply(this, arguments);
ReflectApply(onParsePortComplete, this, arguments);
}

function onParsePathComplete(flags, protocol, username, password,
Expand Down Expand Up @@ -332,8 +351,8 @@ class URL {
base_context = new URL(base)[context];
}
this[context] = new URLContext();
parse(input, -1, base_context, undefined, onParseComplete.bind(this),
onParseError);
parse(input, -1, base_context, undefined,
FunctionPrototypeBind(onParseComplete, this), onParseError);
}

get [special]() {
Expand Down Expand Up @@ -454,8 +473,8 @@ ObjectDefineProperties(URL.prototype, {
set(input) {
// toUSVString is not needed.
input = `${input}`;
parse(input, -1, undefined, undefined, onParseComplete.bind(this),
onParseError);
parse(input, -1, undefined, undefined,
FunctionPrototypeBind(onParseComplete, this), onParseError);
}
},
origin: { // readonly
Expand Down Expand Up @@ -502,7 +521,7 @@ ObjectDefineProperties(URL.prototype, {
return;
}
parse(scheme, kSchemeStart, null, ctx,
onParseProtocolComplete.bind(this));
FunctionPrototypeBind(onParseProtocolComplete, this));
}
},
username: {
Expand Down Expand Up @@ -565,7 +584,8 @@ ObjectDefineProperties(URL.prototype, {
// Cannot set the host if cannot-be-base is set
return;
}
parse(host, kHost, null, ctx, onParseHostComplete.bind(this));
parse(host, kHost, null, ctx,
FunctionPrototypeBind(onParseHostComplete, this));
}
},
hostname: {
Expand Down Expand Up @@ -602,7 +622,8 @@ ObjectDefineProperties(URL.prototype, {
ctx.port = null;
return;
}
parse(port, kPort, null, ctx, onParsePortComplete.bind(this));
parse(port, kPort, null, ctx,
FunctionPrototypeBind(onParsePortComplete, this));
}
},
pathname: {
Expand All @@ -614,7 +635,7 @@ ObjectDefineProperties(URL.prototype, {
return ctx.path[0];
if (ctx.path.length === 0)
return '';
return `/${ctx.path.join('/')}`;
return `/${ArrayPrototypeJoin(ctx.path, '/')}`;
},
set(path) {
// toUSVString is not needed.
Expand All @@ -641,11 +662,12 @@ ObjectDefineProperties(URL.prototype, {
ctx.query = null;
ctx.flags &= ~URL_FLAGS_HAS_QUERY;
} else {
if (search[0] === '?') search = search.slice(1);
if (search[0] === '?') search = StringPrototypeSlice(search, 1);
ctx.query = '';
ctx.flags |= URL_FLAGS_HAS_QUERY;
if (search) {
parse(search, kQuery, null, ctx, onParseSearchComplete.bind(this));
parse(search, kQuery, null, ctx,
FunctionPrototypeBind(onParseSearchComplete, this));
}
}
initSearchParams(this[searchParams], search);
Expand Down Expand Up @@ -676,10 +698,11 @@ ObjectDefineProperties(URL.prototype, {
ctx.flags &= ~URL_FLAGS_HAS_FRAGMENT;
return;
}
if (hash[0] === '#') hash = hash.slice(1);
if (hash[0] === '#') hash = StringPrototypeSlice(hash, 1);
ctx.fragment = '';
ctx.flags |= URL_FLAGS_HAS_FRAGMENT;
parse(hash, kFragment, null, ctx, onParseHashComplete.bind(this));
parse(hash, kFragment, null, ctx,
FunctionPrototypeBind(onParseHashComplete, this));
}
},
toJSON: {
Expand Down Expand Up @@ -728,7 +751,7 @@ function parseParams(qs) {
let encodeCheck = 0;
let i;
for (i = 0; i < qs.length; ++i) {
const code = qs.charCodeAt(i);
const code = StringPrototypeCharCodeAt(qs, i);

// Try matching key/value pair separator
if (code === CHAR_AMPERSAND) {
Expand Down Expand Up @@ -776,7 +799,7 @@ function parseParams(qs) {
// Handle + and percent decoding.
if (code === CHAR_PLUS) {
if (lastPos < i)
buf += qs.slice(lastPos, i);
buf += StringPrototypeSlice(qs, lastPos, i);
buf += ' ';
lastPos = i + 1;
} else if (!encoded) {
Expand Down Expand Up @@ -804,14 +827,14 @@ function parseParams(qs) {
return out;

if (lastPos < i)
buf += qs.slice(lastPos, i);
buf += StringPrototypeSlice(qs, lastPos, i);
if (encoded)
buf = querystring.unescape(buf);
out.push(buf);
ArrayPrototypePush(out, buf);

// If `buf` is the key, add an empty value.
if (!seenSep)
out.push('');
ArrayPrototypePush(out, '');

return out;
}
Expand Down Expand Up @@ -925,7 +948,7 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', {

name = toUSVString(name);
value = toUSVString(value);
this[searchParams].push(name, value);
ArrayPrototypePush(this[searchParams], name, value);
update(this[context], this);
},

Expand Down Expand Up @@ -1039,7 +1062,7 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', {
// Otherwise, append a new name-value pair whose name is `name` and value
// is `value`, to `list`.
if (!found) {
list.push(name, value);
ArrayPrototypePush(list, name, value);
}

update(this[context], this);
Expand Down Expand Up @@ -1225,24 +1248,28 @@ defineIDLClass(URLSearchParamsIteratorPrototype, 'URLSearchParams Iterator', {
kind,
index
} = this[context];
const output = target[searchParams].slice(index).reduce((prev, cur, i) => {
const key = i % 2 === 0;
if (kind === 'key' && key) {
prev.push(cur);
} else if (kind === 'value' && !key) {
prev.push(cur);
} else if (kind === 'key+value' && !key) {
prev.push([target[searchParams][index + i - 1], cur]);
}
return prev;
}, []);
const output = ArrayPrototypeReduce(
ArrayPrototypeSlice(target[searchParams], index),
(prev, cur, i) => {
const key = i % 2 === 0;
if (kind === 'key' && key) {
ArrayPrototypePush(prev, cur);
} else if (kind === 'value' && !key) {
ArrayPrototypePush(prev, cur);
} else if (kind === 'key+value' && !key) {
ArrayPrototypePush(prev, [target[searchParams][index + i - 1], cur]);
}
return prev;
},
[]
);
const breakLn = inspect(output, innerOpts).includes('\n');
const outputStrs = output.map((p) => inspect(p, innerOpts));
const outputStrs = ArrayPrototypeMap(output, (p) => inspect(p, innerOpts));
let outputStr;
if (breakLn) {
outputStr = `\n ${outputStrs.join(',\n ')}`;
outputStr = `\n ${ArrayPrototypeJoin(outputStrs, ',\n ')}`;
} else {
outputStr = ` ${outputStrs.join(', ')}`;
outputStr = ` ${ArrayPrototypeJoin(outputStrs, ', ')}`;
}
return `${this[SymbolToStringTag]} {${outputStr} }`;
}
Expand Down Expand Up @@ -1270,8 +1297,9 @@ function domainToUnicode(domain) {
function urlToOptions(url) {
const options = {
protocol: url.protocol,
hostname: typeof url.hostname === 'string' && url.hostname.startsWith('[') ?
url.hostname.slice(1, -1) :
hostname: typeof url.hostname === 'string' &&
StringPrototypeStartsWith(url.hostname, '[') ?
StringPrototypeSlice(url.hostname, 1, -1) :
url.hostname,
hash: url.hash,
search: url.search,
Expand Down Expand Up @@ -1371,25 +1399,25 @@ const carriageReturnRegEx = /\r/g;
const tabRegEx = /\t/g;

function encodePathChars(filepath) {
if (filepath.includes('%'))
filepath = filepath.replace(percentRegEx, '%25');
if (StringPrototypeIncludes(filepath, '%'))
filepath = StringPrototypeReplace(filepath, percentRegEx, '%25');
// In posix, backslash is a valid character in paths:
if (!isWindows && filepath.includes('\\'))
filepath = filepath.replace(backslashRegEx, '%5C');
if (filepath.includes('\n'))
filepath = filepath.replace(newlineRegEx, '%0A');
if (filepath.includes('\r'))
filepath = filepath.replace(carriageReturnRegEx, '%0D');
if (filepath.includes('\t'))
filepath = filepath.replace(tabRegEx, '%09');
if (!isWindows && StringPrototypeIncludes(filepath, '\\'))
filepath = StringPrototypeReplace(filepath, backslashRegEx, '%5C');
if (StringPrototypeIncludes(filepath, '\n'))
filepath = StringPrototypeReplace(filepath, newlineRegEx, '%0A');
if (StringPrototypeIncludes(filepath, '\r'))
filepath = StringPrototypeReplace(filepath, carriageReturnRegEx, '%0D');
if (StringPrototypeIncludes(filepath, '\t'))
filepath = StringPrototypeReplace(filepath, tabRegEx, '%09');
return filepath;
}

function pathToFileURL(filepath) {
const outURL = new URL('file://');
if (isWindows && filepath.startsWith('\\\\')) {
if (isWindows && StringPrototypeStartsWith(filepath, '\\\\')) {
// UNC path format: \\server\share\resource
const paths = filepath.split('\\');
const paths = StringPrototypeSplit(filepath, '\\');
if (paths.length <= 3) {
throw new ERR_INVALID_ARG_VALUE(
'filepath',
Expand All @@ -1406,11 +1434,13 @@ function pathToFileURL(filepath) {
);
}
outURL.hostname = domainToASCII(hostname);
outURL.pathname = encodePathChars(paths.slice(3).join('/'));
outURL.pathname = encodePathChars(
ArrayPrototypeJoin(ArrayPrototypeSlice(paths, 3), '/'));
} else {
let resolved = path.resolve(filepath);
// path.resolve strips trailing slashes so we must add them back
const filePathLast = filepath.charCodeAt(filepath.length - 1);
const filePathLast = StringPrototypeCharCodeAt(filepath,
filepath.length - 1);
if ((filePathLast === CHAR_FORWARD_SLASH ||
(isWindows && filePathLast === CHAR_BACKWARD_SLASH)) &&
resolved[resolved.length - 1] !== path.sep)
Expand Down

0 comments on commit 131b9cb

Please sign in to comment.