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

avoid prototype builtin hasOwnProperty #2144

Merged
merged 2 commits into from
Apr 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions js/blob.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import * as domTypes from "./dom_types";
import { containsOnlyASCII } from "./util";
import { containsOnlyASCII, hasOwnProperty } from "./util";
import { TextEncoder } from "./text_encoding";

export const bytesSymbol = Symbol("bytes");
Expand Down Expand Up @@ -91,7 +91,7 @@ export class DenoBlob implements domTypes.Blob {

options = options || {};
// Set ending property's default value to "transparent".
if (!options.hasOwnProperty("ending")) {
if (!hasOwnProperty(options, "ending")) {
options.ending = "transparent";
}

Expand Down
18 changes: 18 additions & 0 deletions js/blob_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,22 @@ test(function blobSlice() {
assertEquals(b4.size, blob.size);
});

test(function blobShouldNotThrowError() {
let hasThrown = false;

try {
const options1: object = {
ending: "utf8",
hasOwnProperty: "hasOwnProperty"
};
const options2: object = Object.create(null);
new Blob(["Hello World"], options1);
new Blob(["Hello World"], options2);
} catch {
hasThrown = true;
}

assertEquals(hasThrown, false);
});

// TODO(qti3e) Test the stored data in a Blob after implementing FileReader API.
3 changes: 2 additions & 1 deletion js/console_table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Forked from Node's lib/internal/cli_table.js

import { TextEncoder } from "./text_encoding";
import { hasOwnProperty } from "./util";

const encoder = new TextEncoder();

Expand Down Expand Up @@ -64,7 +65,7 @@ export function cliTable(head: string[], columns: string[][]): string {
if (rows[j] === undefined) {
rows[j] = [];
}
const value = (rows[j][i] = column.hasOwnProperty(j) ? column[j] : "");
const value = (rows[j][i] = hasOwnProperty(column, j) ? column[j] : "");
const width = columnWidths[i] || 0;
const counted = countBytes(value);
columnWidths[i] = Math.max(width, counted);
Expand Down
8 changes: 4 additions & 4 deletions js/event_target.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import * as domTypes from "./dom_types";
import { requiredArguments } from "./util";
import { requiredArguments, hasOwnProperty } from "./util";

/* TODO: This is an incomplete implementation to provide functionality
* for Event. A proper spec is still required for a proper Web API.
Expand All @@ -16,7 +16,7 @@ export class EventTarget implements domTypes.EventTarget {
_options?: boolean | domTypes.AddEventListenerOptions
): void {
requiredArguments("EventTarget.addEventListener", arguments.length, 2);
if (!this.listeners.hasOwnProperty(type)) {
if (!hasOwnProperty(this.listeners, type)) {
this.listeners[type] = [];
}
if (listener !== null) {
Expand All @@ -30,7 +30,7 @@ export class EventTarget implements domTypes.EventTarget {
_options?: domTypes.EventListenerOptions | boolean
): void {
requiredArguments("EventTarget.removeEventListener", arguments.length, 2);
if (this.listeners.hasOwnProperty(type) && callback !== null) {
if (hasOwnProperty(this.listeners, type) && callback !== null) {
this.listeners[type] = this.listeners[type].filter(
listener => listener !== callback
);
Expand All @@ -39,7 +39,7 @@ export class EventTarget implements domTypes.EventTarget {

public dispatchEvent(event: domTypes.Event): boolean {
requiredArguments("EventTarget.dispatchEvent", arguments.length, 1);
if (!this.listeners.hasOwnProperty(event.type)) {
if (!hasOwnProperty(this.listeners, event.type)) {
return true;
}
const stack = this.listeners[event.type].slice();
Expand Down
18 changes: 18 additions & 0 deletions js/event_target_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,21 @@ test(function toStringShouldBeWebCompatibility() {
const target = new EventTarget();
assertEquals(target.toString(), "[object EventTarget]");
});

test(function dispatchEventShouldNotThrowError() {
let hasThrown = false;

try {
const target = new EventTarget();
const event = new Event("hasOwnProperty", {
bubbles: true,
cancelable: false
});
target.addEventListener("hasOwnProperty", () => {});
target.dispatchEvent(event);
} catch {
hasThrown = true;
}

assertEquals(hasThrown, false);
});
30 changes: 30 additions & 0 deletions js/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,33 @@ export function getPrivateValue<
}
throw new TypeError("Illegal invocation");
}

/**
* Determines whether an object has a property with the specified name.
* Avoid calling prototype builtin `hasOwnProperty` for two reasons:
*
* 1. `hasOwnProperty` is defined on the object as something else:
*
* const options = {
* ending: 'utf8',
* hasOwnProperty: 'foo'
* };
* options.hasOwnProperty('ending') // throws a TypeError
*
* 2. The object doesn't inherit from `Object.prototype`:
*
* const options = Object.create(null);
* options.ending = 'utf8';
* options.hasOwnProperty('ending'); // throws a TypeError
*
* @param obj A Object.
* @param v A property name.
* @see https://eslint.org/docs/rules/no-prototype-builtins
* @internal
*/
export function hasOwnProperty<T>(obj: T, v: PropertyKey): boolean {
if (obj == null) {
return false;
}
return Object.prototype.hasOwnProperty.call(obj, v);
}