diff --git a/js/url_search_params.ts b/js/url_search_params.ts index 06369ae29d..fba6f7ac2b 100644 --- a/js/url_search_params.ts +++ b/js/url_search_params.ts @@ -1,3 +1,5 @@ +import { requiredArguments } from "./util"; + // Copyright 2018 the Deno authors. All rights reserved. MIT license. export class URLSearchParams { private params: Array<[string, string]> = []; @@ -46,7 +48,8 @@ export class URLSearchParams { * searchParams.append('name', 'second'); */ append(name: string, value: string): void { - this.params.push([name, value]); + requiredArguments("URLSearchParams.append", arguments.length, 2); + this.params.push([String(name), value]); } /** Deletes the given search parameter and its associated value, @@ -55,6 +58,8 @@ export class URLSearchParams { * searchParams.delete('name'); */ delete(name: string): void { + requiredArguments("URLSearchParams.delete", arguments.length, 1); + name = String(name); let i = 0; while (i < this.params.length) { if (this.params[i][0] === name) { @@ -71,6 +76,8 @@ export class URLSearchParams { * searchParams.getAll('name'); */ getAll(name: string): string[] { + requiredArguments("URLSearchParams.getAll", arguments.length, 1); + name = String(name); const values = []; for (const entry of this.params) { if (entry[0] === name) { @@ -86,6 +93,8 @@ export class URLSearchParams { * searchParams.get('name'); */ get(name: string): string | null { + requiredArguments("URLSearchParams.get", arguments.length, 1); + name = String(name); for (const entry of this.params) { if (entry[0] === name) { return entry[1]; @@ -101,6 +110,8 @@ export class URLSearchParams { * searchParams.has('name'); */ has(name: string): boolean { + requiredArguments("URLSearchParams.has", arguments.length, 1); + name = String(name); return this.params.some(entry => entry[0] === name); } @@ -112,9 +123,12 @@ export class URLSearchParams { * searchParams.set('name', 'value'); */ set(name: string, value: string): void { + requiredArguments("URLSearchParams.set", arguments.length, 2); + // If there are any name-value pairs whose name is name, in list, // set the value of the first such name-value pair to value // and remove the others. + name = String(name); let found = false; let i = 0; while (i < this.params.length) { @@ -122,12 +136,13 @@ export class URLSearchParams { if (!found) { this.params[i][1] = value; found = true; + i++; } else { this.params.splice(i, 1); - continue; } + } else { + i++; } - i++; } // Otherwise, append a new name-value pair whose name is name @@ -163,9 +178,12 @@ export class URLSearchParams { // tslint:disable-next-line:no-any thisArg?: any ) { + requiredArguments("URLSearchParams.forEach", arguments.length, 1); + if (typeof thisArg !== "undefined") { callbackfn = callbackfn.bind(thisArg); } + for (const [key, value] of this.entries()) { callbackfn(value, key, this); } diff --git a/js/url_search_params_test.ts b/js/url_search_params_test.ts index 802ab288b1..0637bf0d80 100644 --- a/js/url_search_params_test.ts +++ b/js/url_search_params_test.ts @@ -138,3 +138,41 @@ test(function urlSearchParamsShouldThrowTypeError() { assertEqual(hasThrown, 2); }); + +test(function urlSearchParamsAppendArgumentsCheck() { + const methodRequireOneParam = ["delete", "getAll", "get", "has", "forEach"]; + + const methodRequireTwoParams = ["append", "set"]; + + methodRequireOneParam.concat(methodRequireTwoParams).forEach(method => { + const searchParams = new URLSearchParams(); + let hasThrown = 0; + try { + searchParams[method](); + hasThrown = 1; + } catch (err) { + if (err instanceof TypeError) { + hasThrown = 2; + } else { + hasThrown = 3; + } + } + assertEqual(hasThrown, 2); + }); + + methodRequireTwoParams.forEach(method => { + const searchParams = new URLSearchParams(); + let hasThrown = 0; + try { + searchParams[method]("foo"); + hasThrown = 1; + } catch (err) { + if (err instanceof TypeError) { + hasThrown = 2; + } else { + hasThrown = 3; + } + } + assertEqual(hasThrown, 2); + }); +}); diff --git a/js/util.ts b/js/util.ts index 53de68c302..58e865337c 100644 --- a/js/util.ts +++ b/js/util.ts @@ -137,3 +137,17 @@ export function isTypedArray(x: unknown): x is TypedArray { export function isObject(o: unknown): o is object { return o != null && typeof o === "object"; } + +// @internal +export function requiredArguments( + name: string, + length: number, + required: number +): void { + if (length < required) { + const errMsg = `${name} requires at least ${required} argument${ + required === 1 ? "" : "s" + }, but only ${length} present`; + throw new TypeError(errMsg); + } +}