diff --git a/.changeset/giant-papayas-hear.md b/.changeset/giant-papayas-hear.md new file mode 100644 index 0000000..ff43585 --- /dev/null +++ b/.changeset/giant-papayas-hear.md @@ -0,0 +1,17 @@ +--- +"react-fast-hoc": minor +--- + +Made displayName editable for each transformed component: + +```tsx +const _ = transformProps(A, (props) => props, { + displayNameTransform: { + value: (name) => name + "C", + type: "rewrite-dynamic", + }, +}); +expect(_.displayName).toBe("AC"); +_.displayName = "D"; +expect(_.displayName).toBe("D"); +``` diff --git a/packages/react-fast-hoc/src/handlers/hocTransformer.ts b/packages/react-fast-hoc/src/handlers/hocTransformer.ts index ae0eba7..02dabb9 100644 --- a/packages/react-fast-hoc/src/handlers/hocTransformer.ts +++ b/packages/react-fast-hoc/src/handlers/hocTransformer.ts @@ -20,6 +20,7 @@ const calculateDisplayNameTransform = ( // Using classes to save memory export class HocTransformer implements ProxyHandler { + _displayNameField = Symbol("displayName"); constructor( private transformer: | null @@ -38,15 +39,30 @@ export class HocTransformer implements ProxyHandler { } get(target: Function, p: string | symbol, receiver: any) { - if (process.env.NODE_ENV === "production") { + if ( + process.env.NODE_ENV === "production" || + p !== "displayName" || + !this.displayNameTransform + ) { return Reflect.get(target, p, receiver); } - if (p !== "displayName" || !this.displayNameTransform) { - return Reflect.get(target, p, receiver); + if (!(this._displayNameField in target)) { + // @ts-expect-error + target[this._displayNameField] = calculateDisplayNameTransform( + getComponentName(target), + this.displayNameTransform + ); } - return calculateDisplayNameTransform( - getComponentName(target), - this.displayNameTransform - ); + + // @ts-expect-error + return target[this._displayNameField]; + } + set(target: Function, p: string | symbol, value: any) { + if (process.env.NODE_ENV !== "production" && p === "displayName") { + // @ts-expect-error + target[this._displayNameField] = value; + return true; + } + return Reflect.set(target, p, value); } } diff --git a/packages/react-fast-hoc/src/internals.ts b/packages/react-fast-hoc/src/internals.ts index bbf3f16..6cda8e6 100644 --- a/packages/react-fast-hoc/src/internals.ts +++ b/packages/react-fast-hoc/src/internals.ts @@ -35,13 +35,6 @@ const REACT_MEMO_TYPE = Symbol.for("react.memo"); const REACT_FORWARD_REF_TYPE = Symbol.for("react.forward_ref"); const REACT_LAZY_TYPE = Symbol.for("react.lazy"); -// const enum LazyStatus { -// Uninitialized = -1, -// Pending = 0, -// Resolved = 1, -// Rejected = 2, -// } - type RealComponentType = | { $$typeof: typeof REACT_FORWARD_REF_TYPE; diff --git a/packages/react-fast-hoc/src/rename.test.ts b/packages/react-fast-hoc/src/rename.test.ts index a2dd6a2..a4967d5 100644 --- a/packages/react-fast-hoc/src/rename.test.ts +++ b/packages/react-fast-hoc/src/rename.test.ts @@ -55,4 +55,26 @@ describe("renaming works", () => { }).displayName ).toBe("AC"); }); + + test("that component is imperatively renameable", () => { + const _ = transformProps(A, (props) => props, { + displayNameTransform: { + value: (name) => name + "C", + type: "rewrite-dynamic", + }, + }); + expect(_.displayName).toBe("AC"); + _.displayName = "D"; + expect(_.displayName).toBe("D"); + const __ = transformProps(_, (props) => props, { + displayNameTransform: { + type: "rewrite", + value: "E", + }, + }); + expect(__.displayName).toBe("E"); + __.displayName = "bebe"; + expect(__.displayName).toBe("bebe"); + expect(_.displayName).toBe("D"); + }); });