From 800ef70389bea5954158c8463c129503e083d2da Mon Sep 17 00:00:00 2001 From: Arturs Jansons Date: Tue, 27 Feb 2024 15:26:18 +0300 Subject: [PATCH] Add hasOwn into utils as safe replacement for hasOwnProperty --- .../__tests__/babel/has-own-property copy.js | 38 +++++++++++++++++++ .../react/__tests__/babel/has-own-property.js | 23 +++++++++++ packages/react/src/emotion-element.js | 6 +-- packages/react/src/jsx-dev-runtime.js | 3 +- packages/react/src/jsx-runtime.js | 5 ++- packages/react/src/jsx.js | 3 +- packages/react/src/utils.js | 2 + 7 files changed, 73 insertions(+), 7 deletions(-) create mode 100644 packages/react/__tests__/babel/has-own-property copy.js create mode 100644 packages/react/__tests__/babel/has-own-property.js diff --git a/packages/react/__tests__/babel/has-own-property copy.js b/packages/react/__tests__/babel/has-own-property copy.js new file mode 100644 index 0000000000..99790bb493 --- /dev/null +++ b/packages/react/__tests__/babel/has-own-property copy.js @@ -0,0 +1,38 @@ +import { render } from '@testing-library/react' +console.error = jest.fn() + +test('hasOwnProperty', async () => { + 'use strict' + // Freeze Object.prototype to not accidentally export its properties again + // see https://github.com/emotion-js/emotion/issues/3158 + Object.freeze(Object.prototype) + + // Previous version: + // const utils = (await import('../../dist/emotion-element-48d2c2e4.cjs.dev.js')) + // .default + + // Current version: + // const utils = (await import('../../dist/emotion-element-e909c831.cjs.dev')) + // .default + + // console.log(utils) + // expect( + // Object.prototype.hasOwnProperty.call(utils, 'hasOwnProperty') + // ).toBeFalsy() + + const element = await import('../../dist/emotion-react.worker.esm.js').default + console.log(element) + expect( + Object.prototype.hasOwnProperty.call(element, 'hasOwnProperty') + ).toBeFalsy() + + // /** @jsx jsx */ + // const { jsx } = await import('@emotion/react') + // // const { CacheProvider } = await import('@emotion/react') + // const { CacheProvider } = await import('../../dist/emotion-react.cjs.dev.js') + // const createCache = await (await import('@emotion/cache')).default + + // const cache = createCache({ key: 'context' }) + // render() + expect(console.error).not.toHaveBeenCalled() +}) diff --git a/packages/react/__tests__/babel/has-own-property.js b/packages/react/__tests__/babel/has-own-property.js new file mode 100644 index 0000000000..6f2552634e --- /dev/null +++ b/packages/react/__tests__/babel/has-own-property.js @@ -0,0 +1,23 @@ +import { render } from '@testing-library/react' +console.error = jest.fn() + +test('hasOwnProperty', async () => { + // Freeze Object.prototype to not accidentally export its properties again + // see https://github.com/emotion-js/emotion/issues/3158 + Object.freeze(Object.prototype) + + // const utils = (await import('../../dist/emotion-react.cjs.dev.js')).default + // Previous version: + // const utils = (await import('../../dist/emotion-element-48d2c2e4.cjs.dev.js')) + // .default + + // Current version: + const utils = (await import('../../dist/emotion-element-e909c831.cjs.dev')) + .default + + expect( + Object.prototype.hasOwnProperty.call(utils, 'hasOwnProperty') + ).toBeFalsy() + + expect(console.error).not.toHaveBeenCalled() +}) diff --git a/packages/react/src/emotion-element.js b/packages/react/src/emotion-element.js index 45e0b649fb..b1ca38adb3 100644 --- a/packages/react/src/emotion-element.js +++ b/packages/react/src/emotion-element.js @@ -7,7 +7,7 @@ import { insertStyles, registerStyles } from '@emotion/utils' -import { isBrowser } from './utils' +import { hasOwn, isBrowser } from './utils' import { serializeStyles } from '@emotion/serialize' import { getLabelFromStackTrace } from './get-label-from-stack-trace' import { useInsertionEffectAlwaysWithSyncFallback } from '@emotion/use-insertion-effect-with-fallbacks' @@ -31,7 +31,7 @@ export const createEmotionProps = (type: React.ElementType, props: Object) => { let newProps: any = {} for (let key in props) { - if (Object.hasOwn(props, key)) { + if (hasOwn(props, key)) { newProps[key] = props[key] } } @@ -133,7 +133,7 @@ let Emotion = /* #__PURE__ */ withEmotionCache( const newProps = {} for (let key in props) { if ( - Object.hasOwn(props, key) && + hasOwn(props, key) && key !== 'css' && key !== typePropName && (process.env.NODE_ENV === 'production' || key !== labelPropName) diff --git a/packages/react/src/jsx-dev-runtime.js b/packages/react/src/jsx-dev-runtime.js index 635a5c0427..1b4ea26184 100644 --- a/packages/react/src/jsx-dev-runtime.js +++ b/packages/react/src/jsx-dev-runtime.js @@ -1,6 +1,7 @@ // @flow import * as ReactJSXRuntimeDev from 'react/jsx-dev-runtime' import Emotion, { createEmotionProps } from './emotion-element' +import { hasOwn } from './utils' export const Fragment = ReactJSXRuntimeDev.Fragment @@ -12,7 +13,7 @@ export function jsxDEV( source: any, self: any ) { - if (!Object.hasOwn(props, 'css')) { + if (!hasOwn(props, 'css')) { return ReactJSXRuntimeDev.jsxDEV( type, props, diff --git a/packages/react/src/jsx-runtime.js b/packages/react/src/jsx-runtime.js index 7f05a2bdda..8fb238b642 100644 --- a/packages/react/src/jsx-runtime.js +++ b/packages/react/src/jsx-runtime.js @@ -1,11 +1,12 @@ // @flow import * as ReactJSXRuntime from 'react/jsx-runtime' import Emotion, { createEmotionProps } from './emotion-element' +import { hasOwn } from './utils' export const Fragment = ReactJSXRuntime.Fragment export function jsx(type: any, props: any, key: any) { - if (!Object.hasOwn(props, 'css')) { + if (!hasOwn(props, 'css')) { return ReactJSXRuntime.jsx(type, props, key) } @@ -13,7 +14,7 @@ export function jsx(type: any, props: any, key: any) { } export function jsxs(type: any, props: any, key: any) { - if (!Object.hasOwn(props, 'css')) { + if (!hasOwn(props, 'css')) { return ReactJSXRuntime.jsxs(type, props, key) } diff --git a/packages/react/src/jsx.js b/packages/react/src/jsx.js index 9f66d9a766..70d4ac0d76 100644 --- a/packages/react/src/jsx.js +++ b/packages/react/src/jsx.js @@ -1,6 +1,7 @@ // @flow import * as React from 'react' import Emotion, { createEmotionProps } from './emotion-element' +import { hasOwn } from './utils' // $FlowFixMe export const jsx: typeof React.createElement = function ( @@ -9,7 +10,7 @@ export const jsx: typeof React.createElement = function ( ) { let args = arguments - if (props == null || !Object.hasOwn(props, 'css')) { + if (props == null || !hasOwn(props, 'css')) { // $FlowFixMe return React.createElement.apply(undefined, args) } diff --git a/packages/react/src/utils.js b/packages/react/src/utils.js index a7d96af4ac..5e6260730e 100644 --- a/packages/react/src/utils.js +++ b/packages/react/src/utils.js @@ -1,2 +1,4 @@ // @flow export let isBrowser = typeof document !== 'undefined' + +export const hasOwn = Object.hasOwn