From: Lady Date: Mon, 4 Sep 2023 22:25:40 +0000 (-0400) Subject: Add toFunctionName to function.js X-Git-Url: https://git.ladys.computer/Pisces/commitdiff_plain/7856a19da4629d55827162c0fe73cab9704237d9?ds=sidebyside Add toFunctionName to function.js --- diff --git a/function.js b/function.js index cc81fb6..d5888eb 100644 --- a/function.js +++ b/function.js @@ -199,3 +199,33 @@ export const ordinaryHasInstance = createCallableFunction( Function.prototype[Symbol.hasInstance], "ordinaryHasInstance", ); + +export const { + /** + * Returns a string function name generated from the provided value + * and optional prefix. + */ + toFunctionName, +} = (() => { + const getSymbolDescription = Object.getOwnPropertyDescriptor( + Symbol.prototype, + "description", + ).get; + + return { + toFunctionName: ($, prefix = undefined) => { + const name = (() => { + if (typeof $ === "symbol") { + // The provided value is a symbol; format its description. + const description = call(getSymbolDescription, $, []); + return description === undefined ? "" : `[${description}]`; + } else { + // The provided value not a symbol; convert it to a string + // property key. + return `${$}`; + } + })(); + return prefix !== undefined ? `${prefix} ${name}` : name; + }, + }; +})(); diff --git a/function.test.js b/function.test.js index 9711f79..75ba300 100644 --- a/function.test.js +++ b/function.test.js @@ -26,6 +26,7 @@ import { isCallable, isConstructor, ordinaryHasInstance, + toFunctionName, } from "./function.js"; describe("bind", () => { @@ -567,3 +568,75 @@ describe("ordinaryHasInstance", () => { }); }); }); + +describe("toFunctionName", () => { + it("[[Call]] works with strings and no prefix", () => { + assertStrictEquals(toFunctionName("etaoin"), "etaoin"); + }); + + it("[[Call]] works with objects and no prefix", () => { + assertStrictEquals( + toFunctionName({ + toString() { + return "etaoin"; + }, + }), + "etaoin", + ); + }); + + it("[[Call]] works with descriptionless symbols and no prefix", () => { + assertStrictEquals(toFunctionName(Symbol()), ""); + }); + + it("[[Call]] works with empty description symbols and no prefix", () => { + assertStrictEquals(toFunctionName(Symbol("")), "[]"); + }); + + it("[[Call]] works with described symbols and no prefix", () => { + assertStrictEquals(toFunctionName(Symbol("etaoin")), "[etaoin]"); + }); + + it("[[Call]] works with strings and a prefix", () => { + assertStrictEquals(toFunctionName("etaoin", "foo"), "foo etaoin"); + }); + + it("[[Call]] works with objects and no prefix", () => { + assertStrictEquals( + toFunctionName({ + toString() { + return "etaoin"; + }, + }, "foo"), + "foo etaoin", + ); + }); + + it("[[Call]] works with descriptionless symbols and no prefix", () => { + assertStrictEquals(toFunctionName(Symbol(), "foo"), "foo "); + }); + + it("[[Call]] works with empty description symbols and no prefix", () => { + assertStrictEquals(toFunctionName(Symbol(""), "foo"), "foo []"); + }); + + it("[[Call]] works with described symbols and no prefix", () => { + assertStrictEquals( + toFunctionName(Symbol("etaoin"), "foo"), + "foo [etaoin]", + ); + }); + + it("[[Construct]] throws an error", () => { + assertThrows(() => new toFunctionName("")); + }); + + describe(".name", () => { + it("[[Get]] returns the correct name", () => { + assertStrictEquals( + toFunctionName.name, + "toFunctionName", + ); + }); + }); +});