From 157743a8f618945a85365fcefa4c46f6a9fb56fd Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Thu, 8 Jul 2021 16:01:39 -0400 Subject: [PATCH] DevTools: Update named hooks match to use column number also This prevents edge cases where AST nodes are incorrectly matched. --- .eslintignore | 1 + .prettierignore | 1 + .../ComponentWithMultipleHooksPerLine.js | 24 +++++ .../src/__tests__/{ => __source__}/README.md | 0 .../__source__/__compiled__/bundle/index.js | 26 ++++- .../__compiled__/bundle/index.js.map | 2 +- .../ComponentWithMultipleHooksPerLine.js | 29 ++++++ .../ComponentWithMultipleHooksPerLine.js.map | 1 + .../__source__/__compiled__/external/index.js | 8 ++ .../__compiled__/external/index.js.map | 2 +- .../ComponentWithMultipleHooksPerLine.js | 29 ++++++ .../__source__/__compiled__/inline/index.js | 10 +- .../ComponentWithNamedCustomHooks.js | 31 ++++++ .../ComponentWithUnnamedCustomHooks.js | 29 ++++++ .../ComponentWithUseEffect.js | 19 ++++ .../ComponentWithUseReducer.js | 20 ++++ .../ComponentWithUseState.js | 20 ++++ .../__source__/__untransformed__/README.md | 1 + .../src/__tests__/__source__/index.js | 1 + .../src/__tests__/parseHookNames-test.js | 98 +++++++------------ .../react-devtools-extensions/src/astUtils.js | 24 ++++- .../src/parseHookNames.js | 20 ++-- scripts/jest/config.build-devtools.js | 1 + scripts/prettier/index.js | 1 + 24 files changed, 322 insertions(+), 76 deletions(-) create mode 100644 packages/react-devtools-extensions/src/__tests__/__source__/ComponentWithMultipleHooksPerLine.js rename packages/react-devtools-extensions/src/__tests__/{ => __source__}/README.md (100%) create mode 100644 packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/ComponentWithMultipleHooksPerLine.js create mode 100644 packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/ComponentWithMultipleHooksPerLine.js.map create mode 100644 packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/ComponentWithMultipleHooksPerLine.js create mode 100644 packages/react-devtools-extensions/src/__tests__/__source__/__untransformed__/ComponentWithNamedCustomHooks.js create mode 100644 packages/react-devtools-extensions/src/__tests__/__source__/__untransformed__/ComponentWithUnnamedCustomHooks.js create mode 100644 packages/react-devtools-extensions/src/__tests__/__source__/__untransformed__/ComponentWithUseEffect.js create mode 100644 packages/react-devtools-extensions/src/__tests__/__source__/__untransformed__/ComponentWithUseReducer.js create mode 100644 packages/react-devtools-extensions/src/__tests__/__source__/__untransformed__/ComponentWithUseState.js create mode 100644 packages/react-devtools-extensions/src/__tests__/__source__/__untransformed__/README.md diff --git a/.eslintignore b/.eslintignore index 2593400242b0a..215132a8225ed 100644 --- a/.eslintignore +++ b/.eslintignore @@ -21,6 +21,7 @@ packages/react-devtools-extensions/chrome/build packages/react-devtools-extensions/firefox/build packages/react-devtools-extensions/shared/build packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/ +packages/react-devtools-extensions/src/__tests__/__source__/__untransformed__/ packages/react-devtools-extensions/src/ErrorTesterCompiled.js packages/react-devtools-inline/dist packages/react-devtools-shell/dist diff --git a/.prettierignore b/.prettierignore index d944a5e628fa7..adf1716fd4fa8 100644 --- a/.prettierignore +++ b/.prettierignore @@ -3,6 +3,7 @@ packages/react-devtools-extensions/chrome/build packages/react-devtools-extensions/firefox/build packages/react-devtools-extensions/shared/build packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/ +packages/react-devtools-extensions/src/__tests__/__source__/__untransformed__/ packages/react-devtools-extensions/src/ErrorTesterCompiled.js packages/react-devtools-inline/dist packages/react-devtools-shell/dist diff --git a/packages/react-devtools-extensions/src/__tests__/__source__/ComponentWithMultipleHooksPerLine.js b/packages/react-devtools-extensions/src/__tests__/__source__/ComponentWithMultipleHooksPerLine.js new file mode 100644 index 0000000000000..4e9020a623495 --- /dev/null +++ b/packages/react-devtools-extensions/src/__tests__/__source__/ComponentWithMultipleHooksPerLine.js @@ -0,0 +1,24 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +import {createContext, useContext} from 'react'; + +const A = createContext(1); +const B = createContext(2); + +export function Component() { + const a1 = useContext(A); + const b1 = useContext(B); + + // eslint-disable-next-line one-var + const a2 = useContext(A), + b2 = useContext(B); + + return a1 + b1 + a2 + b2; +} diff --git a/packages/react-devtools-extensions/src/__tests__/README.md b/packages/react-devtools-extensions/src/__tests__/__source__/README.md similarity index 100% rename from packages/react-devtools-extensions/src/__tests__/README.md rename to packages/react-devtools-extensions/src/__tests__/__source__/README.md diff --git a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/bundle/index.js b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/bundle/index.js index 6bb598647662f..c88d8b701e963 100644 --- a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/bundle/index.js +++ b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/bundle/index.js @@ -71,7 +71,26 @@ function Component$1() { * * @flow */ +const A = /*#__PURE__*/React.createContext(1); +const B = /*#__PURE__*/React.createContext(2); function Component$2() { + const a1 = React.useContext(A); + const b1 = React.useContext(B); // eslint-disable-next-line one-var + + const a2 = React.useContext(A), + b2 = React.useContext(B); + return a1 + b1 + a2 + b2; +} + +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ +function Component$3() { const [count, setCount] = React.useState(0); return /*#__PURE__*/React__default.createElement("div", null, /*#__PURE__*/React__default.createElement("p", null, "You clicked ", count, " times"), /*#__PURE__*/React__default.createElement("button", { onClick: () => setCount(count + 1) @@ -86,7 +105,7 @@ function Component$2() { * * @flow */ -function Component$3() { +function Component$4() { const [count] = require('react').useState(0); return count; @@ -191,8 +210,9 @@ var ToDoList = /*#__PURE__*/Object.freeze({ exports.ComponentWithCustomHook = Component; exports.ComponentWithExternalCustomHooks = Component$1; -exports.Example = Component$2; -exports.InlineRequire = Component$3; +exports.ComponentWithMultipleHooksPerLine = Component$2; +exports.Example = Component$3; +exports.InlineRequire = Component$4; exports.ToDoList = ToDoList; exports.useTheme = useTheme; //# sourceMappingURL=index.js.map diff --git a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/bundle/index.js.map b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/bundle/index.js.map index 1a4fb620f9286..d614fadd7c4dc 100644 --- a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/bundle/index.js.map +++ b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/bundle/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sources":["../../ComponentWithCustomHook.js","../../useTheme.js","../../ComponentWithExternalCustomHooks.js","../../Example.js","../../InlineRequire.js","../../ToDoList.js"],"sourcesContent":["/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n */\n\nimport React, {useEffect, useState} from 'react';\n\nexport function Component() {\n const [count, setCount] = useState(0);\n const isDarkMode = useIsDarkMode();\n\n useEffect(() => {\n // ...\n }, []);\n\n const handleClick = () => setCount(count + 1);\n\n return (\n <>\n
Dark mode? {isDarkMode}
\n
Count: {count}
\n \n \n );\n}\n\nfunction useIsDarkMode() {\n const [isDarkMode] = useState(false);\n\n useEffect(function useEffectCreate() {\n // Here is where we may listen to a \"theme\" event...\n }, []);\n\n return isDarkMode;\n}\n","/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n */\n\nimport {createContext, useContext, useDebugValue} from 'react';\n\nexport const ThemeContext = createContext('bright');\n\nexport default function useTheme() {\n const theme = useContext(ThemeContext);\n useDebugValue(theme);\n return theme;\n}\n","/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n */\n\nimport React from 'react';\nimport useTheme from './useTheme';\n\nexport function Component() {\n const theme = useTheme();\n\n return
theme: {theme}
;\n}\n","/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n */\n\nimport React, {useState} from 'react';\n\nexport function Component() {\n const [count, setCount] = useState(0);\n\n return (\n
\n

You clicked {count} times

\n \n
\n );\n}\n","/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n */\n\nexport function Component() {\n const [count] = require('react').useState(0);\n\n return count;\n}\n","/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n */\n\nimport * as React from 'react';\nimport {Fragment, useCallback, useState} from 'react';\n\nexport function ListItem({item, removeItem, toggleItem}) {\n const handleDelete = useCallback(() => {\n removeItem(item);\n }, [item, removeItem]);\n\n const handleToggle = useCallback(() => {\n toggleItem(item);\n }, [item, toggleItem]);\n\n return (\n
  • \n \n \n
  • \n );\n}\n\nexport function List(props) {\n const [newItemText, setNewItemText] = useState('');\n const [items, setItems] = useState([\n {id: 1, isComplete: true, text: 'First'},\n {id: 2, isComplete: true, text: 'Second'},\n {id: 3, isComplete: false, text: 'Third'},\n ]);\n const [uid, setUID] = useState(4);\n\n const handleClick = useCallback(() => {\n if (newItemText !== '') {\n setItems([\n ...items,\n {\n id: uid,\n isComplete: false,\n text: newItemText,\n },\n ]);\n setUID(uid + 1);\n setNewItemText('');\n }\n }, [newItemText, items, uid]);\n\n const handleKeyPress = useCallback(\n event => {\n if (event.key === 'Enter') {\n handleClick();\n }\n },\n [handleClick],\n );\n\n const handleChange = useCallback(\n event => {\n setNewItemText(event.currentTarget.value);\n },\n [setNewItemText],\n );\n\n const removeItem = useCallback(\n itemToRemove => setItems(items.filter(item => item !== itemToRemove)),\n [items],\n );\n\n const toggleItem = useCallback(\n itemToToggle => {\n // Dont use indexOf()\n // because editing props in DevTools creates a new Object.\n const index = items.findIndex(item => item.id === itemToToggle.id);\n\n setItems(\n items\n .slice(0, index)\n .concat({\n ...itemToToggle,\n isComplete: !itemToToggle.isComplete,\n })\n .concat(items.slice(index + 1)),\n );\n },\n [items],\n );\n\n return (\n \n

    List

    \n \n \n
      \n {items.map(item => (\n \n ))}\n
    \n
    \n );\n}\n"],"names":["Component","count","setCount","useState","isDarkMode","useIsDarkMode","useEffect","handleClick","React","useEffectCreate","ThemeContext","createContext","useTheme","theme","useContext","useDebugValue","require","ListItem","item","removeItem","toggleItem","handleDelete","useCallback","handleToggle","React.createElement","isComplete","text","List","props","newItemText","setNewItemText","items","setItems","id","uid","setUID","handleKeyPress","event","key","handleChange","currentTarget","value","itemToRemove","filter","itemToToggle","index","findIndex","slice","concat","Fragment","map"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.js","sources":["../../ComponentWithCustomHook.js","../../useTheme.js","../../ComponentWithExternalCustomHooks.js","../../ComponentWithMultipleHooksPerLine.js","../../Example.js","../../InlineRequire.js","../../ToDoList.js"],"sourcesContent":["/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n */\n\nimport React, {useEffect, useState} from 'react';\n\nexport function Component() {\n const [count, setCount] = useState(0);\n const isDarkMode = useIsDarkMode();\n\n useEffect(() => {\n // ...\n }, []);\n\n const handleClick = () => setCount(count + 1);\n\n return (\n <>\n
    Dark mode? {isDarkMode}
    \n
    Count: {count}
    \n \n \n );\n}\n\nfunction useIsDarkMode() {\n const [isDarkMode] = useState(false);\n\n useEffect(function useEffectCreate() {\n // Here is where we may listen to a \"theme\" event...\n }, []);\n\n return isDarkMode;\n}\n","/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n */\n\nimport {createContext, useContext, useDebugValue} from 'react';\n\nexport const ThemeContext = createContext('bright');\n\nexport default function useTheme() {\n const theme = useContext(ThemeContext);\n useDebugValue(theme);\n return theme;\n}\n","/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n */\n\nimport React from 'react';\nimport useTheme from './useTheme';\n\nexport function Component() {\n const theme = useTheme();\n\n return
    theme: {theme}
    ;\n}\n","/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n */\n\nimport {createContext, useContext} from 'react';\n\nconst A = createContext(1);\nconst B = createContext(2);\n\nexport function Component() {\n const a1 = useContext(A);\n const b1 = useContext(B);\n\n // eslint-disable-next-line one-var\n const a2 = useContext(A),\n b2 = useContext(B);\n\n return a1 + b1 + a2 + b2;\n}\n","/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n */\n\nimport React, {useState} from 'react';\n\nexport function Component() {\n const [count, setCount] = useState(0);\n\n return (\n
    \n

    You clicked {count} times

    \n \n
    \n );\n}\n","/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n */\n\nexport function Component() {\n const [count] = require('react').useState(0);\n\n return count;\n}\n","/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n */\n\nimport * as React from 'react';\nimport {Fragment, useCallback, useState} from 'react';\n\nexport function ListItem({item, removeItem, toggleItem}) {\n const handleDelete = useCallback(() => {\n removeItem(item);\n }, [item, removeItem]);\n\n const handleToggle = useCallback(() => {\n toggleItem(item);\n }, [item, toggleItem]);\n\n return (\n
  • \n \n \n
  • \n );\n}\n\nexport function List(props) {\n const [newItemText, setNewItemText] = useState('');\n const [items, setItems] = useState([\n {id: 1, isComplete: true, text: 'First'},\n {id: 2, isComplete: true, text: 'Second'},\n {id: 3, isComplete: false, text: 'Third'},\n ]);\n const [uid, setUID] = useState(4);\n\n const handleClick = useCallback(() => {\n if (newItemText !== '') {\n setItems([\n ...items,\n {\n id: uid,\n isComplete: false,\n text: newItemText,\n },\n ]);\n setUID(uid + 1);\n setNewItemText('');\n }\n }, [newItemText, items, uid]);\n\n const handleKeyPress = useCallback(\n event => {\n if (event.key === 'Enter') {\n handleClick();\n }\n },\n [handleClick],\n );\n\n const handleChange = useCallback(\n event => {\n setNewItemText(event.currentTarget.value);\n },\n [setNewItemText],\n );\n\n const removeItem = useCallback(\n itemToRemove => setItems(items.filter(item => item !== itemToRemove)),\n [items],\n );\n\n const toggleItem = useCallback(\n itemToToggle => {\n // Dont use indexOf()\n // because editing props in DevTools creates a new Object.\n const index = items.findIndex(item => item.id === itemToToggle.id);\n\n setItems(\n items\n .slice(0, index)\n .concat({\n ...itemToToggle,\n isComplete: !itemToToggle.isComplete,\n })\n .concat(items.slice(index + 1)),\n );\n },\n [items],\n );\n\n return (\n \n

    List

    \n \n \n
      \n {items.map(item => (\n \n ))}\n
    \n
    \n );\n}\n"],"names":["Component","count","setCount","useState","isDarkMode","useIsDarkMode","useEffect","handleClick","React","useEffectCreate","ThemeContext","createContext","useTheme","theme","useContext","useDebugValue","A","B","a1","b1","a2","b2","require","ListItem","item","removeItem","toggleItem","handleDelete","useCallback","handleToggle","React.createElement","isComplete","text","List","props","newItemText","setNewItemText","items","setItems","id","uid","setUID","handleKeyPress","event","key","handleChange","currentTarget","value","itemToRemove","filter","itemToToggle","index","findIndex","slice","concat","Fragment","map"],"mappings":";;;;;;;;;AAAA;;;;;;;;AAWO,SAASA,SAAT,GAAqB;AAC1B,QAAM,CAACC,KAAD,EAAQC,QAAR,IAAoBC,cAAQ,CAAC,CAAD,CAAlC;AACA,QAAMC,UAAU,GAAGC,aAAa,EAAhC;AAEAC,EAAAA,eAAS,CAAC,MAAM;AAEf,GAFQ,EAEN,EAFM,CAAT;;AAIA,QAAMC,WAAW,GAAG,MAAML,QAAQ,CAACD,KAAK,GAAG,CAAT,CAAlC;;AAEA,sBACEO,yEACEA,yDAAiBJ,UAAjB,CADF,eAEEI,qDAAaP,KAAb,CAFF,eAGEO;AAAQ,IAAA,OAAO,EAAED;AAAjB,oBAHF,CADF;AAOD;;AAED,SAASF,aAAT,GAAyB;AACvB,QAAM,CAACD,UAAD,IAAeD,cAAQ,CAAC,KAAD,CAA7B;AAEAG,EAAAA,eAAS,CAAC,SAASG,eAAT,GAA2B;AAEpC,GAFQ,EAEN,EAFM,CAAT;AAIA,SAAOL,UAAP;AACD;;ACtCD;;;;;;;;AASA,AAEO,MAAMM,YAAY,gBAAGC,mBAAa,CAAC,QAAD,CAAlC;AAEP,AAAe,SAASC,QAAT,GAAoB;AACjC,QAAMC,KAAK,GAAGC,gBAAU,CAACJ,YAAD,CAAxB;AACAK,EAAAA,mBAAa,CAACF,KAAD,CAAb;AACA,SAAOA,KAAP;AACD;;ACjBD;;;;;;;;AASA,AAGO,SAASb,WAAT,GAAqB;AAC1B,QAAMa,KAAK,GAAGD,QAAQ,EAAtB;AAEA,sBAAOJ,qDAAaK,KAAb,CAAP;AACD;;AChBD;;;;;;;;AASA,AAEA,MAAMG,CAAC,gBAAGL,mBAAa,CAAC,CAAD,CAAvB;AACA,MAAMM,CAAC,gBAAGN,mBAAa,CAAC,CAAD,CAAvB;AAEA,AAAO,SAASX,WAAT,GAAqB;AAC1B,QAAMkB,EAAE,GAAGJ,gBAAU,CAACE,CAAD,CAArB;AACA,QAAMG,EAAE,GAAGL,gBAAU,CAACG,CAAD,CAArB,CAF0B;;AAK1B,QAAMG,EAAE,GAAGN,gBAAU,CAACE,CAAD,CAArB;AAAA,QACEK,EAAE,GAAGP,gBAAU,CAACG,CAAD,CADjB;AAGA,SAAOC,EAAE,GAAGC,EAAL,GAAUC,EAAV,GAAeC,EAAtB;AACD;;ACvBD;;;;;;;;AASA,AAEO,SAASrB,WAAT,GAAqB;AAC1B,QAAM,CAACC,KAAD,EAAQC,QAAR,IAAoBC,cAAQ,CAAC,CAAD,CAAlC;AAEA,sBACEK,uDACEA,wDAAgBP,KAAhB,WADF,eAEEO;AAAQ,IAAA,OAAO,EAAE,MAAMN,QAAQ,CAACD,KAAK,GAAG,CAAT;AAA/B,gBAFF,CADF;AAMD;;ACpBD;;;;;;;;AASA,AAAO,SAASD,WAAT,GAAqB;AAC1B,QAAM,CAACC,KAAD,IAAUqB,OAAO,CAAC,OAAD,CAAP,CAAiBnB,QAAjB,CAA0B,CAA1B,CAAhB;;AAEA,SAAOF,KAAP;AACD;;ACbD;;;;;;;;AASA,AAGO,SAASsB,QAAT,CAAkB;AAACC,EAAAA,IAAD;AAAOC,EAAAA,UAAP;AAAmBC,EAAAA;AAAnB,CAAlB,EAAkD;AACvD,QAAMC,YAAY,GAAGC,iBAAW,CAAC,MAAM;AACrCH,IAAAA,UAAU,CAACD,IAAD,CAAV;AACD,GAF+B,EAE7B,CAACA,IAAD,EAAOC,UAAP,CAF6B,CAAhC;AAIA,QAAMI,YAAY,GAAGD,iBAAW,CAAC,MAAM;AACrCF,IAAAA,UAAU,CAACF,IAAD,CAAV;AACD,GAF+B,EAE7B,CAACA,IAAD,EAAOE,UAAP,CAF6B,CAAhC;AAIA,sBACEI,6CACEA;AAAQ,IAAA,OAAO,EAAEH;AAAjB,cADF,eAEEG,gDACEA;AACE,IAAA,OAAO,EAAEN,IAAI,CAACO,UADhB;AAEE,IAAA,QAAQ,EAAEF,YAFZ;AAGE,IAAA,IAAI,EAAC;AAHP,IADF,EAKK,GALL,EAMGL,IAAI,CAACQ,IANR,CAFF,CADF;AAaD;AAED,AAAO,SAASC,IAAT,CAAcC,KAAd,EAAqB;AAC1B,QAAM,CAACC,WAAD,EAAcC,cAAd,IAAgCjC,cAAQ,CAAC,EAAD,CAA9C;AACA,QAAM,CAACkC,KAAD,EAAQC,QAAR,IAAoBnC,cAAQ,CAAC,CACjC;AAACoC,IAAAA,EAAE,EAAE,CAAL;AAAQR,IAAAA,UAAU,EAAE,IAApB;AAA0BC,IAAAA,IAAI,EAAE;AAAhC,GADiC,EAEjC;AAACO,IAAAA,EAAE,EAAE,CAAL;AAAQR,IAAAA,UAAU,EAAE,IAApB;AAA0BC,IAAAA,IAAI,EAAE;AAAhC,GAFiC,EAGjC;AAACO,IAAAA,EAAE,EAAE,CAAL;AAAQR,IAAAA,UAAU,EAAE,KAApB;AAA2BC,IAAAA,IAAI,EAAE;AAAjC,GAHiC,CAAD,CAAlC;AAKA,QAAM,CAACQ,GAAD,EAAMC,MAAN,IAAgBtC,cAAQ,CAAC,CAAD,CAA9B;AAEA,QAAMI,WAAW,GAAGqB,iBAAW,CAAC,MAAM;AACpC,QAAIO,WAAW,KAAK,EAApB,EAAwB;AACtBG,MAAAA,QAAQ,CAAC,CACP,GAAGD,KADI,EAEP;AACEE,QAAAA,EAAE,EAAEC,GADN;AAEET,QAAAA,UAAU,EAAE,KAFd;AAGEC,QAAAA,IAAI,EAAEG;AAHR,OAFO,CAAD,CAAR;AAQAM,MAAAA,MAAM,CAACD,GAAG,GAAG,CAAP,CAAN;AACAJ,MAAAA,cAAc,CAAC,EAAD,CAAd;AACD;AACF,GAb8B,EAa5B,CAACD,WAAD,EAAcE,KAAd,EAAqBG,GAArB,CAb4B,CAA/B;AAeA,QAAME,cAAc,GAAGd,iBAAW,CAChCe,KAAK,IAAI;AACP,QAAIA,KAAK,CAACC,GAAN,KAAc,OAAlB,EAA2B;AACzBrC,MAAAA,WAAW;AACZ;AACF,GAL+B,EAMhC,CAACA,WAAD,CANgC,CAAlC;AASA,QAAMsC,YAAY,GAAGjB,iBAAW,CAC9Be,KAAK,IAAI;AACPP,IAAAA,cAAc,CAACO,KAAK,CAACG,aAAN,CAAoBC,KAArB,CAAd;AACD,GAH6B,EAI9B,CAACX,cAAD,CAJ8B,CAAhC;AAOA,QAAMX,UAAU,GAAGG,iBAAW,CAC5BoB,YAAY,IAAIV,QAAQ,CAACD,KAAK,CAACY,MAAN,CAAazB,IAAI,IAAIA,IAAI,KAAKwB,YAA9B,CAAD,CADI,EAE5B,CAACX,KAAD,CAF4B,CAA9B;AAKA,QAAMX,UAAU,GAAGE,iBAAW,CAC5BsB,YAAY,IAAI;AACd;AACA;AACA,UAAMC,KAAK,GAAGd,KAAK,CAACe,SAAN,CAAgB5B,IAAI,IAAIA,IAAI,CAACe,EAAL,KAAYW,YAAY,CAACX,EAAjD,CAAd;AAEAD,IAAAA,QAAQ,CACND,KAAK,CACFgB,KADH,CACS,CADT,EACYF,KADZ,EAEGG,MAFH,CAEU,EACN,GAAGJ,YADG;AAENnB,MAAAA,UAAU,EAAE,CAACmB,YAAY,CAACnB;AAFpB,KAFV,EAMGuB,MANH,CAMUjB,KAAK,CAACgB,KAAN,CAAYF,KAAK,GAAG,CAApB,CANV,CADM,CAAR;AASD,GAf2B,EAgB5B,CAACd,KAAD,CAhB4B,CAA9B;AAmBA,sBACEP,oBAACyB,cAAD,qBACEzB,uCADF,eAEEA;AACE,IAAA,IAAI,EAAC,MADP;AAEE,IAAA,WAAW,EAAC,kBAFd;AAGE,IAAA,KAAK,EAAEK,WAHT;AAIE,IAAA,QAAQ,EAAEU,YAJZ;AAKE,IAAA,UAAU,EAAEH;AALd,IAFF,eASEZ;AAAQ,IAAA,QAAQ,EAAEK,WAAW,KAAK,EAAlC;AAAsC,IAAA,OAAO,EAAE5B;AAA/C,kBACEuB;AAAM,IAAA,IAAI,EAAC,KAAX;AAAiB,kBAAW;AAA5B,WADF,CATF,eAcEA,gCACGO,KAAK,CAACmB,GAAN,CAAUhC,IAAI,iBACbM,oBAAC,QAAD;AACE,IAAA,GAAG,EAAEN,IAAI,CAACe,EADZ;AAEE,IAAA,IAAI,EAAEf,IAFR;AAGE,IAAA,UAAU,EAAEC,UAHd;AAIE,IAAA,UAAU,EAAEC;AAJd,IADD,CADH,CAdF,CADF;AA2BD;;;;;;;;;;;;;;;;"} \ No newline at end of file diff --git a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/ComponentWithMultipleHooksPerLine.js b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/ComponentWithMultipleHooksPerLine.js new file mode 100644 index 0000000000000..2ee3b4fb5fcbc --- /dev/null +++ b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/ComponentWithMultipleHooksPerLine.js @@ -0,0 +1,29 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.Component = Component; + +var _react = require("react"); + +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ +const A = /*#__PURE__*/(0, _react.createContext)(1); +const B = /*#__PURE__*/(0, _react.createContext)(2); + +function Component() { + const a1 = (0, _react.useContext)(A); + const b1 = (0, _react.useContext)(B); // eslint-disable-next-line one-var + + const a2 = (0, _react.useContext)(A), + b2 = (0, _react.useContext)(B); + return a1 + b1 + a2 + b2; +} +//# sourceMappingURL=ComponentWithMultipleHooksPerLine.js.map \ No newline at end of file diff --git a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/ComponentWithMultipleHooksPerLine.js.map b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/ComponentWithMultipleHooksPerLine.js.map new file mode 100644 index 0000000000000..9afd2792a2cab --- /dev/null +++ b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/ComponentWithMultipleHooksPerLine.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["ComponentWithMultipleHooksPerLine.js"],"names":["A","B","Component","a1","b1","a2","b2"],"mappings":";;;;;;;AASA;;AATA;;;;;;;;AAWA,MAAMA,CAAC,gBAAG,0BAAc,CAAd,CAAV;AACA,MAAMC,CAAC,gBAAG,0BAAc,CAAd,CAAV;;AAEO,SAASC,SAAT,GAAqB;AAC1B,QAAMC,EAAE,GAAG,uBAAWH,CAAX,CAAX;AACA,QAAMI,EAAE,GAAG,uBAAWH,CAAX,CAAX,CAF0B,CAI1B;;AACA,QAAMI,EAAE,GAAG,uBAAWL,CAAX,CAAX;AAAA,QACEM,EAAE,GAAG,uBAAWL,CAAX,CADP;AAGA,SAAOE,EAAE,GAAGC,EAAL,GAAUC,EAAV,GAAeC,EAAtB;AACD","sourcesContent":["/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n */\n\nimport {createContext, useContext} from 'react';\n\nconst A = createContext(1);\nconst B = createContext(2);\n\nexport function Component() {\n const a1 = useContext(A);\n const b1 = useContext(B);\n\n // eslint-disable-next-line one-var\n const a2 = useContext(A),\n b2 = useContext(B);\n\n return a1 + b1 + a2 + b2;\n}\n"]} \ No newline at end of file diff --git a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/index.js b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/index.js index 060a736cf1aba..e82ebfd746fd3 100644 --- a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/index.js +++ b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/index.js @@ -15,6 +15,12 @@ Object.defineProperty(exports, "ComponentWithExternalCustomHooks", { return _ComponentWithExternalCustomHooks.Component; } }); +Object.defineProperty(exports, "ComponentWithMultipleHooksPerLine", { + enumerable: true, + get: function () { + return _ComponentWithMultipleHooksPerLine.Component; + } +}); Object.defineProperty(exports, "Example", { enumerable: true, get: function () { @@ -39,6 +45,8 @@ var _ComponentWithCustomHook = require("./ComponentWithCustomHook"); var _ComponentWithExternalCustomHooks = require("./ComponentWithExternalCustomHooks"); +var _ComponentWithMultipleHooksPerLine = require("./ComponentWithMultipleHooksPerLine"); + var _Example = require("./Example"); var _InlineRequire = require("./InlineRequire"); diff --git a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/index.js.map b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/index.js.map index 0cd3aeaca0771..27dbc8d2296d2 100644 --- a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/index.js.map +++ b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/index.js.map @@ -1 +1 @@ -{"version":3,"sources":["index.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AASA;;AACA;;AACA;;AACA;;AACA;;;;AAEA","sourcesContent":["/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n */\n\nexport {Component as ComponentWithCustomHook} from './ComponentWithCustomHook';\nexport {Component as ComponentWithExternalCustomHooks} from './ComponentWithExternalCustomHooks';\nexport {Component as Example} from './Example';\nexport {Component as InlineRequire} from './InlineRequire';\nimport * as ToDoList from './ToDoList';\nexport {ToDoList};\nexport {default as useTheme} from './useTheme';\n"]} \ No newline at end of file +{"version":3,"sources":["index.js"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AASA;;AACA;;AACA;;AACA;;AACA;;AACA;;;;AAEA","sourcesContent":["/**\n * Copyright (c) Facebook, Inc. and its affiliates.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n *\n * @flow\n */\n\nexport {Component as ComponentWithCustomHook} from './ComponentWithCustomHook';\nexport {Component as ComponentWithExternalCustomHooks} from './ComponentWithExternalCustomHooks';\nexport {Component as ComponentWithMultipleHooksPerLine} from './ComponentWithMultipleHooksPerLine';\nexport {Component as Example} from './Example';\nexport {Component as InlineRequire} from './InlineRequire';\nimport * as ToDoList from './ToDoList';\nexport {ToDoList};\nexport {default as useTheme} from './useTheme';\n"]} \ No newline at end of file diff --git a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/ComponentWithMultipleHooksPerLine.js b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/ComponentWithMultipleHooksPerLine.js new file mode 100644 index 0000000000000..7d115b67f7369 --- /dev/null +++ b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/ComponentWithMultipleHooksPerLine.js @@ -0,0 +1,29 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.Component = Component; + +var _react = require("react"); + +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ +const A = /*#__PURE__*/(0, _react.createContext)(1); +const B = /*#__PURE__*/(0, _react.createContext)(2); + +function Component() { + const a1 = (0, _react.useContext)(A); + const b1 = (0, _react.useContext)(B); // eslint-disable-next-line one-var + + const a2 = (0, _react.useContext)(A), + b2 = (0, _react.useContext)(B); + return a1 + b1 + a2 + b2; +} +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIkNvbXBvbmVudFdpdGhNdWx0aXBsZUhvb2tzUGVyTGluZS5qcyJdLCJuYW1lcyI6WyJBIiwiQiIsIkNvbXBvbmVudCIsImExIiwiYjEiLCJhMiIsImIyIl0sIm1hcHBpbmdzIjoiOzs7Ozs7O0FBU0E7O0FBVEE7Ozs7Ozs7O0FBV0EsTUFBTUEsQ0FBQyxnQkFBRywwQkFBYyxDQUFkLENBQVY7QUFDQSxNQUFNQyxDQUFDLGdCQUFHLDBCQUFjLENBQWQsQ0FBVjs7QUFFTyxTQUFTQyxTQUFULEdBQXFCO0FBQzFCLFFBQU1DLEVBQUUsR0FBRyx1QkFBV0gsQ0FBWCxDQUFYO0FBQ0EsUUFBTUksRUFBRSxHQUFHLHVCQUFXSCxDQUFYLENBQVgsQ0FGMEIsQ0FJMUI7O0FBQ0EsUUFBTUksRUFBRSxHQUFHLHVCQUFXTCxDQUFYLENBQVg7QUFBQSxRQUNFTSxFQUFFLEdBQUcsdUJBQVdMLENBQVgsQ0FEUDtBQUdBLFNBQU9FLEVBQUUsR0FBR0MsRUFBTCxHQUFVQyxFQUFWLEdBQWVDLEVBQXRCO0FBQ0QiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIENvcHlyaWdodCAoYykgRmFjZWJvb2ssIEluYy4gYW5kIGl0cyBhZmZpbGlhdGVzLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLlxuICpcbiAqIEBmbG93XG4gKi9cblxuaW1wb3J0IHtjcmVhdGVDb250ZXh0LCB1c2VDb250ZXh0fSBmcm9tICdyZWFjdCc7XG5cbmNvbnN0IEEgPSBjcmVhdGVDb250ZXh0KDEpO1xuY29uc3QgQiA9IGNyZWF0ZUNvbnRleHQoMik7XG5cbmV4cG9ydCBmdW5jdGlvbiBDb21wb25lbnQoKSB7XG4gIGNvbnN0IGExID0gdXNlQ29udGV4dChBKTtcbiAgY29uc3QgYjEgPSB1c2VDb250ZXh0KEIpO1xuXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBvbmUtdmFyXG4gIGNvbnN0IGEyID0gdXNlQ29udGV4dChBKSxcbiAgICBiMiA9IHVzZUNvbnRleHQoQik7XG5cbiAgcmV0dXJuIGExICsgYjEgKyBhMiArIGIyO1xufVxuIl19 \ No newline at end of file diff --git a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/index.js b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/index.js index 429ebfbbcf6ce..60e56857a864b 100644 --- a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/index.js +++ b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/index.js @@ -15,6 +15,12 @@ Object.defineProperty(exports, "ComponentWithExternalCustomHooks", { return _ComponentWithExternalCustomHooks.Component; } }); +Object.defineProperty(exports, "ComponentWithMultipleHooksPerLine", { + enumerable: true, + get: function () { + return _ComponentWithMultipleHooksPerLine.Component; + } +}); Object.defineProperty(exports, "Example", { enumerable: true, get: function () { @@ -39,6 +45,8 @@ var _ComponentWithCustomHook = require("./ComponentWithCustomHook"); var _ComponentWithExternalCustomHooks = require("./ComponentWithExternalCustomHooks"); +var _ComponentWithMultipleHooksPerLine = require("./ComponentWithMultipleHooksPerLine"); + var _Example = require("./Example"); var _InlineRequire = require("./InlineRequire"); @@ -54,4 +62,4 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; } function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImluZGV4LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFTQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7OztBQUVBIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBDb3B5cmlnaHQgKGMpIEZhY2Vib29rLCBJbmMuIGFuZCBpdHMgYWZmaWxpYXRlcy5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS5cbiAqXG4gKiBAZmxvd1xuICovXG5cbmV4cG9ydCB7Q29tcG9uZW50IGFzIENvbXBvbmVudFdpdGhDdXN0b21Ib29rfSBmcm9tICcuL0NvbXBvbmVudFdpdGhDdXN0b21Ib29rJztcbmV4cG9ydCB7Q29tcG9uZW50IGFzIENvbXBvbmVudFdpdGhFeHRlcm5hbEN1c3RvbUhvb2tzfSBmcm9tICcuL0NvbXBvbmVudFdpdGhFeHRlcm5hbEN1c3RvbUhvb2tzJztcbmV4cG9ydCB7Q29tcG9uZW50IGFzIEV4YW1wbGV9IGZyb20gJy4vRXhhbXBsZSc7XG5leHBvcnQge0NvbXBvbmVudCBhcyBJbmxpbmVSZXF1aXJlfSBmcm9tICcuL0lubGluZVJlcXVpcmUnO1xuaW1wb3J0ICogYXMgVG9Eb0xpc3QgZnJvbSAnLi9Ub0RvTGlzdCc7XG5leHBvcnQge1RvRG9MaXN0fTtcbmV4cG9ydCB7ZGVmYXVsdCBhcyB1c2VUaGVtZX0gZnJvbSAnLi91c2VUaGVtZSc7XG4iXX0= \ No newline at end of file +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImluZGV4LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFTQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7OztBQUVBIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBDb3B5cmlnaHQgKGMpIEZhY2Vib29rLCBJbmMuIGFuZCBpdHMgYWZmaWxpYXRlcy5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS5cbiAqXG4gKiBAZmxvd1xuICovXG5cbmV4cG9ydCB7Q29tcG9uZW50IGFzIENvbXBvbmVudFdpdGhDdXN0b21Ib29rfSBmcm9tICcuL0NvbXBvbmVudFdpdGhDdXN0b21Ib29rJztcbmV4cG9ydCB7Q29tcG9uZW50IGFzIENvbXBvbmVudFdpdGhFeHRlcm5hbEN1c3RvbUhvb2tzfSBmcm9tICcuL0NvbXBvbmVudFdpdGhFeHRlcm5hbEN1c3RvbUhvb2tzJztcbmV4cG9ydCB7Q29tcG9uZW50IGFzIENvbXBvbmVudFdpdGhNdWx0aXBsZUhvb2tzUGVyTGluZX0gZnJvbSAnLi9Db21wb25lbnRXaXRoTXVsdGlwbGVIb29rc1BlckxpbmUnO1xuZXhwb3J0IHtDb21wb25lbnQgYXMgRXhhbXBsZX0gZnJvbSAnLi9FeGFtcGxlJztcbmV4cG9ydCB7Q29tcG9uZW50IGFzIElubGluZVJlcXVpcmV9IGZyb20gJy4vSW5saW5lUmVxdWlyZSc7XG5pbXBvcnQgKiBhcyBUb0RvTGlzdCBmcm9tICcuL1RvRG9MaXN0JztcbmV4cG9ydCB7VG9Eb0xpc3R9O1xuZXhwb3J0IHtkZWZhdWx0IGFzIHVzZVRoZW1lfSBmcm9tICcuL3VzZVRoZW1lJztcbiJdfQ== \ No newline at end of file diff --git a/packages/react-devtools-extensions/src/__tests__/__source__/__untransformed__/ComponentWithNamedCustomHooks.js b/packages/react-devtools-extensions/src/__tests__/__source__/__untransformed__/ComponentWithNamedCustomHooks.js new file mode 100644 index 0000000000000..d738b99923463 --- /dev/null +++ b/packages/react-devtools-extensions/src/__tests__/__source__/__untransformed__/ComponentWithNamedCustomHooks.js @@ -0,0 +1,31 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +const {useDebugValue, useState} = require('react'); + +function Component(props) { + const foo = useCustomHookOne(); + // This cae is ignored; + // the meaning of a tuple assignment for a custom hook is unclear. + const [bar] = useCustomHookTwo(); + return `${foo}-${bar}`; +} + +function useCustomHookOne() { + // DebugValue hook should not appear in log. + useDebugValue('example'); + return true; +} + +function useCustomHookTwo() { + const [baz, setBaz] = useState(true); + return [baz, setBaz]; +} + +module.exports = {Component}; \ No newline at end of file diff --git a/packages/react-devtools-extensions/src/__tests__/__source__/__untransformed__/ComponentWithUnnamedCustomHooks.js b/packages/react-devtools-extensions/src/__tests__/__source__/__untransformed__/ComponentWithUnnamedCustomHooks.js new file mode 100644 index 0000000000000..ee55f33d73a82 --- /dev/null +++ b/packages/react-devtools-extensions/src/__tests__/__source__/__untransformed__/ComponentWithUnnamedCustomHooks.js @@ -0,0 +1,29 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +const {useDebugValue} = require('react'); + +function Component(props) { + useCustomHookOne(); + const [bar] = useCustomHookTwo(); + return bar; +} + +function useCustomHookOne() { + // DebugValue hook should not appear in log. + useDebugValue('example'); +} + +function useCustomHookTwo() { + // DebugValue hook should not appear in log. + useDebugValue('example'); + return [true]; +} + +module.exports = {Component}; \ No newline at end of file diff --git a/packages/react-devtools-extensions/src/__tests__/__source__/__untransformed__/ComponentWithUseEffect.js b/packages/react-devtools-extensions/src/__tests__/__source__/__untransformed__/ComponentWithUseEffect.js new file mode 100644 index 0000000000000..ca1d30b1f39d0 --- /dev/null +++ b/packages/react-devtools-extensions/src/__tests__/__source__/__untransformed__/ComponentWithUseEffect.js @@ -0,0 +1,19 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +const React = require('react'); +const {useEffect} = React; + +function Component(props) { + useEffect(() => {}); + React.useLayoutEffect(() => () => {}); + return null; +} + +module.exports = {Component}; \ No newline at end of file diff --git a/packages/react-devtools-extensions/src/__tests__/__source__/__untransformed__/ComponentWithUseReducer.js b/packages/react-devtools-extensions/src/__tests__/__source__/__untransformed__/ComponentWithUseReducer.js new file mode 100644 index 0000000000000..7fed158224db6 --- /dev/null +++ b/packages/react-devtools-extensions/src/__tests__/__source__/__untransformed__/ComponentWithUseReducer.js @@ -0,0 +1,20 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +const React = require('react'); +const {useReducer} = React; + +function Component(props) { + const [foo] = useReducer(true); + const [bar] = useReducer(true); + const [baz] = React.useReducer(true); + return `${foo}-${bar}-${baz}`; +} + +module.exports = {Component}; \ No newline at end of file diff --git a/packages/react-devtools-extensions/src/__tests__/__source__/__untransformed__/ComponentWithUseState.js b/packages/react-devtools-extensions/src/__tests__/__source__/__untransformed__/ComponentWithUseState.js new file mode 100644 index 0000000000000..cf50881bd87b3 --- /dev/null +++ b/packages/react-devtools-extensions/src/__tests__/__source__/__untransformed__/ComponentWithUseState.js @@ -0,0 +1,20 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +const React = require('react'); +const {useState} = React; + +function Component(props) { + const [foo] = useState(true); + const bar = useState(true); + const [baz] = React.useState(true); + return `${foo}-${bar}-${baz}`; +} + +module.exports = {Component}; \ No newline at end of file diff --git a/packages/react-devtools-extensions/src/__tests__/__source__/__untransformed__/README.md b/packages/react-devtools-extensions/src/__tests__/__source__/__untransformed__/README.md new file mode 100644 index 0000000000000..1c88f7fa638cd --- /dev/null +++ b/packages/react-devtools-extensions/src/__tests__/__source__/__untransformed__/README.md @@ -0,0 +1 @@ +The JavaScript source files in this directory are not linted or pre-processed in any way. This is intentional, since they are used by the `parseHookNames-test` to test the behavior of "uncompiled" JavaScript (without source maps). \ No newline at end of file diff --git a/packages/react-devtools-extensions/src/__tests__/__source__/index.js b/packages/react-devtools-extensions/src/__tests__/__source__/index.js index a4f204fe19f9f..56d9683937e70 100644 --- a/packages/react-devtools-extensions/src/__tests__/__source__/index.js +++ b/packages/react-devtools-extensions/src/__tests__/__source__/index.js @@ -9,6 +9,7 @@ export {Component as ComponentWithCustomHook} from './ComponentWithCustomHook'; export {Component as ComponentWithExternalCustomHooks} from './ComponentWithExternalCustomHooks'; +export {Component as ComponentWithMultipleHooksPerLine} from './ComponentWithMultipleHooksPerLine'; export {Component as Example} from './Example'; export {Component as InlineRequire} from './InlineRequire'; import * as ToDoList from './ToDoList'; diff --git a/packages/react-devtools-extensions/src/__tests__/parseHookNames-test.js b/packages/react-devtools-extensions/src/__tests__/parseHookNames-test.js index e1efe7c32caaa..9be56d0a18e96 100644 --- a/packages/react-devtools-extensions/src/__tests__/parseHookNames-test.js +++ b/packages/react-devtools-extensions/src/__tests__/parseHookNames-test.js @@ -7,6 +7,10 @@ * @flow */ +// Note that this test uses React components declared in the "__source__" directory. +// This is done to control if and how the code is transformed at runtime. +// Do not declare test components within this test file as it is very fragile. + describe('parseHookNames', () => { let fetchMock; let inspectHooks; @@ -87,65 +91,29 @@ describe('parseHookNames', () => { } it('should parse names for useState()', async () => { - const React = require('react'); - const {useState} = React; - function Component(props) { - const [foo] = useState(true); - const bar = useState(true); - const [baz] = React.useState(true); - return `${foo}-${bar}-${baz}`; - } - + const Component = require('./__source__/__untransformed__/ComponentWithUseState') + .Component; const hookNames = await getHookNamesForComponent(Component); expectHookNamesToEqual(hookNames, ['foo', 'bar', 'baz']); }); it('should parse names for useReducer()', async () => { - const React = require('react'); - const {useReducer} = React; - function Component(props) { - const [foo] = useReducer(true); - const [bar] = useReducer(true); - const [baz] = React.useReducer(true); - return `${foo}-${bar}-${baz}`; - } - + const Component = require('./__source__/__untransformed__/ComponentWithUseReducer') + .Component; const hookNames = await getHookNamesForComponent(Component); expectHookNamesToEqual(hookNames, ['foo', 'bar', 'baz']); }); it('should return null for hooks without names like useEffect', async () => { - const React = require('react'); - const {useEffect} = React; - function Component(props) { - useEffect(() => {}); - React.useLayoutEffect(() => () => {}); - return null; - } - + const Component = require('./__source__/__untransformed__/ComponentWithUseEffect') + .Component; const hookNames = await getHookNamesForComponent(Component); expectHookNamesToEqual(hookNames, []); // No hooks with names }); it('should parse names for custom hooks', async () => { - const {useDebugValue, useState} = require('react'); - function useCustomHookOne() { - // DebugValue hook should not appear in log. - useDebugValue('example'); - return true; - } - function useCustomHookTwo() { - const [baz, setBaz] = useState(true); - return [baz, setBaz]; - } - function Component(props) { - const foo = useCustomHookOne(); - // This cae is ignored; - // the meaning of a tuple assignment for a custom hook is unclear. - const [bar] = useCustomHookTwo(); - return `${foo}-${bar}`; - } - + const Component = require('./__source__/__untransformed__/ComponentWithNamedCustomHooks') + .Component; const hookNames = await getHookNamesForComponent(Component); expectHookNamesToEqual(hookNames, [ 'foo', @@ -155,22 +123,8 @@ describe('parseHookNames', () => { }); it('should return null for custom hooks without explicit names', async () => { - const {useDebugValue} = require('react'); - function useCustomHookOne() { - // DebugValue hook should not appear in log. - useDebugValue('example'); - } - function useCustomHookTwo() { - // DebugValue hook should not appear in log. - useDebugValue('example'); - return [true]; - } - function Component(props) { - useCustomHookOne(); - const [bar] = useCustomHookTwo(); - return bar; - } - + const Component = require('./__source__/__untransformed__/ComponentWithUnnamedCustomHooks') + .Component; const hookNames = await getHookNamesForComponent(Component); expectHookNamesToEqual(hookNames, [ null, // Custom hooks can have names, but this one does not even return a value. @@ -267,6 +221,30 @@ describe('parseHookNames', () => { ); // bundle source map }); + it('should work when multiple hooks are on a line', async () => { + async function test(path, name = 'Component') { + const Component = require(path)[name]; + const hookNames = await getHookNamesForComponent(Component); + expectHookNamesToEqual(hookNames, [ + 'a1', // useContext() + 'b1', // useContext() + 'a2', // useContext() + 'b2', // useContext() + ]); + } + + await test( + './__source__/__compiled__/inline/ComponentWithMultipleHooksPerLine', + ); // inline source map + await test( + './__source__/__compiled__/external/ComponentWithMultipleHooksPerLine', + ); // external source map + await test( + './__source__/__compiled__/bundle', + 'ComponentWithMultipleHooksPerLine', + ); // bundle source map + }); + // TODO Inline require (e.g. require("react").useState()) isn't supported yet. // Maybe this isn't an important use case to support, // since inline requires are most likely to exist in compiled source (if at all). diff --git a/packages/react-devtools-extensions/src/astUtils.js b/packages/react-devtools-extensions/src/astUtils.js index dff938c9d3817..27fbb7a80a05d 100644 --- a/packages/react-devtools-extensions/src/astUtils.js +++ b/packages/react-devtools-extensions/src/astUtils.js @@ -29,9 +29,25 @@ const AST_NODE_TYPES = Object.freeze({ }); // Check if line number obtained from source map and the line number in hook node match -function checkNodeLocation(path: NodePath, line: number): boolean { +function checkNodeLocation( + path: NodePath, + line: number, + column: number, +): boolean { const {start, end} = path.node.loc; - return line >= start.line && line <= end.line; + + if (line < start.line || line > end.line) { + return false; + } + + if ( + (line === start.line && column < start.column) || + (line === end.line && column > end.column) + ) { + return false; + } + + return true; } // Checks whether hookNode is a member of targetHookNode @@ -91,13 +107,15 @@ export function getHookName( originalSourceAST: mixed, originalSourceCode: string, originalSourceLineNumber: number, + originalSourceColumnNumber: number, ): string | null { const hooksFromAST = getPotentialHookDeclarationsFromAST(originalSourceAST); const potentialReactHookASTNode = hooksFromAST.find(node => { const nodeLocationCheck = checkNodeLocation( node, - ((originalSourceLineNumber: any): number), + originalSourceLineNumber, + originalSourceColumnNumber, ); const hookDeclaractionCheck = isConfirmedHookDeclaration(node); return nodeLocationCheck && hookDeclaractionCheck; diff --git a/packages/react-devtools-extensions/src/parseHookNames.js b/packages/react-devtools-extensions/src/parseHookNames.js index 9336c5818ef16..d0be611d11b7c 100644 --- a/packages/react-devtools-extensions/src/parseHookNames.js +++ b/packages/react-devtools-extensions/src/parseHookNames.js @@ -376,32 +376,37 @@ function findHookNames( const sourceConsumer = hookSourceData.sourceConsumer; + let originalSourceColumnNumber; let originalSourceLineNumber; if (areSourceMapsAppliedToErrors() || !sourceConsumer) { // Either the current environment automatically applies source maps to errors, // or the current code had no source map to begin with. // Either way, we don't need to convert the Error stack frame locations. + originalSourceColumnNumber = columnNumber; originalSourceLineNumber = lineNumber; } else { - originalSourceLineNumber = sourceConsumer.originalPositionFor({ + const position = sourceConsumer.originalPositionFor({ line: lineNumber, // Column numbers are representated differently between tools/engines. // For more info see https://github.com/facebook/react/issues/21792#issuecomment-873171991 column: columnNumber - 1, - }).line; + }); + + originalSourceColumnNumber = position.column; + originalSourceLineNumber = position.line; } if (__DEBUG__) { console.log( - 'findHookNames() mapped line number', - lineNumber, - 'to', - originalSourceLineNumber, + `findHookNames() mapped line ${lineNumber}->${originalSourceLineNumber} and column ${columnNumber}->${originalSourceColumnNumber}`, ); } - if (originalSourceLineNumber === null) { + if ( + originalSourceLineNumber === null || + originalSourceColumnNumber === null + ) { return null; } @@ -410,6 +415,7 @@ function findHookNames( hookSourceData.originalSourceAST, ((hookSourceData.originalSourceCode: any): string), ((originalSourceLineNumber: any): number), + originalSourceColumnNumber, ); if (__DEBUG__) { diff --git a/scripts/jest/config.build-devtools.js b/scripts/jest/config.build-devtools.js index ed6a0b7db0f88..5108c61aa4027 100644 --- a/scripts/jest/config.build-devtools.js +++ b/scripts/jest/config.build-devtools.js @@ -59,6 +59,7 @@ module.exports = Object.assign({}, baseConfig, { '/node_modules/', '/build2/', '/__compiled__/', + '/__untransformed__/', ], testRegex: 'packages/react-devtools-(extensions|shared)/src/__tests__/[^]+.test.js$', diff --git a/scripts/prettier/index.js b/scripts/prettier/index.js index 0be3fefdca68e..18426b81f5b58 100644 --- a/scripts/prettier/index.js +++ b/scripts/prettier/index.js @@ -30,6 +30,7 @@ const files = glob '**/node_modules/**', '**/cjs/**', '**/__compiled__/**', + '**/__untransformed__/**', 'packages/react-devtools-extensions/src/ErrorTesterCompiled.js', ], })