* Removes the provided property key from the provided object and
* returns the object.
*
- * ☡ This function differs from Reflect.deleteProperty and the
+ * ※ This function differs from Reflect.deleteProperty and the
* `delete` operator in that it throws if the deletion is
* unsuccessful.
+ *
+ * ※ This function throws if the first argument is not an object.
*/
deleteOwnProperty,
+ /**
+ * Returns an array of property keys on the provided object.
+ *
+ * ※ This is effectively an alias for Reflect.ownKeys, except that
+ * it does not require that the argument be an object.
+ */
+ getOwnPropertyKeys,
+
+ /**
+ * Returns the value of the provided property key on the provided
+ * object.
+ *
+ * ※ This is effectively an alias for Reflect.get, except that it
+ * does not require that the argument be an object.
+ */
+ getPropertyValue,
+
+ /**
+ * Returns whether the provided property key exists on the provided
+ * object.
+ *
+ * ※ This is effectively an alias for Reflect.has, except that it
+ * does not require that the argument be an object.
+ *
+ * ※ This includes properties present on the prototype chain.
+ */
+ hasProperty,
+
/**
* Sets the provided property key to the provided value on the
* provided object and returns the object.
*
* ※ This function differs from Reflect.set in that it throws if the
* setting is unsuccessful.
+ *
+ * ※ This function throws if the first argument is not an object.
*/
setPropertyValue,
} = (() => {
- const { deleteProperty, set } = Reflect;
+ const { deleteProperty, get, has, ownKeys, set } = Reflect;
return {
deleteOwnProperty: (O, P) => {
- if (!deleteProperty(O, P)) {
+ if (type(O) !== "object") {
+ throw new TypeError(
+ `Piscēs: Tried to set property but provided value was not an object: ${V}`,
+ );
+ } else if (!deleteProperty(O, P)) {
throw new TypeError(
`Piscēs: Tried to delete property from object but [[Delete]] returned false: ${P}`,
);
return O;
}
},
+ getOwnPropertyKeys: (O) => ownKeys(toObject(O)),
+ getPropertyValue: (O, P, Receiver = O) =>
+ get(toObject(O), P, Receiver),
+ hasProperty: (O, P) => has(toObject(O), P),
setPropertyValue: (O, P, V, Receiver = O) => {
- if (!set(O, P, V, Receiver)) {
+ if (type(O) !== "object") {
+ throw new TypeError(
+ `Piscēs: Tried to set property but provided value was not an object: ${V}`,
+ );
+ } else if (!set(O, P, V, Receiver)) {
throw new TypeError(
`Piscēs: Tried to set property on object but [[Set]] returned false: ${P}`,
);
};
})();
-export const {
- /**
- * Returns an array of property keys on the provided object.
- *
- * ※ This is an alias for Reflect.ownKeys.
- */
- ownKeys: getOwnPropertyKeys,
-
- /**
- * Returns the value of the provided property key on the provided
- * object.
- *
- * ※ This is an alias for Reflect.get.
- */
- get: getPropertyValue,
-
- /**
- * Returns whether the provided property key exists on the provided
- * object.
- *
- * ※ This is an alias for Reflect.has.
- *
- * ※ This includes properties present on the prototype chain.
- */
- has: hasProperty,
-} = Reflect;
+export const getMethod = (V, P) => {
+ const func = getPropertyValue(V, P);
+ if (func == null) {
+ return undefined;
+ } else if (typeof func !== "function") {
+ throw new TypeError(`Piscēs: Method not callable: ${P}`);
+ } else {
+ return func;
+ }
+};
/**
* Returns the provided value converted to an object.
*
- * Null and undefined are converted to a new, empty object. Other
- * primitives are wrapped. Existing objects are returned with no
- * modification.
+ * Existing objects are returned with no modification.
*
- * ※ This is effectively a nonconstructible version of the Object
- * constructor.
+ * ☡ This function throws a TypeError if its argument is null or
+ * undefined.
*/
export const { toObject } = (() => {
const makeObject = Object;
- return { toObject: ($) => makeObject($) };
+ return {
+ toObject: ($) => {
+ if ($ == null) {
+ throw new TypeError(
+ `Piscēs: Cannot convert ${$} into an object.`,
+ );
+ } else {
+ return makeObject($);
+ }
+ },
+ };
})();
/**
defineOwnProperties,
deleteOwnProperty,
frozenCopy,
+ getMethod,
+ getOwnPropertyKeys,
+ getPropertyValue,
+ hasProperty,
LazyLoader,
PropertyDescriptor,
setPropertyValue,
});
});
+describe("getMethod", () => {
+ it("[[Call]] gets a method", () => {
+ const method = () => {};
+ assertStrictEquals(getMethod({ method }, "method"), method);
+ });
+
+ it("[[Call]] works for values coercible to objects", () => {
+ assertEquals(getMethod("", "toString"), String.prototype.toString);
+ });
+
+ it("[[Call]] throws for null and undefined", () => {
+ assertThrows(() => getMethod(null, "valueOf"));
+ assertThrows(() => getMethod(undefined, "valueOf"));
+ });
+
+ it("[[Call]] throws if the resulting value isn’t callable", () => {
+ assertThrows(() => getMethod({ "failure": true }, "failure"));
+ });
+});
+
+describe("getOwnPropertyKeys", () => {
+ it("[[Call]] gets own (but not inherited) property keys", () => {
+ assertEquals(getOwnPropertyKeys({ success: true }), ["success"]);
+ });
+
+ it("[[Call]] works for values coercible to objects", () => {
+ assertEquals(getOwnPropertyKeys("foo"), ["0", "1", "2", "length"]);
+ });
+
+ it("[[Call]] throws for null and undefined", () => {
+ assertThrows(() => getOwnPropertyKeys(null));
+ assertThrows(() => getOwnPropertyKeys(undefined));
+ });
+});
+
+describe("getPropertyValue", () => {
+ it("[[Call]] gets property values on the provided object", () => {
+ assertStrictEquals(
+ getPropertyValue({ success: true }, "success"),
+ true,
+ );
+ });
+
+ it("[[Call]] works for values coercible to objects", () => {
+ assertStrictEquals(
+ getPropertyValue("", "toString"),
+ String.prototype.toString,
+ );
+ });
+
+ it("[[Call]] throws for null and undefined", () => {
+ assertThrows(() => getPropertyValue(null, "valueOf"));
+ assertThrows(() => getPropertyValue(undefined, "valueOf"));
+ });
+});
+
+describe("hasProperty", () => {
+ it("[[Call]] gets whether a property exists on the provided object", () => {
+ assertStrictEquals(
+ hasProperty({ success: "etaoin" }, "success"),
+ true,
+ );
+ });
+
+ it("[[Call]] works for values coercible to objects", () => {
+ assertStrictEquals(hasProperty("", "toString"), true);
+ });
+
+ it("[[Call]] throws for null and undefined", () => {
+ assertThrows(() => hasProperty(null, "valueOf"));
+ assertThrows(() => hasProperty(undefined, "valueOf"));
+ });
+});
+
describe("setPropertyValue", () => {
it("[[Call]] sets the provided property on the provided object", () => {
const obj = {};
assertStrictEquals(toObject(obj), obj);
});
- it("returns a new object for nullish values", () => {
- assertEquals(toObject(null), {});
- assertEquals(toObject(void {}), {});
+ it("throws for nullish values", () => {
+ assertThrows(() => toObject(null));
+ assertThrows(() => toObject(void {}));
});
it("returns a wrapper object for other primitives", () => {