mirror of
https://github.com/denoland/deno.git
synced 2025-03-03 17:34:47 -05:00
avoid prototype builtin hasOwnProperty (#2144)
This commit is contained in:
parent
2be7e44403
commit
d0cd7a39a2
6 changed files with 74 additions and 7 deletions
|
@ -1,6 +1,6 @@
|
||||||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||||
import * as domTypes from "./dom_types";
|
import * as domTypes from "./dom_types";
|
||||||
import { containsOnlyASCII } from "./util";
|
import { containsOnlyASCII, hasOwnProperty } from "./util";
|
||||||
import { TextEncoder } from "./text_encoding";
|
import { TextEncoder } from "./text_encoding";
|
||||||
|
|
||||||
export const bytesSymbol = Symbol("bytes");
|
export const bytesSymbol = Symbol("bytes");
|
||||||
|
@ -91,7 +91,7 @@ export class DenoBlob implements domTypes.Blob {
|
||||||
|
|
||||||
options = options || {};
|
options = options || {};
|
||||||
// Set ending property's default value to "transparent".
|
// Set ending property's default value to "transparent".
|
||||||
if (!options.hasOwnProperty("ending")) {
|
if (!hasOwnProperty(options, "ending")) {
|
||||||
options.ending = "transparent";
|
options.ending = "transparent";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,4 +32,22 @@ test(function blobSlice() {
|
||||||
assertEquals(b4.size, blob.size);
|
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.
|
// TODO(qti3e) Test the stored data in a Blob after implementing FileReader API.
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
// Forked from Node's lib/internal/cli_table.js
|
// Forked from Node's lib/internal/cli_table.js
|
||||||
|
|
||||||
import { TextEncoder } from "./text_encoding";
|
import { TextEncoder } from "./text_encoding";
|
||||||
|
import { hasOwnProperty } from "./util";
|
||||||
|
|
||||||
const encoder = new TextEncoder();
|
const encoder = new TextEncoder();
|
||||||
|
|
||||||
|
@ -64,7 +65,7 @@ export function cliTable(head: string[], columns: string[][]): string {
|
||||||
if (rows[j] === undefined) {
|
if (rows[j] === undefined) {
|
||||||
rows[j] = [];
|
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 width = columnWidths[i] || 0;
|
||||||
const counted = countBytes(value);
|
const counted = countBytes(value);
|
||||||
columnWidths[i] = Math.max(width, counted);
|
columnWidths[i] = Math.max(width, counted);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||||
import * as domTypes from "./dom_types";
|
import * as domTypes from "./dom_types";
|
||||||
import { requiredArguments } from "./util";
|
import { requiredArguments, hasOwnProperty } from "./util";
|
||||||
|
|
||||||
/* TODO: This is an incomplete implementation to provide functionality
|
/* TODO: This is an incomplete implementation to provide functionality
|
||||||
* for Event. A proper spec is still required for a proper Web API.
|
* for Event. A proper spec is still required for a proper Web API.
|
||||||
|
@ -16,7 +16,7 @@ export class EventTarget implements domTypes.EventTarget {
|
||||||
_options?: boolean | domTypes.AddEventListenerOptions
|
_options?: boolean | domTypes.AddEventListenerOptions
|
||||||
): void {
|
): void {
|
||||||
requiredArguments("EventTarget.addEventListener", arguments.length, 2);
|
requiredArguments("EventTarget.addEventListener", arguments.length, 2);
|
||||||
if (!this.listeners.hasOwnProperty(type)) {
|
if (!hasOwnProperty(this.listeners, type)) {
|
||||||
this.listeners[type] = [];
|
this.listeners[type] = [];
|
||||||
}
|
}
|
||||||
if (listener !== null) {
|
if (listener !== null) {
|
||||||
|
@ -30,7 +30,7 @@ export class EventTarget implements domTypes.EventTarget {
|
||||||
_options?: domTypes.EventListenerOptions | boolean
|
_options?: domTypes.EventListenerOptions | boolean
|
||||||
): void {
|
): void {
|
||||||
requiredArguments("EventTarget.removeEventListener", arguments.length, 2);
|
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(
|
this.listeners[type] = this.listeners[type].filter(
|
||||||
listener => listener !== callback
|
listener => listener !== callback
|
||||||
);
|
);
|
||||||
|
@ -39,7 +39,7 @@ export class EventTarget implements domTypes.EventTarget {
|
||||||
|
|
||||||
public dispatchEvent(event: domTypes.Event): boolean {
|
public dispatchEvent(event: domTypes.Event): boolean {
|
||||||
requiredArguments("EventTarget.dispatchEvent", arguments.length, 1);
|
requiredArguments("EventTarget.dispatchEvent", arguments.length, 1);
|
||||||
if (!this.listeners.hasOwnProperty(event.type)) {
|
if (!hasOwnProperty(this.listeners, event.type)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const stack = this.listeners[event.type].slice();
|
const stack = this.listeners[event.type].slice();
|
||||||
|
|
|
@ -92,3 +92,21 @@ test(function toStringShouldBeWebCompatibility() {
|
||||||
const target = new EventTarget();
|
const target = new EventTarget();
|
||||||
assertEquals(target.toString(), "[object 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
js/util.ts
30
js/util.ts
|
@ -142,3 +142,33 @@ export function getPrivateValue<
|
||||||
}
|
}
|
||||||
throw new TypeError("Illegal invocation");
|
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);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue