Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

url: refactor to use more primordials #36316

Merged
merged 1 commit into from Dec 25, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
148 changes: 89 additions & 59 deletions lib/internal/url.js
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 @@ -461,8 +480,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 @@ -504,7 +523,7 @@ ObjectDefineProperties(URL.prototype, {
return;
const ctx = this[context];
parse(scheme, kSchemeStart, null, ctx,
onParseProtocolComplete.bind(this));
FunctionPrototypeBind(onParseProtocolComplete, this));
}
},
username: {
Expand Down Expand Up @@ -567,7 +586,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 @@ -604,7 +624,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 @@ -616,7 +637,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 @@ -643,11 +664,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 @@ -678,10 +700,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 @@ -730,7 +753,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 @@ -778,7 +801,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 @@ -806,14 +829,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 @@ -927,7 +950,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 @@ -1041,7 +1064,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 @@ -1227,24 +1250,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 @@ -1272,8 +1299,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 @@ -1373,25 +1401,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 @@ -1408,11 +1436,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