1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-22 23:34:47 -05:00

fix(#2142) make URLSearchParams more standardized (#4695)

This commit is contained in:
Fenzland 2020-04-23 22:30:32 +08:00 committed by GitHub
parent 65bba2b87e
commit cb935a375c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 75 additions and 45 deletions

View file

@ -243,3 +243,33 @@ unitTest(
assertEquals(params1.get("1"), "2"); assertEquals(params1.get("1"), "2");
} }
); );
// If a class extends URLSearchParams, override one method should not change another's behavior.
unitTest(
function urlSearchParamsOverridingAppendNotChangeConstructorAndSet(): void {
let overridedAppendCalled = 0;
class CustomSearchParams extends URLSearchParams {
append(name: string, value: string): void {
++overridedAppendCalled;
super.append(name, value);
}
}
new CustomSearchParams("foo=bar");
new CustomSearchParams([["foo", "bar"]]);
new CustomSearchParams(new CustomSearchParams({ foo: "bar" }));
new CustomSearchParams().set("foo", "bar");
assertEquals(overridedAppendCalled, 0);
}
);
unitTest(function urlSearchParamsOverridingEntriesNotChangeForEach(): void {
class CustomSearchParams extends URLSearchParams {
*entries(): IterableIterator<[string, string]> {
yield* [];
}
}
let loopCount = 0;
const params = new CustomSearchParams({ foo: "bar" });
params.forEach(() => void ++loopCount);
assertEquals(loopCount, 1);
});

View file

@ -5,56 +5,17 @@ import { isIterable, requiredArguments } from "./util.ts";
/** @internal */ /** @internal */
export const urls = new WeakMap<URLSearchParams, URL | null>(); export const urls = new WeakMap<URLSearchParams, URL | null>();
function handleStringInitialization(
searchParams: URLSearchParams,
init: string
): void {
// Overload: USVString
// If init is a string and starts with U+003F (?),
// remove the first code point from init.
if (init.charCodeAt(0) === 0x003f) {
init = init.slice(1);
}
for (const pair of init.split("&")) {
// Empty params are ignored
if (pair.length === 0) {
continue;
}
const position = pair.indexOf("=");
const name = pair.slice(0, position === -1 ? pair.length : position);
const value = pair.slice(name.length + 1);
searchParams.append(decodeURIComponent(name), decodeURIComponent(value));
}
}
function handleArrayInitialization(
searchParams: URLSearchParams,
init: string[][] | Iterable<[string, string]>
): void {
// Overload: sequence<sequence<USVString>>
for (const tuple of init) {
// If pair does not contain exactly two items, then throw a TypeError.
if (tuple.length !== 2) {
throw new TypeError(
"URLSearchParams.constructor tuple array argument must only contain pair elements"
);
}
searchParams.append(tuple[0], tuple[1]);
}
}
export class URLSearchParamsImpl implements URLSearchParams { export class URLSearchParamsImpl implements URLSearchParams {
#params: Array<[string, string]> = []; #params: Array<[string, string]> = [];
constructor(init: string | string[][] | Record<string, string> = "") { constructor(init: string | string[][] | Record<string, string> = "") {
if (typeof init === "string") { if (typeof init === "string") {
handleStringInitialization(this, init); this.#handleStringInitialization(init);
return; return;
} }
if (Array.isArray(init) || isIterable(init)) { if (Array.isArray(init) || isIterable(init)) {
handleArrayInitialization(this, init); this.#handleArrayInitialization(init);
return; return;
} }
@ -69,12 +30,47 @@ export class URLSearchParamsImpl implements URLSearchParams {
// Overload: record<USVString, USVString> // Overload: record<USVString, USVString>
for (const key of Object.keys(init)) { for (const key of Object.keys(init)) {
this.append(key, init[key]); this.#append(key, init[key]);
} }
urls.set(this, null); urls.set(this, null);
} }
#handleStringInitialization = (init: string): void => {
// Overload: USVString
// If init is a string and starts with U+003F (?),
// remove the first code point from init.
if (init.charCodeAt(0) === 0x003f) {
init = init.slice(1);
}
for (const pair of init.split("&")) {
// Empty params are ignored
if (pair.length === 0) {
continue;
}
const position = pair.indexOf("=");
const name = pair.slice(0, position === -1 ? pair.length : position);
const value = pair.slice(name.length + 1);
this.#append(decodeURIComponent(name), decodeURIComponent(value));
}
};
#handleArrayInitialization = (
init: string[][] | Iterable<[string, string]>
): void => {
// Overload: sequence<sequence<USVString>>
for (const tuple of init) {
// If pair does not contain exactly two items, then throw a TypeError.
if (tuple.length !== 2) {
throw new TypeError(
"URLSearchParams.constructor tuple array argument must only contain pair elements"
);
}
this.#append(tuple[0], tuple[1]);
}
};
#updateSteps = (): void => { #updateSteps = (): void => {
const url = urls.get(this); const url = urls.get(this);
if (url == null) { if (url == null) {
@ -89,9 +85,13 @@ export class URLSearchParamsImpl implements URLSearchParams {
parts.get(url)!.query = query; parts.get(url)!.query = query;
}; };
#append = (name: string, value: string): void => {
this.#params.push([String(name), String(value)]);
};
append(name: string, value: string): void { append(name: string, value: string): void {
requiredArguments("URLSearchParams.append", arguments.length, 2); requiredArguments("URLSearchParams.append", arguments.length, 2);
this.#params.push([String(name), String(value)]); this.#append(name, value);
this.#updateSteps(); this.#updateSteps();
} }
@ -167,7 +167,7 @@ export class URLSearchParamsImpl implements URLSearchParams {
// Otherwise, append a new name-value pair whose name is name // Otherwise, append a new name-value pair whose name is name
// and value is value, to list. // and value is value, to list.
if (!found) { if (!found) {
this.append(name, value); this.#append(name, value);
} }
this.#updateSteps(); this.#updateSteps();
@ -189,7 +189,7 @@ export class URLSearchParamsImpl implements URLSearchParams {
callbackfn = callbackfn.bind(thisArg); callbackfn = callbackfn.bind(thisArg);
} }
for (const [key, value] of this.entries()) { for (const [key, value] of this.#params) {
callbackfn(value, key, this); callbackfn(value, key, this);
} }
} }