diff --git a/packages/react-devtools-extensions/package.json b/packages/react-devtools-extensions/package.json
index 1949edbd023..40954c44251 100644
--- a/packages/react-devtools-extensions/package.json
+++ b/packages/react-devtools-extensions/package.json
@@ -19,6 +19,7 @@
"update-mock-source-maps": "node ./src/__tests__/updateMockSourceMaps.js"
},
"devDependencies": {
+ "acorn-jsx": "^5.2.0",
"@babel/core": "^7.11.1",
"@babel/plugin-proposal-class-properties": "^7.10.4",
"@babel/plugin-transform-flow-strip-types": "^7.10.4",
@@ -44,6 +45,10 @@
"open": "^7.0.2",
"os-name": "^3.1.0",
"raw-loader": "^3.1.0",
+ "rollup": "^1.19.4",
+ "rollup-plugin-babel": "^4.0.1",
+ "rollup-plugin-commonjs": "^9.3.4",
+ "rollup-plugin-node-resolve": "^2.1.1",
"source-map": "^0.8.0-beta.0",
"style-loader": "^0.23.1",
"web-ext": "^3.0.0",
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
new file mode 100644
index 00000000000..6bb59864766
--- /dev/null
+++ b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/bundle/index.js
@@ -0,0 +1,198 @@
+'use strict';
+
+Object.defineProperty(exports, '__esModule', { value: true });
+
+function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
+
+var React = require('react');
+var React__default = _interopDefault(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
+ */
+function Component() {
+ const [count, setCount] = React.useState(0);
+ const isDarkMode = useIsDarkMode();
+ React.useEffect(() => {// ...
+ }, []);
+
+ const handleClick = () => setCount(count + 1);
+
+ return /*#__PURE__*/React__default.createElement(React__default.Fragment, null, /*#__PURE__*/React__default.createElement("div", null, "Dark mode? ", isDarkMode), /*#__PURE__*/React__default.createElement("div", null, "Count: ", count), /*#__PURE__*/React__default.createElement("button", {
+ onClick: handleClick
+ }, "Update count"));
+}
+
+function useIsDarkMode() {
+ const [isDarkMode] = React.useState(false);
+ React.useEffect(function useEffectCreate() {// Here is where we may listen to a "theme" event...
+ }, []);
+ return isDarkMode;
+}
+
+/**
+ * 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 ThemeContext = /*#__PURE__*/React.createContext('bright');
+function useTheme() {
+ const theme = React.useContext(ThemeContext);
+ React.useDebugValue(theme);
+ return theme;
+}
+
+/**
+ * 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$1() {
+ const theme = useTheme();
+ return /*#__PURE__*/React__default.createElement("div", null, "theme: ", theme);
+}
+
+/**
+ * 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$2() {
+ 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)
+ }, "Click me"));
+}
+
+/**
+ * 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] = require('react').useState(0);
+
+ return count;
+}
+
+/**
+ * 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 ListItem({
+ item,
+ removeItem,
+ toggleItem
+}) {
+ const handleDelete = React.useCallback(() => {
+ removeItem(item);
+ }, [item, removeItem]);
+ const handleToggle = React.useCallback(() => {
+ toggleItem(item);
+ }, [item, toggleItem]);
+ return /*#__PURE__*/React.createElement("li", null, /*#__PURE__*/React.createElement("button", {
+ onClick: handleDelete
+ }, "Delete"), /*#__PURE__*/React.createElement("label", null, /*#__PURE__*/React.createElement("input", {
+ checked: item.isComplete,
+ onChange: handleToggle,
+ type: "checkbox"
+ }), ' ', item.text));
+}
+function List(props) {
+ const [newItemText, setNewItemText] = React.useState('');
+ const [items, setItems] = React.useState([{
+ id: 1,
+ isComplete: true,
+ text: 'First'
+ }, {
+ id: 2,
+ isComplete: true,
+ text: 'Second'
+ }, {
+ id: 3,
+ isComplete: false,
+ text: 'Third'
+ }]);
+ const [uid, setUID] = React.useState(4);
+ const handleClick = React.useCallback(() => {
+ if (newItemText !== '') {
+ setItems([...items, {
+ id: uid,
+ isComplete: false,
+ text: newItemText
+ }]);
+ setUID(uid + 1);
+ setNewItemText('');
+ }
+ }, [newItemText, items, uid]);
+ const handleKeyPress = React.useCallback(event => {
+ if (event.key === 'Enter') {
+ handleClick();
+ }
+ }, [handleClick]);
+ const handleChange = React.useCallback(event => {
+ setNewItemText(event.currentTarget.value);
+ }, [setNewItemText]);
+ const removeItem = React.useCallback(itemToRemove => setItems(items.filter(item => item !== itemToRemove)), [items]);
+ const toggleItem = React.useCallback(itemToToggle => {
+ // Dont use indexOf()
+ // because editing props in DevTools creates a new Object.
+ const index = items.findIndex(item => item.id === itemToToggle.id);
+ setItems(items.slice(0, index).concat({ ...itemToToggle,
+ isComplete: !itemToToggle.isComplete
+ }).concat(items.slice(index + 1)));
+ }, [items]);
+ return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("h1", null, "List"), /*#__PURE__*/React.createElement("input", {
+ type: "text",
+ placeholder: "New list item...",
+ value: newItemText,
+ onChange: handleChange,
+ onKeyPress: handleKeyPress
+ }), /*#__PURE__*/React.createElement("button", {
+ disabled: newItemText === '',
+ onClick: handleClick
+ }, /*#__PURE__*/React.createElement("span", {
+ role: "img",
+ "aria-label": "Add item"
+ }, "Add")), /*#__PURE__*/React.createElement("ul", null, items.map(item => /*#__PURE__*/React.createElement(ListItem, {
+ key: item.id,
+ item: item,
+ removeItem: removeItem,
+ toggleItem: toggleItem
+ }))));
+}
+
+var ToDoList = /*#__PURE__*/Object.freeze({
+ __proto__: null,
+ ListItem: ListItem,
+ List: List
+});
+
+exports.ComponentWithCustomHook = Component;
+exports.ComponentWithExternalCustomHooks = Component$1;
+exports.Example = Component$2;
+exports.InlineRequire = Component$3;
+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
new file mode 100644
index 00000000000..1a4fb620f92
--- /dev/null
+++ b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/bundle/index.js.map
@@ -0,0 +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"],"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
diff --git a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/ComponentWithCustomHook.js b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/ComponentWithCustomHook.js
index f76a1acedb8..e326d7a4962 100644
--- a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/ComponentWithCustomHook.js
+++ b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/ComponentWithCustomHook.js
@@ -33,10 +33,9 @@ function Component() {
}
function useIsDarkMode() {
- const [isDarkMode, setIsDarkMode] = (0, _react.useState)(0);
+ const [isDarkMode] = (0, _react.useState)(false);
(0, _react.useEffect)(function useEffectCreate() {// Here is where we may listen to a "theme" event...
}, []);
return isDarkMode;
}
-//# sourceMappingURL=ComponentWithCustomHook.js.map
-//# sourceURL=ComponentWithCustomHook.js
\ No newline at end of file
+//# sourceMappingURL=ComponentWithCustomHook.js.map
\ No newline at end of file
diff --git a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/ComponentWithCustomHook.js.map b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/ComponentWithCustomHook.js.map
index ac54e5738f9..3ebcb084abc 100644
--- a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/ComponentWithCustomHook.js.map
+++ b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/ComponentWithCustomHook.js.map
@@ -1 +1 @@
-{"version":3,"sources":["ComponentWithCustomHook.js"],"names":["Component","count","setCount","isDarkMode","useIsDarkMode","handleClick","setIsDarkMode","useEffectCreate"],"mappings":";;;;;;;AASA;;;;;;AATA;;;;;;;;AAWO,SAASA,SAAT,GAAqB;AAC1B,QAAM,CAACC,KAAD,EAAQC,QAAR,IAAoB,qBAAS,CAAT,CAA1B;AACA,QAAMC,UAAU,GAAGC,aAAa,EAAhC;AAEA,wBAAU,MAAM,CACd;AACD,GAFD,EAEG,EAFH;;AAIA,QAAMC,WAAW,GAAG,MAAMH,QAAQ,CAACD,KAAK,GAAG,CAAT,CAAlC;;AAEA,sBACE,yEACE,yDAAiBE,UAAjB,CADF,eAEE,qDAAaF,KAAb,CAFF,eAGE;AAAQ,IAAA,OAAO,EAAEI;AAAjB,oBAHF,CADF;AAOD;;AAED,SAASD,aAAT,GAAyB;AACvB,QAAM,CAACD,UAAD,EAAaG,aAAb,IAA8B,qBAAS,CAAT,CAApC;AAEA,wBAAU,SAASC,eAAT,GAA2B,CACnC;AACD,GAFD,EAEG,EAFH;AAIA,SAAOJ,UAAP;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 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, setIsDarkMode] = useState(0);\n\n useEffect(function useEffectCreate() {\n // Here is where we may listen to a \"theme\" event...\n }, []);\n\n return isDarkMode;\n}"]}
\ No newline at end of file
+{"version":3,"sources":["ComponentWithCustomHook.js"],"names":["Component","count","setCount","isDarkMode","useIsDarkMode","handleClick","useEffectCreate"],"mappings":";;;;;;;AASA;;;;;;AATA;;;;;;;;AAWO,SAASA,SAAT,GAAqB;AAC1B,QAAM,CAACC,KAAD,EAAQC,QAAR,IAAoB,qBAAS,CAAT,CAA1B;AACA,QAAMC,UAAU,GAAGC,aAAa,EAAhC;AAEA,wBAAU,MAAM,CACd;AACD,GAFD,EAEG,EAFH;;AAIA,QAAMC,WAAW,GAAG,MAAMH,QAAQ,CAACD,KAAK,GAAG,CAAT,CAAlC;;AAEA,sBACE,yEACE,yDAAiBE,UAAjB,CADF,eAEE,qDAAaF,KAAb,CAFF,eAGE;AAAQ,IAAA,OAAO,EAAEI;AAAjB,oBAHF,CADF;AAOD;;AAED,SAASD,aAAT,GAAyB;AACvB,QAAM,CAACD,UAAD,IAAe,qBAAS,KAAT,CAArB;AAEA,wBAAU,SAASG,eAAT,GAA2B,CACnC;AACD,GAFD,EAEG,EAFH;AAIA,SAAOH,UAAP;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 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"]}
\ No newline at end of file
diff --git a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/ComponentWithExternalCustomHooks.js b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/ComponentWithExternalCustomHooks.js
index dbdc0b3ade5..05aedb938b7 100644
--- a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/ComponentWithExternalCustomHooks.js
+++ b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/ComponentWithExternalCustomHooks.js
@@ -23,5 +23,4 @@ function Component() {
const theme = (0, _useTheme.default)();
return /*#__PURE__*/_react.default.createElement("div", null, "theme: ", theme);
}
-//# sourceMappingURL=ComponentWithExternalCustomHooks.js.map
-//# sourceURL=ComponentWithExternalCustomHooks.js
\ No newline at end of file
+//# sourceMappingURL=ComponentWithExternalCustomHooks.js.map
\ No newline at end of file
diff --git a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/Example.js b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/Example.js
index b51d2b2c843..19134738824 100644
--- a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/Example.js
+++ b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/Example.js
@@ -25,5 +25,4 @@ function Component() {
onClick: () => setCount(count + 1)
}, "Click me"));
}
-//# sourceMappingURL=Example.js.map
-//# sourceURL=Example.js
\ No newline at end of file
+//# sourceMappingURL=Example.js.map
\ No newline at end of file
diff --git a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/InlineRequire.js b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/InlineRequire.js
index 4d025dab585..388aeda62b3 100644
--- a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/InlineRequire.js
+++ b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/InlineRequire.js
@@ -18,5 +18,4 @@ function Component() {
return count;
}
-//# sourceMappingURL=InlineRequire.js.map
-//# sourceURL=InlineRequire.js
\ No newline at end of file
+//# sourceMappingURL=InlineRequire.js.map
\ No newline at end of file
diff --git a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/ToDoList.js b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/ToDoList.js
index d9cca2b089c..a6eb863b661 100644
--- a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/ToDoList.js
+++ b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/ToDoList.js
@@ -103,5 +103,4 @@ function List(props) {
toggleItem: toggleItem
}))));
}
-//# sourceMappingURL=ToDoList.js.map
-//# sourceURL=ToDoList.js
\ No newline at end of file
+//# sourceMappingURL=ToDoList.js.map
\ 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
new file mode 100644
index 00000000000..060a736cf1a
--- /dev/null
+++ b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/index.js
@@ -0,0 +1,57 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+Object.defineProperty(exports, "ComponentWithCustomHook", {
+ enumerable: true,
+ get: function () {
+ return _ComponentWithCustomHook.Component;
+ }
+});
+Object.defineProperty(exports, "ComponentWithExternalCustomHooks", {
+ enumerable: true,
+ get: function () {
+ return _ComponentWithExternalCustomHooks.Component;
+ }
+});
+Object.defineProperty(exports, "Example", {
+ enumerable: true,
+ get: function () {
+ return _Example.Component;
+ }
+});
+Object.defineProperty(exports, "InlineRequire", {
+ enumerable: true,
+ get: function () {
+ return _InlineRequire.Component;
+ }
+});
+Object.defineProperty(exports, "useTheme", {
+ enumerable: true,
+ get: function () {
+ return _useTheme.default;
+ }
+});
+exports.ToDoList = void 0;
+
+var _ComponentWithCustomHook = require("./ComponentWithCustomHook");
+
+var _ComponentWithExternalCustomHooks = require("./ComponentWithExternalCustomHooks");
+
+var _Example = require("./Example");
+
+var _InlineRequire = require("./InlineRequire");
+
+var ToDoList = _interopRequireWildcard(require("./ToDoList"));
+
+exports.ToDoList = ToDoList;
+
+var _useTheme = _interopRequireDefault(require("./useTheme"));
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+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=index.js.map
\ No newline at end of file
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
new file mode 100644
index 00000000000..0cd3aeaca07
--- /dev/null
+++ b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/index.js.map
@@ -0,0 +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
diff --git a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/useTheme.js b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/useTheme.js
index b32aa123308..95bb454253e 100644
--- a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/useTheme.js
+++ b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/external/useTheme.js
@@ -24,5 +24,4 @@ function useTheme() {
(0, _react.useDebugValue)(theme);
return theme;
}
-//# sourceMappingURL=useTheme.js.map
-//# sourceURL=useTheme.js
\ No newline at end of file
+//# sourceMappingURL=useTheme.js.map
\ No newline at end of file
diff --git a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/ComponentWithCustomHook.js b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/ComponentWithCustomHook.js
index 85ac8a37c89..a382725a538 100644
--- a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/ComponentWithCustomHook.js
+++ b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/ComponentWithCustomHook.js
@@ -33,10 +33,9 @@ function Component() {
}
function useIsDarkMode() {
- const [isDarkMode, setIsDarkMode] = (0, _react.useState)(0);
+ const [isDarkMode] = (0, _react.useState)(false);
(0, _react.useEffect)(function useEffectCreate() {// Here is where we may listen to a "theme" event...
}, []);
return isDarkMode;
}
-//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIkNvbXBvbmVudFdpdGhDdXN0b21Ib29rLmpzIl0sIm5hbWVzIjpbIkNvbXBvbmVudCIsImNvdW50Iiwic2V0Q291bnQiLCJpc0RhcmtNb2RlIiwidXNlSXNEYXJrTW9kZSIsImhhbmRsZUNsaWNrIiwic2V0SXNEYXJrTW9kZSIsInVzZUVmZmVjdENyZWF0ZSJdLCJtYXBwaW5ncyI6Ijs7Ozs7OztBQVNBOzs7Ozs7QUFUQTs7Ozs7Ozs7QUFXTyxTQUFTQSxTQUFULEdBQXFCO0FBQzFCLFFBQU0sQ0FBQ0MsS0FBRCxFQUFRQyxRQUFSLElBQW9CLHFCQUFTLENBQVQsQ0FBMUI7QUFDQSxRQUFNQyxVQUFVLEdBQUdDLGFBQWEsRUFBaEM7QUFFQSx3QkFBVSxNQUFNLENBQ2Q7QUFDRCxHQUZELEVBRUcsRUFGSDs7QUFJQSxRQUFNQyxXQUFXLEdBQUcsTUFBTUgsUUFBUSxDQUFDRCxLQUFLLEdBQUcsQ0FBVCxDQUFsQzs7QUFFQSxzQkFDRSx5RUFDRSx5REFBaUJFLFVBQWpCLENBREYsZUFFRSxxREFBYUYsS0FBYixDQUZGLGVBR0U7QUFBUSxJQUFBLE9BQU8sRUFBRUk7QUFBakIsb0JBSEYsQ0FERjtBQU9EOztBQUVELFNBQVNELGFBQVQsR0FBeUI7QUFDdkIsUUFBTSxDQUFDRCxVQUFELEVBQWFHLGFBQWIsSUFBOEIscUJBQVMsQ0FBVCxDQUFwQztBQUVBLHdCQUFVLFNBQVNDLGVBQVQsR0FBMkIsQ0FDbkM7QUFDRCxHQUZELEVBRUcsRUFGSDtBQUlBLFNBQU9KLFVBQVA7QUFDRCIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQ29weXJpZ2h0IChjKSBGYWNlYm9vaywgSW5jLiBhbmQgaXRzIGFmZmlsaWF0ZXMuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuXG4gKlxuICogQGZsb3dcbiAqL1xuXG5pbXBvcnQgUmVhY3QsIHt1c2VFZmZlY3QsIHVzZVN0YXRlfSBmcm9tICdyZWFjdCc7XG5cbmV4cG9ydCBmdW5jdGlvbiBDb21wb25lbnQoKSB7XG4gIGNvbnN0IFtjb3VudCwgc2V0Q291bnRdID0gdXNlU3RhdGUoMCk7XG4gIGNvbnN0IGlzRGFya01vZGUgPSB1c2VJc0RhcmtNb2RlKCk7XG5cbiAgdXNlRWZmZWN0KCgpID0+IHtcbiAgICAvLyAuLi5cbiAgfSwgW10pO1xuXG4gIGNvbnN0IGhhbmRsZUNsaWNrID0gKCkgPT4gc2V0Q291bnQoY291bnQgKyAxKTtcblxuICByZXR1cm4gKFxuICAgIDw+XG4gICAgICA8ZGl2PkRhcmsgbW9kZT8ge2lzRGFya01vZGV9PC9kaXY+XG4gICAgICA8ZGl2PkNvdW50OiB7Y291bnR9PC9kaXY+XG4gICAgICA8YnV0dG9uIG9uQ2xpY2s9e2hhbmRsZUNsaWNrfT5VcGRhdGUgY291bnQ8L2J1dHRvbj5cbiAgICA8Lz5cbiAgKTtcbn1cblxuZnVuY3Rpb24gdXNlSXNEYXJrTW9kZSgpIHtcbiAgY29uc3QgW2lzRGFya01vZGUsIHNldElzRGFya01vZGVdID0gdXNlU3RhdGUoMCk7XG5cbiAgdXNlRWZmZWN0KGZ1bmN0aW9uIHVzZUVmZmVjdENyZWF0ZSgpIHtcbiAgICAvLyBIZXJlIGlzIHdoZXJlIHdlIG1heSBsaXN0ZW4gdG8gYSBcInRoZW1lXCIgZXZlbnQuLi5cbiAgfSwgW10pO1xuXG4gIHJldHVybiBpc0RhcmtNb2RlO1xufSJdfQ==
-//# sourceURL=ComponentWithCustomHook.js
\ No newline at end of file
+//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIkNvbXBvbmVudFdpdGhDdXN0b21Ib29rLmpzIl0sIm5hbWVzIjpbIkNvbXBvbmVudCIsImNvdW50Iiwic2V0Q291bnQiLCJpc0RhcmtNb2RlIiwidXNlSXNEYXJrTW9kZSIsImhhbmRsZUNsaWNrIiwidXNlRWZmZWN0Q3JlYXRlIl0sIm1hcHBpbmdzIjoiOzs7Ozs7O0FBU0E7Ozs7OztBQVRBOzs7Ozs7OztBQVdPLFNBQVNBLFNBQVQsR0FBcUI7QUFDMUIsUUFBTSxDQUFDQyxLQUFELEVBQVFDLFFBQVIsSUFBb0IscUJBQVMsQ0FBVCxDQUExQjtBQUNBLFFBQU1DLFVBQVUsR0FBR0MsYUFBYSxFQUFoQztBQUVBLHdCQUFVLE1BQU0sQ0FDZDtBQUNELEdBRkQsRUFFRyxFQUZIOztBQUlBLFFBQU1DLFdBQVcsR0FBRyxNQUFNSCxRQUFRLENBQUNELEtBQUssR0FBRyxDQUFULENBQWxDOztBQUVBLHNCQUNFLHlFQUNFLHlEQUFpQkUsVUFBakIsQ0FERixlQUVFLHFEQUFhRixLQUFiLENBRkYsZUFHRTtBQUFRLElBQUEsT0FBTyxFQUFFSTtBQUFqQixvQkFIRixDQURGO0FBT0Q7O0FBRUQsU0FBU0QsYUFBVCxHQUF5QjtBQUN2QixRQUFNLENBQUNELFVBQUQsSUFBZSxxQkFBUyxLQUFULENBQXJCO0FBRUEsd0JBQVUsU0FBU0csZUFBVCxHQUEyQixDQUNuQztBQUNELEdBRkQsRUFFRyxFQUZIO0FBSUEsU0FBT0gsVUFBUDtBQUNEIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBDb3B5cmlnaHQgKGMpIEZhY2Vib29rLCBJbmMuIGFuZCBpdHMgYWZmaWxpYXRlcy5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS5cbiAqXG4gKiBAZmxvd1xuICovXG5cbmltcG9ydCBSZWFjdCwge3VzZUVmZmVjdCwgdXNlU3RhdGV9IGZyb20gJ3JlYWN0JztcblxuZXhwb3J0IGZ1bmN0aW9uIENvbXBvbmVudCgpIHtcbiAgY29uc3QgW2NvdW50LCBzZXRDb3VudF0gPSB1c2VTdGF0ZSgwKTtcbiAgY29uc3QgaXNEYXJrTW9kZSA9IHVzZUlzRGFya01vZGUoKTtcblxuICB1c2VFZmZlY3QoKCkgPT4ge1xuICAgIC8vIC4uLlxuICB9LCBbXSk7XG5cbiAgY29uc3QgaGFuZGxlQ2xpY2sgPSAoKSA9PiBzZXRDb3VudChjb3VudCArIDEpO1xuXG4gIHJldHVybiAoXG4gICAgPD5cbiAgICAgIDxkaXY+RGFyayBtb2RlPyB7aXNEYXJrTW9kZX08L2Rpdj5cbiAgICAgIDxkaXY+Q291bnQ6IHtjb3VudH08L2Rpdj5cbiAgICAgIDxidXR0b24gb25DbGljaz17aGFuZGxlQ2xpY2t9PlVwZGF0ZSBjb3VudDwvYnV0dG9uPlxuICAgIDwvPlxuICApO1xufVxuXG5mdW5jdGlvbiB1c2VJc0RhcmtNb2RlKCkge1xuICBjb25zdCBbaXNEYXJrTW9kZV0gPSB1c2VTdGF0ZShmYWxzZSk7XG5cbiAgdXNlRWZmZWN0KGZ1bmN0aW9uIHVzZUVmZmVjdENyZWF0ZSgpIHtcbiAgICAvLyBIZXJlIGlzIHdoZXJlIHdlIG1heSBsaXN0ZW4gdG8gYSBcInRoZW1lXCIgZXZlbnQuLi5cbiAgfSwgW10pO1xuXG4gIHJldHVybiBpc0RhcmtNb2RlO1xufVxuIl19
\ No newline at end of file
diff --git a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/ComponentWithExternalCustomHooks.js b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/ComponentWithExternalCustomHooks.js
index b9812467b7f..fc925fdd5c2 100644
--- a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/ComponentWithExternalCustomHooks.js
+++ b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/ComponentWithExternalCustomHooks.js
@@ -23,5 +23,4 @@ function Component() {
const theme = (0, _useTheme.default)();
return /*#__PURE__*/_react.default.createElement("div", null, "theme: ", theme);
}
-//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIkNvbXBvbmVudFdpdGhFeHRlcm5hbEN1c3RvbUhvb2tzLmpzIl0sIm5hbWVzIjpbIkNvbXBvbmVudCIsInRoZW1lIl0sIm1hcHBpbmdzIjoiOzs7Ozs7O0FBU0E7O0FBQ0E7Ozs7QUFWQTs7Ozs7Ozs7QUFZTyxTQUFTQSxTQUFULEdBQXFCO0FBQzFCLFFBQU1DLEtBQUssR0FBRyx3QkFBZDtBQUVBLHNCQUFPLHFEQUFhQSxLQUFiLENBQVA7QUFDRCIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQ29weXJpZ2h0IChjKSBGYWNlYm9vaywgSW5jLiBhbmQgaXRzIGFmZmlsaWF0ZXMuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuXG4gKlxuICogQGZsb3dcbiAqL1xuXG5pbXBvcnQgUmVhY3QgZnJvbSAncmVhY3QnO1xuaW1wb3J0IHVzZVRoZW1lIGZyb20gJy4vdXNlVGhlbWUnO1xuXG5leHBvcnQgZnVuY3Rpb24gQ29tcG9uZW50KCkge1xuICBjb25zdCB0aGVtZSA9IHVzZVRoZW1lKCk7XG5cbiAgcmV0dXJuIDxkaXY+dGhlbWU6IHt0aGVtZX08L2Rpdj47XG59XG4iXX0=
-//# sourceURL=ComponentWithExternalCustomHooks.js
\ No newline at end of file
+//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIkNvbXBvbmVudFdpdGhFeHRlcm5hbEN1c3RvbUhvb2tzLmpzIl0sIm5hbWVzIjpbIkNvbXBvbmVudCIsInRoZW1lIl0sIm1hcHBpbmdzIjoiOzs7Ozs7O0FBU0E7O0FBQ0E7Ozs7QUFWQTs7Ozs7Ozs7QUFZTyxTQUFTQSxTQUFULEdBQXFCO0FBQzFCLFFBQU1DLEtBQUssR0FBRyx3QkFBZDtBQUVBLHNCQUFPLHFEQUFhQSxLQUFiLENBQVA7QUFDRCIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQ29weXJpZ2h0IChjKSBGYWNlYm9vaywgSW5jLiBhbmQgaXRzIGFmZmlsaWF0ZXMuXG4gKlxuICogVGhpcyBzb3VyY2UgY29kZSBpcyBsaWNlbnNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UgZm91bmQgaW4gdGhlXG4gKiBMSUNFTlNFIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoaXMgc291cmNlIHRyZWUuXG4gKlxuICogQGZsb3dcbiAqL1xuXG5pbXBvcnQgUmVhY3QgZnJvbSAncmVhY3QnO1xuaW1wb3J0IHVzZVRoZW1lIGZyb20gJy4vdXNlVGhlbWUnO1xuXG5leHBvcnQgZnVuY3Rpb24gQ29tcG9uZW50KCkge1xuICBjb25zdCB0aGVtZSA9IHVzZVRoZW1lKCk7XG5cbiAgcmV0dXJuIDxkaXY+dGhlbWU6IHt0aGVtZX08L2Rpdj47XG59XG4iXX0=
\ No newline at end of file
diff --git a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/Example.js b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/Example.js
index ea6b7e4b988..1902dd97ec6 100644
--- a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/Example.js
+++ b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/Example.js
@@ -25,5 +25,4 @@ function Component() {
onClick: () => setCount(count + 1)
}, "Click me"));
}
-//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIkV4YW1wbGUuanMiXSwibmFtZXMiOlsiQ29tcG9uZW50IiwiY291bnQiLCJzZXRDb3VudCJdLCJtYXBwaW5ncyI6Ijs7Ozs7OztBQVNBOzs7Ozs7QUFUQTs7Ozs7Ozs7QUFXTyxTQUFTQSxTQUFULEdBQXFCO0FBQzFCLFFBQU0sQ0FBQ0MsS0FBRCxFQUFRQyxRQUFSLElBQW9CLHFCQUFTLENBQVQsQ0FBMUI7QUFFQSxzQkFDRSx1REFDRSx3REFBZ0JELEtBQWhCLFdBREYsZUFFRTtBQUFRLElBQUEsT0FBTyxFQUFFLE1BQU1DLFFBQVEsQ0FBQ0QsS0FBSyxHQUFHLENBQVQ7QUFBL0IsZ0JBRkYsQ0FERjtBQU1EIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBDb3B5cmlnaHQgKGMpIEZhY2Vib29rLCBJbmMuIGFuZCBpdHMgYWZmaWxpYXRlcy5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS5cbiAqXG4gKiBAZmxvd1xuICovXG5cbmltcG9ydCBSZWFjdCwge3VzZVN0YXRlfSBmcm9tICdyZWFjdCc7XG5cbmV4cG9ydCBmdW5jdGlvbiBDb21wb25lbnQoKSB7XG4gIGNvbnN0IFtjb3VudCwgc2V0Q291bnRdID0gdXNlU3RhdGUoMCk7XG5cbiAgcmV0dXJuIChcbiAgICA8ZGl2PlxuICAgICAgPHA+WW91IGNsaWNrZWQge2NvdW50fSB0aW1lczwvcD5cbiAgICAgIDxidXR0b24gb25DbGljaz17KCkgPT4gc2V0Q291bnQoY291bnQgKyAxKX0+Q2xpY2sgbWU8L2J1dHRvbj5cbiAgICA8L2Rpdj5cbiAgKTtcbn1cbiJdfQ==
-//# sourceURL=Example.js
\ No newline at end of file
+//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIkV4YW1wbGUuanMiXSwibmFtZXMiOlsiQ29tcG9uZW50IiwiY291bnQiLCJzZXRDb3VudCJdLCJtYXBwaW5ncyI6Ijs7Ozs7OztBQVNBOzs7Ozs7QUFUQTs7Ozs7Ozs7QUFXTyxTQUFTQSxTQUFULEdBQXFCO0FBQzFCLFFBQU0sQ0FBQ0MsS0FBRCxFQUFRQyxRQUFSLElBQW9CLHFCQUFTLENBQVQsQ0FBMUI7QUFFQSxzQkFDRSx1REFDRSx3REFBZ0JELEtBQWhCLFdBREYsZUFFRTtBQUFRLElBQUEsT0FBTyxFQUFFLE1BQU1DLFFBQVEsQ0FBQ0QsS0FBSyxHQUFHLENBQVQ7QUFBL0IsZ0JBRkYsQ0FERjtBQU1EIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBDb3B5cmlnaHQgKGMpIEZhY2Vib29rLCBJbmMuIGFuZCBpdHMgYWZmaWxpYXRlcy5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS5cbiAqXG4gKiBAZmxvd1xuICovXG5cbmltcG9ydCBSZWFjdCwge3VzZVN0YXRlfSBmcm9tICdyZWFjdCc7XG5cbmV4cG9ydCBmdW5jdGlvbiBDb21wb25lbnQoKSB7XG4gIGNvbnN0IFtjb3VudCwgc2V0Q291bnRdID0gdXNlU3RhdGUoMCk7XG5cbiAgcmV0dXJuIChcbiAgICA8ZGl2PlxuICAgICAgPHA+WW91IGNsaWNrZWQge2NvdW50fSB0aW1lczwvcD5cbiAgICAgIDxidXR0b24gb25DbGljaz17KCkgPT4gc2V0Q291bnQoY291bnQgKyAxKX0+Q2xpY2sgbWU8L2J1dHRvbj5cbiAgICA8L2Rpdj5cbiAgKTtcbn1cbiJdfQ==
\ No newline at end of file
diff --git a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/InlineRequire.js b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/InlineRequire.js
index 3492fe27327..83458fd428f 100644
--- a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/InlineRequire.js
+++ b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/InlineRequire.js
@@ -18,5 +18,4 @@ function Component() {
return count;
}
-//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIklubGluZVJlcXVpcmUuanMiXSwibmFtZXMiOlsiQ29tcG9uZW50IiwiY291bnQiLCJyZXF1aXJlIiwidXNlU3RhdGUiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7QUFBQTs7Ozs7Ozs7QUFTTyxTQUFTQSxTQUFULEdBQXFCO0FBQzFCLFFBQU0sQ0FBQ0MsS0FBRCxJQUFVQyxPQUFPLENBQUMsT0FBRCxDQUFQLENBQWlCQyxRQUFqQixDQUEwQixDQUExQixDQUFoQjs7QUFFQSxTQUFPRixLQUFQO0FBQ0QiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIENvcHlyaWdodCAoYykgRmFjZWJvb2ssIEluYy4gYW5kIGl0cyBhZmZpbGlhdGVzLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLlxuICpcbiAqIEBmbG93XG4gKi9cblxuZXhwb3J0IGZ1bmN0aW9uIENvbXBvbmVudCgpIHtcbiAgY29uc3QgW2NvdW50XSA9IHJlcXVpcmUoJ3JlYWN0JykudXNlU3RhdGUoMCk7XG5cbiAgcmV0dXJuIGNvdW50O1xufVxuIl19
-//# sourceURL=InlineRequire.js
\ No newline at end of file
+//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIklubGluZVJlcXVpcmUuanMiXSwibmFtZXMiOlsiQ29tcG9uZW50IiwiY291bnQiLCJyZXF1aXJlIiwidXNlU3RhdGUiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7QUFBQTs7Ozs7Ozs7QUFTTyxTQUFTQSxTQUFULEdBQXFCO0FBQzFCLFFBQU0sQ0FBQ0MsS0FBRCxJQUFVQyxPQUFPLENBQUMsT0FBRCxDQUFQLENBQWlCQyxRQUFqQixDQUEwQixDQUExQixDQUFoQjs7QUFFQSxTQUFPRixLQUFQO0FBQ0QiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIENvcHlyaWdodCAoYykgRmFjZWJvb2ssIEluYy4gYW5kIGl0cyBhZmZpbGlhdGVzLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLlxuICpcbiAqIEBmbG93XG4gKi9cblxuZXhwb3J0IGZ1bmN0aW9uIENvbXBvbmVudCgpIHtcbiAgY29uc3QgW2NvdW50XSA9IHJlcXVpcmUoJ3JlYWN0JykudXNlU3RhdGUoMCk7XG5cbiAgcmV0dXJuIGNvdW50O1xufVxuIl19
\ No newline at end of file
diff --git a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/ToDoList.js b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/ToDoList.js
index b196f598b6d..a5a2b216cf7 100644
--- a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/ToDoList.js
+++ b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/ToDoList.js
@@ -103,5 +103,4 @@ function List(props) {
toggleItem: toggleItem
}))));
}
-//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIlRvRG9MaXN0LmpzIl0sIm5hbWVzIjpbIkxpc3RJdGVtIiwiaXRlbSIsInJlbW92ZUl0ZW0iLCJ0b2dnbGVJdGVtIiwiaGFuZGxlRGVsZXRlIiwiaGFuZGxlVG9nZ2xlIiwiaXNDb21wbGV0ZSIsInRleHQiLCJMaXN0IiwicHJvcHMiLCJuZXdJdGVtVGV4dCIsInNldE5ld0l0ZW1UZXh0IiwiaXRlbXMiLCJzZXRJdGVtcyIsImlkIiwidWlkIiwic2V0VUlEIiwiaGFuZGxlQ2xpY2siLCJoYW5kbGVLZXlQcmVzcyIsImV2ZW50Iiwia2V5IiwiaGFuZGxlQ2hhbmdlIiwiY3VycmVudFRhcmdldCIsInZhbHVlIiwiaXRlbVRvUmVtb3ZlIiwiZmlsdGVyIiwiaXRlbVRvVG9nZ2xlIiwiaW5kZXgiLCJmaW5kSW5kZXgiLCJzbGljZSIsImNvbmNhdCIsIm1hcCJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7QUFTQTs7Ozs7O0FBVEE7Ozs7Ozs7O0FBWU8sU0FBU0EsUUFBVCxDQUFrQjtBQUFDQyxFQUFBQSxJQUFEO0FBQU9DLEVBQUFBLFVBQVA7QUFBbUJDLEVBQUFBO0FBQW5CLENBQWxCLEVBQWtEO0FBQ3ZELFFBQU1DLFlBQVksR0FBRyx1QkFBWSxNQUFNO0FBQ3JDRixJQUFBQSxVQUFVLENBQUNELElBQUQsQ0FBVjtBQUNELEdBRm9CLEVBRWxCLENBQUNBLElBQUQsRUFBT0MsVUFBUCxDQUZrQixDQUFyQjtBQUlBLFFBQU1HLFlBQVksR0FBRyx1QkFBWSxNQUFNO0FBQ3JDRixJQUFBQSxVQUFVLENBQUNGLElBQUQsQ0FBVjtBQUNELEdBRm9CLEVBRWxCLENBQUNBLElBQUQsRUFBT0UsVUFBUCxDQUZrQixDQUFyQjtBQUlBLHNCQUNFLDZDQUNFO0FBQVEsSUFBQSxPQUFPLEVBQUVDO0FBQWpCLGNBREYsZUFFRSxnREFDRTtBQUNFLElBQUEsT0FBTyxFQUFFSCxJQUFJLENBQUNLLFVBRGhCO0FBRUUsSUFBQSxRQUFRLEVBQUVELFlBRlo7QUFHRSxJQUFBLElBQUksRUFB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UDtBQUVFLElBQUEsV0FBVyxFQUFDLGtCQUZkO0FBR0UsSUFBQSxLQUFLLEVBQUVGLFdBSFQ7QUFJRSxJQUFBLFFBQVEsRUFBRVcsWUFKWjtBQUtFLElBQUEsVUFBVSxFQUFFSDtBQUxkLElBRkYsZUFTRTtBQUFRLElBQUEsUUFBUSxFQUFFUixXQUFXLEtBQUssRUFBbEM7QUFBc0MsSUFBQSxPQUFPLEVBQUVPO0FBQS9DLGtCQUNFO0FBQU0sSUFBQSxJQUFJLEVBQUMsS0FBWDtBQUFpQixrQkFBVztBQUE1QixXQURGLENBVEYsZUFjRSxnQ0FDR0wsS0FBSyxDQUFDbUIsR0FBTixDQUFVOUIsSUFBSSxpQkFDYixvQkFBQyxRQUFEO0FBQ0UsSUFBQSxHQUFHLEVBQUVBLElBQUksQ0FBQ2EsRUFEWjtBQUVFLElBQUEsSUFBSSxFQUFFYixJQUZSO0FBR0UsSUFBQSxVQUFVLEVBQUVDLFVBSGQ7QUFJRSxJQUFBLFVBQVUsRUFBRUM7QUFKZCxJQURELENBREgsQ0FkRixDQURGO0FBMkJEIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBDb3B5cmlnaHQgKGMpIEZhY2Vib29rLCBJbmMuIGFuZCBpdHMgYWZmaWxpYXRlcy5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS5cbiAqXG4gKiBAZmxvd1xuICovXG5cbmltcG9ydCAqIGFzIFJlYWN0IGZyb20gJ3JlYWN0JztcbmltcG9ydCB7RnJhZ21lbnQsIHVzZUNhbGxiYWNrLCB1c2VTdGF0ZX0gZnJvbSAncmVhY3QnO1xuXG5leHBvcnQgZnVuY3Rpb24gTGlzdEl0ZW0oe2l0ZW0sIHJlbW92ZUl0ZW0sIHRvZ2dsZUl0ZW19KSB7XG4gIGNvbnN0IGhhbmRsZURlbGV0ZSA9IHVzZUNhbGxiYWNrKCgpID0+IHtcbiAgICByZW1vdmVJdGVtKGl0ZW0pO1xuICB9LCBbaXRlbSwgcmVtb3ZlSXRlbV0pO1xuXG4gIGNvbnN0IGhhbmRsZVRvZ2dsZSA9IHVzZUNhbGxiYWNrKCgpID0+IHtcbiAgICB0b2dnbGVJdGVtKGl0ZW0pO1xuICB9LCBbaXRlbSwgdG9nZ2xlSXRlbV0pO1xuXG4gIHJldHVybiAoXG4gICAgPGxpPlxuICAgICAgPGJ1dHRvbiBvbkNsaWNrPXtoYW5kbGVEZWxldGV9PkRlbGV0ZTwvYnV0dG9uPlxuICAgICAgPGxhYmVsPlxuICAgICAgICA8aW5wdXRcbiAgICAgICAgICBjaGVja2VkPXtpdGVtLmlzQ29tcGxldGV9XG4gICAgICAgICAgb25DaGFuZ2U9e2hhbmRsZVRvZ2dsZX1cbiAgICAgICAgICB0eXBlPVwiY2hlY2tib3hcIlxuICAgICAgICAvPnsnICd9XG4gICAgICAgIHtpdGVtLnRleHR9XG4gICAgICA8L2xhYmVsPlxuICAgIDwvbGk+XG4gICk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBMaXN0KHByb3BzKSB7XG4gIGNvbnN0IFtuZXdJdGVtVGV4dCwgc2V0TmV3SXRlbVRleHRdID0gdXNlU3RhdGUoJycpO1xuICBjb25zdCBbaXRlbXMsIHNldEl0ZW1zXSA9IHVzZVN0YXRlKFtcbiAgICB7aWQ6IDEsIGlzQ29tcGxldGU6IHRydWUsIHRleHQ6ICdGaXJzdCd9LFxuICAgIHtpZDogMiwgaXNDb21wbGV0ZTogdHJ1ZSwgdGV4dDogJ1NlY29uZCd9LFxuICAgIHtpZDogMywgaXNDb21wbGV0ZTogZmFsc2UsIHRleHQ6ICdUaGlyZCd9LFxuICBdKTtcbiAgY29uc3QgW3VpZCwgc2V0VUlEXSA9IHVzZVN0YXRlKDQpO1xuXG4gIGNvbnN0IGhhbmRsZUNsaWNrID0gdXNlQ2FsbGJhY2soKCkgPT4ge1xuICAgIGlmIChuZXdJdGVtVGV4dCAhPT0gJycpIHtcbiAgICAgIHNldEl0ZW1zKFtcbiAgICAgICAgLi4uaXRlbXMsXG4gICAgICAgIHtcbiAgICAgICAgICBpZDogdWlkLFxuICAgICAgICAgIGlzQ29tcGxldGU6IGZhbHNlLFxuICAgICAgICAgIHRleHQ6IG5ld0l0ZW1UZXh0LFxuICAgICAgICB9LFxuICAgICAgXSk7XG4gICAgICBzZXRVSUQodWlkICsgMSk7XG4gICAgICBzZXROZXdJdGVtVGV4dCgnJyk7XG4gICAgfVxuICB9LCBbbmV3SXRlbVRleHQsIGl0ZW1zLCB1aWRdKTtcblxuICBjb25zdCBoYW5kbGVLZXlQcmVzcyA9IHVzZUNhbGxiYWNrKFxuICAgIGV2ZW50ID0+IHtcbiAgICAgIGlmIChldmVudC5rZXkgPT09ICdFbnRlcicpIHtcbiAgICAgICAgaGFuZGxlQ2xpY2soKTtcbiAgICAgIH1cbiAgICB9LFxuICAgIFtoYW5kbGVDbGlja10sXG4gICk7XG5cbiAgY29uc3QgaGFuZGxlQ2hhbmdlID0gdXNlQ2FsbGJhY2soXG4gICAgZXZlbnQgPT4ge1xuICAgICAgc2V0TmV3SXRlbVRleHQoZXZlbnQuY3VycmVudFRhcmdldC52YWx1ZSk7XG4gICAgfSxcbiAgICBbc2V0TmV3SXRlbVRleHRdLFxuICApO1xuXG4gIGNvbnN0IHJlbW92ZUl0ZW0gPSB1c2VDYWxsYmFjayhcbiAgICBpdGVtVG9SZW1vdmUgPT4gc2V0SXRlbXMoaXRlbXMuZmlsdGVyKGl0ZW0gPT4gaXRlbSAhPT0gaXRlbVRvUmVtb3ZlKSksXG4gICAgW2l0ZW1zXSxcbiAgKTtcblxuICBjb25zdCB0b2dnbGVJdGVtID0gdXNlQ2FsbGJhY2soXG4gICAgaXRlbVRvVG9nZ2xlID0+IHtcbiAgICAgIC8vIERvbnQgdXNlIGluZGV4T2YoKVxuICAgICAgLy8gYmVjYXVzZSBlZGl0aW5nIHByb3BzIGluIERldlRvb2xzIGNyZWF0ZXMgYSBuZXcgT2JqZWN0LlxuICAgICAgY29uc3QgaW5kZXggPSBpdGVtcy5maW5kSW5kZXgoaXRlbSA9PiBpdGVtLmlkID09PSBpdGVtVG9Ub2dnbGUuaWQpO1xuXG4gICAgICBzZXRJdGVtcyhcbiAgICAgICAgaXRlbXNcbiAgICAgICAgICAuc2xpY2UoMCwgaW5kZXgpXG4gICAgICAgICAgLmNvbmNhdCh7XG4gICAgICAgICAgICAuLi5pdGVtVG9Ub2dnbGUsXG4gICAgICAgICAgICBpc0NvbXBsZXRlOiAhaXRlbVRvVG9nZ2xlLmlzQ29tcGxldGUsXG4gICAgICAgICAgfSlcbiAgICAgICAgICAuY29uY2F0KGl0ZW1zLnNsaWNlKGluZGV4ICsgMSkpLFxuICAgICAgKTtcbiAgICB9LFxuICAgIFtpdGVtc10sXG4gICk7XG5cbiAgcmV0dXJuIChcbiAgICA8RnJhZ21lbnQ+XG4gICAgICA8aDE+TGlzdDwvaDE+XG4gICAgICA8aW5wdXRcbiAgICAgICAgdHlwZT1cInRleHRcIlxuICAgICAgICBwbGFjZWhvbGRlcj1cIk5ldyBsaXN0IGl0ZW0uLi5cIlxuICAgICAgICB2YWx1ZT17bmV3SXRlbVRleHR9XG4gICAgICAgIG9uQ2hhbmdlPXtoYW5kbGVDaGFuZ2V9XG4gICAgICAgIG9uS2V5UHJlc3M9e2hhbmRsZUtleVByZXNzfVxuICAgICAgLz5cbiAgICAgIDxidXR0b24gZGlzYWJsZWQ9e25ld0l0ZW1UZXh0ID09PSAnJ30gb25DbGljaz17aGFuZGxlQ2xpY2t9PlxuICAgICAgICA8c3BhbiByb2xlPVwiaW1nXCIgYXJpYS1sYWJlbD1cIkFkZCBpdGVtXCI+XG4gICAgICAgICAgQWRkXG4gICAgICAgIDwvc3Bhbj5cbiAgICAgIDwvYnV0dG9uPlxuICAgICAgPHVsPlxuICAgICAgICB7aXRlbXMubWFwKGl0ZW0gPT4gKFxuICAgICAgICAgIDxMaXN0SXRlbVxuICAgICAgICAgICAga2V5PXtpdGVtLmlkfVxuICAgICAgICAgICAgaXRlbT17aXRlbX1cbiAgICAgICAgICAgIHJlbW92ZUl0ZW09e3JlbW92ZUl0ZW19XG4gICAgICAgICAgICB0b2dnbGVJdGVtPXt0b2dnbGVJdGVtfVxuICAgICAgICAgIC8+XG4gICAgICAgICkpfVxuICAgICAgPC91bD5cbiAgICA8L0ZyYWdtZW50PlxuICApO1xufVxuIl19
-//# sourceURL=ToDoList.js
\ No newline at end of file
+//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIlRvRG9MaXN0LmpzIl0sIm5hbWVzIjpbIkxpc3RJdGVtIiwiaXRlbSIsInJlbW92ZUl0ZW0iLCJ0b2dnbGVJdGVtIiwiaGFuZGxlRGVsZXRlIiwiaGFuZGxlVG9nZ2xlIiwiaXNDb21wbGV0ZSIsInRleHQiLCJMaXN0IiwicHJvcHMiLCJuZXdJdGVtVGV4dCIsInNldE5ld0l0ZW1UZXh0IiwiaXRlbXMiLCJzZXRJdGVtcyIsImlkIiwidWlkIiwic2V0VUlEIiwiaGFuZGxlQ2xpY2siLCJoYW5kbGVLZXlQcmVzcyIsImV2ZW50Iiwia2V5IiwiaGFuZGxlQ2hhbmdlIiwiY3VycmVudFRhcmdldCIsInZhbHVlIiwiaXRlbVRvUmVtb3ZlIiwiZmlsdGVyIiwiaXRlbVRvVG9nZ2xlIiwiaW5kZXgiLCJmaW5kSW5kZXgiLCJzbGljZSIsImNvbmNhdCIsIm1hcCJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7QUFTQTs7Ozs7O0FBVEE7Ozs7Ozs7O0FBWU8sU0FBU0EsUUFBVCxDQUFrQjtBQUFDQyxFQUFBQSxJQUFEO0FBQU9DLEVBQUFBLFVBQVA7QUFBbUJDLEVBQUFBO0FBQW5CLENBQWxCLEVBQWtEO0FBQ3ZELFFBQU1DLFlBQVksR0FBRyx1QkFBWSxNQUFNO0FBQ3JDRixJQUFBQSxVQUFVLENBQUNELElBQUQsQ0FBVjtBQUNELEdBRm9CLEVBRWxCLENBQUNBLElBQUQsRUFBT0MsVUFBUCxDQUZrQixDQUFyQjtBQUlBLFFBQU1HLFlBQVksR0FBRyx1QkFBWSxNQUFNO0FBQ3JDRixJQUFBQSxVQUFVLENBQUNGLElBQUQsQ0FBVjtBQUNELEdBRm9CLEVBRWxCLENBQUNBLElBQUQsRUFBT0UsVUFBUCxDQUZrQixDQUFyQjtBQUlBLHNCQUNFLDZDQUNFO0FBQVEsSUFBQSxPQUFPLEVBQUVDO0FBQWpCLGNBREYsZUFFRSxnREFDRTtBQUNFLElBQUEsT0FBTyxFQUFFSCxJQUFJLENBQUNLLFVBRGhCO0FBRUUsSUFBQSxRQUFRLEVBQUVELFlBRlo7QUFHRSxJQUFBLElBQUksRUFB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UDtBQUVFLElBQUEsV0FBVyxFQUFDLGtCQUZkO0FBR0UsSUFBQSxLQUFLLEVBQUVGLFdBSFQ7QUFJRSxJQUFBLFFBQVEsRUFBRVcsWUFKWjtBQUtFLElBQUEsVUFBVSxFQUFFSDtBQUxkLElBRkYsZUFTRTtBQUFRLElBQUEsUUFBUSxFQUFFUixXQUFXLEtBQUssRUFBbEM7QUFBc0MsSUFBQSxPQUFPLEVBQUVPO0FBQS9DLGtCQUNFO0FBQU0sSUFBQSxJQUFJLEVBQUMsS0FBWDtBQUFpQixrQkFBVztBQUE1QixXQURGLENBVEYsZUFjRSxnQ0FDR0wsS0FBSyxDQUFDbUIsR0FBTixDQUFVOUIsSUFBSSxpQkFDYixvQkFBQyxRQUFEO0FBQ0UsSUFBQSxHQUFHLEVBQUVBLElBQUksQ0FBQ2EsRUFEWjtBQUVFLElBQUEsSUFBSSxFQUFFYixJQUZSO0FBR0UsSUFBQSxVQUFVLEVBQUVDLFVBSGQ7QUFJRSxJQUFBLFVBQVUsRUFBRUM7QUFKZCxJQURELENBREgsQ0FkRixDQURGO0FBMkJEIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBDb3B5cmlnaHQgKGMpIEZhY2Vib29rLCBJbmMuIGFuZCBpdHMgYWZmaWxpYXRlcy5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS5cbiAqXG4gKiBAZmxvd1xuICovXG5cbmltcG9ydCAqIGFzIFJlYWN0IGZyb20gJ3JlYWN0JztcbmltcG9ydCB7RnJhZ21lbnQsIHVzZUNhbGxiYWNrLCB1c2VTdGF0ZX0gZnJvbSAncmVhY3QnO1xuXG5leHBvcnQgZnVuY3Rpb24gTGlzdEl0ZW0oe2l0ZW0sIHJlbW92ZUl0ZW0sIHRvZ2dsZUl0ZW19KSB7XG4gIGNvbnN0IGhhbmRsZURlbGV0ZSA9IHVzZUNhbGxiYWNrKCgpID0+IHtcbiAgICByZW1vdmVJdGVtKGl0ZW0pO1xuICB9LCBbaXRlbSwgcmVtb3ZlSXRlbV0pO1xuXG4gIGNvbnN0IGhhbmRsZVRvZ2dsZSA9IHVzZUNhbGxiYWNrKCgpID0+IHtcbiAgICB0b2dnbGVJdGVtKGl0ZW0pO1xuICB9LCBbaXRlbSwgdG9nZ2xlSXRlbV0pO1xuXG4gIHJldHVybiAoXG4gICAgPGxpPlxuICAgICAgPGJ1dHRvbiBvbkNsaWNrPXtoYW5kbGVEZWxldGV9PkRlbGV0ZTwvYnV0dG9uPlxuICAgICAgPGxhYmVsPlxuICAgICAgICA8aW5wdXRcbiAgICAgICAgICBjaGVja2VkPXtpdGVtLmlzQ29tcGxldGV9XG4gICAgICAgICAgb25DaGFuZ2U9e2hhbmRsZVRvZ2dsZX1cbiAgICAgICAgICB0eXBlPVwiY2hlY2tib3hcIlxuICAgICAgICAvPnsnICd9XG4gICAgICAgIHtpdGVtLnRleHR9XG4gICAgICA8L2xhYmVsPlxuICAgIDwvbGk+XG4gICk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBMaXN0KHByb3BzKSB7XG4gIGNvbnN0IFtuZXdJdGVtVGV4dCwgc2V0TmV3SXRlbVRleHRdID0gdXNlU3RhdGUoJycpO1xuICBjb25zdCBbaXRlbXMsIHNldEl0ZW1zXSA9IHVzZVN0YXRlKFtcbiAgICB7aWQ6IDEsIGlzQ29tcGxldGU6IHRydWUsIHRleHQ6ICdGaXJzdCd9LFxuICAgIHtpZDogMiwgaXNDb21wbGV0ZTogdHJ1ZSwgdGV4dDogJ1NlY29uZCd9LFxuICAgIHtpZDogMywgaXNDb21wbGV0ZTogZmFsc2UsIHRleHQ6ICdUaGlyZCd9LFxuICBdKTtcbiAgY29uc3QgW3VpZCwgc2V0VUlEXSA9IHVzZVN0YXRlKDQpO1xuXG4gIGNvbnN0IGhhbmRsZUNsaWNrID0gdXNlQ2FsbGJhY2soKCkgPT4ge1xuICAgIGlmIChuZXdJdGVtVGV4dCAhPT0gJycpIHtcbiAgICAgIHNldEl0ZW1zKFtcbiAgICAgICAgLi4uaXRlbXMsXG4gICAgICAgIHtcbiAgICAgICAgICBpZDogdWlkLFxuICAgICAgICAgIGlzQ29tcGxldGU6IGZhbHNlLFxuICAgICAgICAgIHRleHQ6IG5ld0l0ZW1UZXh0LFxuICAgICAgICB9LFxuICAgICAgXSk7XG4gICAgICBzZXRVSUQodWlkICsgMSk7XG4gICAgICBzZXROZXdJdGVtVGV4dCgnJyk7XG4gICAgfVxuICB9LCBbbmV3SXRlbVRleHQsIGl0ZW1zLCB1aWRdKTtcblxuICBjb25zdCBoYW5kbGVLZXlQcmVzcyA9IHVzZUNhbGxiYWNrKFxuICAgIGV2ZW50ID0+IHtcbiAgICAgIGlmIChldmVudC5rZXkgPT09ICdFbnRlcicpIHtcbiAgICAgICAgaGFuZGxlQ2xpY2soKTtcbiAgICAgIH1cbiAgICB9LFxuICAgIFtoYW5kbGVDbGlja10sXG4gICk7XG5cbiAgY29uc3QgaGFuZGxlQ2hhbmdlID0gdXNlQ2FsbGJhY2soXG4gICAgZXZlbnQgPT4ge1xuICAgICAgc2V0TmV3SXRlbVRleHQoZXZlbnQuY3VycmVudFRhcmdldC52YWx1ZSk7XG4gICAgfSxcbiAgICBbc2V0TmV3SXRlbVRleHRdLFxuICApO1xuXG4gIGNvbnN0IHJlbW92ZUl0ZW0gPSB1c2VDYWxsYmFjayhcbiAgICBpdGVtVG9SZW1vdmUgPT4gc2V0SXRlbXMoaXRlbXMuZmlsdGVyKGl0ZW0gPT4gaXRlbSAhPT0gaXRlbVRvUmVtb3ZlKSksXG4gICAgW2l0ZW1zXSxcbiAgKTtcblxuICBjb25zdCB0b2dnbGVJdGVtID0gdXNlQ2FsbGJhY2soXG4gICAgaXRlbVRvVG9nZ2xlID0+IHtcbiAgICAgIC8vIERvbnQgdXNlIGluZGV4T2YoKVxuICAgICAgLy8gYmVjYXVzZSBlZGl0aW5nIHByb3BzIGluIERldlRvb2xzIGNyZWF0ZXMgYSBuZXcgT2JqZWN0LlxuICAgICAgY29uc3QgaW5kZXggPSBpdGVtcy5maW5kSW5kZXgoaXRlbSA9PiBpdGVtLmlkID09PSBpdGVtVG9Ub2dnbGUuaWQpO1xuXG4gICAgICBzZXRJdGVtcyhcbiAgICAgICAgaXRlbXNcbiAgICAgICAgICAuc2xpY2UoMCwgaW5kZXgpXG4gICAgICAgICAgLmNvbmNhdCh7XG4gICAgICAgICAgICAuLi5pdGVtVG9Ub2dnbGUsXG4gICAgICAgICAgICBpc0NvbXBsZXRlOiAhaXRlbVRvVG9nZ2xlLmlzQ29tcGxldGUsXG4gICAgICAgICAgfSlcbiAgICAgICAgICAuY29uY2F0KGl0ZW1zLnNsaWNlKGluZGV4ICsgMSkpLFxuICAgICAgKTtcbiAgICB9LFxuICAgIFtpdGVtc10sXG4gICk7XG5cbiAgcmV0dXJuIChcbiAgICA8RnJhZ21lbnQ+XG4gICAgICA8aDE+TGlzdDwvaDE+XG4gICAgICA8aW5wdXRcbiAgICAgICAgdHlwZT1cInRleHRcIlxuICAgICAgICBwbGFjZWhvbGRlcj1cIk5ldyBsaXN0IGl0ZW0uLi5cIlxuICAgICAgICB2YWx1ZT17bmV3SXRlbVRleHR9XG4gICAgICAgIG9uQ2hhbmdlPXtoYW5kbGVDaGFuZ2V9XG4gICAgICAgIG9uS2V5UHJlc3M9e2hhbmRsZUtleVByZXNzfVxuICAgICAgLz5cbiAgICAgIDxidXR0b24gZGlzYWJsZWQ9e25ld0l0ZW1UZXh0ID09PSAnJ30gb25DbGljaz17aGFuZGxlQ2xpY2t9PlxuICAgICAgICA8c3BhbiByb2xlPVwiaW1nXCIgYXJpYS1sYWJlbD1cIkFkZCBpdGVtXCI+XG4gICAgICAgICAgQWRkXG4gICAgICAgIDwvc3Bhbj5cbiAgICAgIDwvYnV0dG9uPlxuICAgICAgPHVsPlxuICAgICAgICB7aXRlbXMubWFwKGl0ZW0gPT4gKFxuICAgICAgICAgIDxMaXN0SXRlbVxuICAgICAgICAgICAga2V5PXtpdGVtLmlkfVxuICAgICAgICAgICAgaXRlbT17aXRlbX1cbiAgICAgICAgICAgIHJlbW92ZUl0ZW09e3JlbW92ZUl0ZW19XG4gICAgICAgICAgICB0b2dnbGVJdGVtPXt0b2dnbGVJdGVtfVxuICAgICAgICAgIC8+XG4gICAgICAgICkpfVxuICAgICAgPC91bD5cbiAgICA8L0ZyYWdtZW50PlxuICApO1xufVxuIl19
\ 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
new file mode 100644
index 00000000000..429ebfbbcf6
--- /dev/null
+++ b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/index.js
@@ -0,0 +1,57 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+Object.defineProperty(exports, "ComponentWithCustomHook", {
+ enumerable: true,
+ get: function () {
+ return _ComponentWithCustomHook.Component;
+ }
+});
+Object.defineProperty(exports, "ComponentWithExternalCustomHooks", {
+ enumerable: true,
+ get: function () {
+ return _ComponentWithExternalCustomHooks.Component;
+ }
+});
+Object.defineProperty(exports, "Example", {
+ enumerable: true,
+ get: function () {
+ return _Example.Component;
+ }
+});
+Object.defineProperty(exports, "InlineRequire", {
+ enumerable: true,
+ get: function () {
+ return _InlineRequire.Component;
+ }
+});
+Object.defineProperty(exports, "useTheme", {
+ enumerable: true,
+ get: function () {
+ return _useTheme.default;
+ }
+});
+exports.ToDoList = void 0;
+
+var _ComponentWithCustomHook = require("./ComponentWithCustomHook");
+
+var _ComponentWithExternalCustomHooks = require("./ComponentWithExternalCustomHooks");
+
+var _Example = require("./Example");
+
+var _InlineRequire = require("./InlineRequire");
+
+var ToDoList = _interopRequireWildcard(require("./ToDoList"));
+
+exports.ToDoList = ToDoList;
+
+var _useTheme = _interopRequireDefault(require("./useTheme"));
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+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
diff --git a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/useTheme.js b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/useTheme.js
index 1122f6ab69e..0703c679363 100644
--- a/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/useTheme.js
+++ b/packages/react-devtools-extensions/src/__tests__/__source__/__compiled__/inline/useTheme.js
@@ -24,5 +24,4 @@ function useTheme() {
(0, _react.useDebugValue)(theme);
return theme;
}
-//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInVzZVRoZW1lLmpzIl0sIm5hbWVzIjpbIlRoZW1lQ29udGV4dCIsInVzZVRoZW1lIiwidGhlbWUiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7O0FBU0E7O0FBVEE7Ozs7Ozs7O0FBV08sTUFBTUEsWUFBWSxnQkFBRywwQkFBYyxRQUFkLENBQXJCOzs7QUFFUSxTQUFTQyxRQUFULEdBQW9CO0FBQ2pDLFFBQU1DLEtBQUssR0FBRyx1QkFBV0YsWUFBWCxDQUFkO0FBQ0EsNEJBQWNFLEtBQWQ7QUFDQSxTQUFPQSxLQUFQO0FBQ0QiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIENvcHlyaWdodCAoYykgRmFjZWJvb2ssIEluYy4gYW5kIGl0cyBhZmZpbGlhdGVzLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLlxuICpcbiAqIEBmbG93XG4gKi9cblxuaW1wb3J0IHtjcmVhdGVDb250ZXh0LCB1c2VDb250ZXh0LCB1c2VEZWJ1Z1ZhbHVlfSBmcm9tICdyZWFjdCc7XG5cbmV4cG9ydCBjb25zdCBUaGVtZUNvbnRleHQgPSBjcmVhdGVDb250ZXh0KCdicmlnaHQnKTtcblxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gdXNlVGhlbWUoKSB7XG4gIGNvbnN0IHRoZW1lID0gdXNlQ29udGV4dChUaGVtZUNvbnRleHQpO1xuICB1c2VEZWJ1Z1ZhbHVlKHRoZW1lKTtcbiAgcmV0dXJuIHRoZW1lO1xufVxuIl19
-//# sourceURL=useTheme.js
\ No newline at end of file
+//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInVzZVRoZW1lLmpzIl0sIm5hbWVzIjpbIlRoZW1lQ29udGV4dCIsInVzZVRoZW1lIiwidGhlbWUiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7O0FBU0E7O0FBVEE7Ozs7Ozs7O0FBV08sTUFBTUEsWUFBWSxnQkFBRywwQkFBYyxRQUFkLENBQXJCOzs7QUFFUSxTQUFTQyxRQUFULEdBQW9CO0FBQ2pDLFFBQU1DLEtBQUssR0FBRyx1QkFBV0YsWUFBWCxDQUFkO0FBQ0EsNEJBQWNFLEtBQWQ7QUFDQSxTQUFPQSxLQUFQO0FBQ0QiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIENvcHlyaWdodCAoYykgRmFjZWJvb2ssIEluYy4gYW5kIGl0cyBhZmZpbGlhdGVzLlxuICpcbiAqIFRoaXMgc291cmNlIGNvZGUgaXMgbGljZW5zZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlIGZvdW5kIGluIHRoZVxuICogTElDRU5TRSBmaWxlIGluIHRoZSByb290IGRpcmVjdG9yeSBvZiB0aGlzIHNvdXJjZSB0cmVlLlxuICpcbiAqIEBmbG93XG4gKi9cblxuaW1wb3J0IHtjcmVhdGVDb250ZXh0LCB1c2VDb250ZXh0LCB1c2VEZWJ1Z1ZhbHVlfSBmcm9tICdyZWFjdCc7XG5cbmV4cG9ydCBjb25zdCBUaGVtZUNvbnRleHQgPSBjcmVhdGVDb250ZXh0KCdicmlnaHQnKTtcblxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gdXNlVGhlbWUoKSB7XG4gIGNvbnN0IHRoZW1lID0gdXNlQ29udGV4dChUaGVtZUNvbnRleHQpO1xuICB1c2VEZWJ1Z1ZhbHVlKHRoZW1lKTtcbiAgcmV0dXJuIHRoZW1lO1xufVxuIl19
\ 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
new file mode 100644
index 00000000000..a4f204fe19f
--- /dev/null
+++ b/packages/react-devtools-extensions/src/__tests__/__source__/index.js
@@ -0,0 +1,16 @@
+/**
+ * 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
+ */
+
+export {Component as ComponentWithCustomHook} from './ComponentWithCustomHook';
+export {Component as ComponentWithExternalCustomHooks} from './ComponentWithExternalCustomHooks';
+export {Component as Example} from './Example';
+export {Component as InlineRequire} from './InlineRequire';
+import * as ToDoList from './ToDoList';
+export {ToDoList};
+export {default as useTheme} from './useTheme';
diff --git a/packages/react-devtools-extensions/src/__tests__/parseHookNames-test.js b/packages/react-devtools-extensions/src/__tests__/parseHookNames-test.js
index 3a65b3709d2..e1efe7c32ca 100644
--- a/packages/react-devtools-extensions/src/__tests__/parseHookNames-test.js
+++ b/packages/react-devtools-extensions/src/__tests__/parseHookNames-test.js
@@ -33,25 +33,18 @@ describe('parseHookNames', () => {
// Jest (jest-runner?) configures Errors to automatically account for source maps.
// This changes behavior between our tests and the browser.
- // To "fix" this, clear the prepareStackTrace() method on the Error object.
- delete Error.prepareStackTrace;
+ // Ideally we would clear the prepareStackTrace() method on the Error object,
+ // but Node falls back to looking for it on the main context's Error constructor,
+ // which may still be patched.
+ // To ensure we get the default behavior, override prepareStackTrace ourselves.
+ // NOTE: prepareStackTrace is called from the error.stack getter, but the getter
+ // has a recursion breaker which falls back to the default behavior.
+ Error.prepareStackTrace = (error, trace) => {
+ return error.stack;
+ };
fetchMock.mockIf(/.+$/, request => {
- const {resolve} = require('path');
- const url = request.url;
- if (url.endsWith('js.map')) {
- // Source maps are relative URLs (e.g. "path/to/Exmaple.js" specifies "Exmaple.js.map").
- const sourceMapURL = resolve(
- __dirname,
- '__source__',
- '__compiled__',
- 'external',
- url,
- );
- return Promise.resolve(requireText(sourceMapURL, 'utf8'));
- } else {
- return Promise.resolve(requireText(url, 'utf8'));
- }
+ return Promise.resolve(requireText(request.url, 'utf8'));
});
// Mock out portion of browser API used by parseHookNames to initialize "source-map".
@@ -185,10 +178,10 @@ describe('parseHookNames', () => {
]);
});
- describe('inline and external source maps', () => {
+ describe('inline, external and bundle source maps', () => {
it('should work for simple components', async () => {
- async function test(path) {
- const Component = require(path).Component;
+ async function test(path, name = 'Component') {
+ const Component = require(path)[name];
const hookNames = await getHookNamesForComponent(Component);
expectHookNamesToEqual(hookNames, [
'count', // useState
@@ -198,11 +191,12 @@ describe('parseHookNames', () => {
await test('./__source__/Example'); // original source (uncompiled)
await test('./__source__/__compiled__/inline/Example'); // inline source map
await test('./__source__/__compiled__/external/Example'); // external source map
+ await test('./__source__/__compiled__/bundle/index', 'Example'); // bundle source map
});
it('should work with more complex files and components', async () => {
- async function test(path) {
- const components = require(path);
+ async function test(path, name = undefined) {
+ const components = name != null ? require(path)[name] : require(path);
let hookNames = await getHookNamesForComponent(components.List);
expectHookNamesToEqual(hookNames, [
@@ -228,11 +222,12 @@ describe('parseHookNames', () => {
await test('./__source__/ToDoList'); // original source (uncompiled)
await test('./__source__/__compiled__/inline/ToDoList'); // inline source map
await test('./__source__/__compiled__/external/ToDoList'); // external source map
+ await test('./__source__/__compiled__/bundle', 'ToDoList'); // bundle source map
});
it('should work for custom hook', async () => {
- async function test(path) {
- const Component = require(path).Component;
+ async function test(path, name = 'Component') {
+ const Component = require(path)[name];
const hookNames = await getHookNamesForComponent(Component);
expectHookNamesToEqual(hookNames, [
'count', // useState()
@@ -244,11 +239,12 @@ describe('parseHookNames', () => {
await test('./__source__/ComponentWithCustomHook'); // original source (uncompiled)
await test('./__source__/__compiled__/inline/ComponentWithCustomHook'); // inline source map
await test('./__source__/__compiled__/external/ComponentWithCustomHook'); // external source map
+ await test('./__source__/__compiled__/bundle', 'ComponentWithCustomHook'); // bundle source map
});
it('should work for external hooks', async () => {
- async function test(path) {
- const Component = require(path).Component;
+ async function test(path, name = 'Component') {
+ const Component = require(path)[name];
const hookNames = await getHookNamesForComponent(Component);
expectHookNamesToEqual(hookNames, [
'theme', // useTheme()
@@ -265,14 +261,18 @@ describe('parseHookNames', () => {
await test(
'./__source__/__compiled__/external/ComponentWithExternalCustomHooks',
); // external source map
+ await test(
+ './__source__/__compiled__/bundle',
+ 'ComponentWithExternalCustomHooks',
+ ); // 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).
xit('should work for inline requires', async () => {
- async function test(path) {
- const Component = require(path).Component;
+ async function test(path, name = 'Component') {
+ const Component = require(path)[name];
const hookNames = await getHookNamesForComponent(Component);
expectHookNamesToEqual(hookNames, [
'count', // useState()
@@ -282,6 +282,7 @@ describe('parseHookNames', () => {
await test('./__source__/InlineRequire'); // original source (uncompiled)
await test('./__source__/__compiled__/inline/InlineRequire'); // inline source map
await test('./__source__/__compiled__/external/InlineRequire'); // external source map
+ await test('./__source__/__compiled__/bundle', 'InlineRequire'); // bundle source map
});
});
});
diff --git a/packages/react-devtools-extensions/src/__tests__/updateMockSourceMaps.js b/packages/react-devtools-extensions/src/__tests__/updateMockSourceMaps.js
index 590cd36cc63..231bdee5212 100644
--- a/packages/react-devtools-extensions/src/__tests__/updateMockSourceMaps.js
+++ b/packages/react-devtools-extensions/src/__tests__/updateMockSourceMaps.js
@@ -9,16 +9,23 @@ const {
} = require('fs');
const {emptyDirSync} = require('fs-extra');
const {resolve} = require('path');
+const rollup = require('rollup');
+const babel = require('rollup-plugin-babel');
+const commonjs = require('rollup-plugin-commonjs');
+const jsx = require('acorn-jsx');
+const rollupResolve = require('rollup-plugin-node-resolve');
const sourceDir = resolve(__dirname, '__source__');
const buildRoot = resolve(sourceDir, '__compiled__');
const externalDir = resolve(buildRoot, 'external');
const inlineDir = resolve(buildRoot, 'inline');
+const bundleDir = resolve(buildRoot, 'bundle');
// Remove previous builds
emptyDirSync(buildRoot);
mkdirSync(externalDir);
mkdirSync(inlineDir);
+mkdirSync(bundleDir);
function compile(fileName) {
const code = readFileSync(resolve(sourceDir, fileName), 'utf8');
@@ -44,9 +51,7 @@ function compile(fileName) {
// Generate compiled output with external source maps
writeFileSync(
resolve(externalDir, fileName),
- transformed.code +
- `\n//# sourceMappingURL=${fileName}.map` +
- `\n//# sourceURL=${fileName}`,
+ transformed.code + `\n//# sourceMappingURL=${fileName}.map`,
'utf8',
);
writeFileSync(
@@ -60,12 +65,32 @@ function compile(fileName) {
resolve(inlineDir, fileName),
transformed.code +
'\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,' +
- btoa(JSON.stringify(sourceMap)) +
- `\n//# sourceURL=${fileName}`,
+ btoa(JSON.stringify(sourceMap)),
'utf8',
);
}
+async function bundle() {
+ const entryFileName = resolve(sourceDir, 'index.js');
+
+ // Bundle all modules with rollup
+ const result = await rollup.rollup({
+ input: entryFileName,
+ acornInjectPlugins: [jsx()],
+ plugins: [
+ rollupResolve(),
+ commonjs(),
+ babel({presets: ['@babel/preset-react'], sourceMap: true}),
+ ],
+ external: ['react'],
+ });
+ await result.write({
+ file: resolve(bundleDir, 'index.js'),
+ format: 'cjs',
+ sourcemap: true,
+ });
+}
+
// Compile all files in the current directory
const entries = readdirSync(sourceDir);
entries.forEach(entry => {
@@ -74,3 +99,8 @@ entries.forEach(entry => {
compile(entry);
}
});
+
+bundle().catch(e => {
+ console.error(e);
+ process.exit(1);
+});
diff --git a/packages/react-devtools-extensions/src/astUtils.js b/packages/react-devtools-extensions/src/astUtils.js
index cc976bbd198..dff938c9d38 100644
--- a/packages/react-devtools-extensions/src/astUtils.js
+++ b/packages/react-devtools-extensions/src/astUtils.js
@@ -20,14 +20,6 @@ export type SourceFileASTWithHookDetails = {
source: string,
};
-export type SourceMap = {|
- mappings: string,
- names: Array,
- sources: Array,
- sourcesContent: Array,
- version: number,
-|};
-
const AST_NODE_TYPES = Object.freeze({
CALL_EXPRESSION: 'CallExpression',
MEMBER_EXPRESSION: 'MemberExpression',
diff --git a/packages/react-devtools-extensions/src/parseHookNames.js b/packages/react-devtools-extensions/src/parseHookNames.js
index f2d74dc2929..dc2b8b3c4bc 100644
--- a/packages/react-devtools-extensions/src/parseHookNames.js
+++ b/packages/react-devtools-extensions/src/parseHookNames.js
@@ -24,7 +24,7 @@ import type {
} from 'react-debug-tools/src/ReactDebugHooks';
import type {HookNames, LRUCache} from 'react-devtools-shared/src/types';
import type {Thenable} from 'shared/ReactTypes';
-import type {SourceConsumer, SourceMap} from './astUtils';
+import type {SourceConsumer} from './astUtils';
const SOURCE_MAP_REGEX = / ?sourceMappingURL=([^\s'"]+)/gm;
const ABSOLUTE_URL_REGEX = /^https?:\/\//i;
@@ -43,36 +43,36 @@ type HookSourceData = {|
// If no source map has been provided, this code will be the same as runtimeSourceCode.
originalSourceCode: string | null,
+ // Original source URL if there is a source map, or the same as runtimeSourceURL.
+ originalSourceURL: string | null,
+
// Compiled code (React components or custom hooks) containing primitive hook calls.
runtimeSourceCode: string | null,
+ // Same as hookSource.fileName but guaranteed to be non-null.
+ runtimeSourceURL: string,
+
// APIs from source-map for parsing source maps (if detected).
sourceConsumer: SourceConsumer | null,
// External URL of source map.
// Sources without source maps (or with inline source maps) won't have this.
sourceMapURL: string | null,
-
- // Parsed source map object.
- sourceMapContents: SourceMap | null,
|};
-type CachedMetadata = {|
- originalSourceAST: AST,
- originalSourceCode: string,
+type CachedRuntimeCodeMetadata = {|
sourceConsumer: SourceConsumer | null,
|};
-// On large trees, encoding takes significant time.
-// Try to reuse the already encoded strings.
-const fileNameToMetadataCache: LRUCache = new LRU({
+const runtimeURLToMetadataCache: LRUCache<
+ string,
+ CachedRuntimeCodeMetadata,
+> = new LRU({
max: 50,
- dispose: (fileName: string, metadata: CachedMetadata) => {
+ dispose: (runtimeSourceURL: string, metadata: CachedRuntimeCodeMetadata) => {
if (__DEBUG__) {
console.log(
- 'fileNameToHookSourceData.dispose() Evicting cached metadata for "' +
- fileName +
- '"',
+ `runtimeURLToMetadataCache.dispose() Evicting cached metadata for "${runtimeSourceURL}"`,
);
}
@@ -83,6 +83,36 @@ const fileNameToMetadataCache: LRUCache = new LRU({
},
});
+type CachedSourceCodeMetadata = {|
+ originalSourceAST: AST,
+ originalSourceCode: string,
+|};
+
+const originalURLToMetadataCache: LRUCache<
+ string,
+ CachedSourceCodeMetadata,
+> = new LRU({
+ max: 50,
+ dispose: (originalSourceURL: string, metadata: CachedSourceCodeMetadata) => {
+ if (__DEBUG__) {
+ console.log(
+ `originalURLToMetadataCache.dispose() Evicting cached metadata for "${originalSourceURL}"`,
+ );
+ }
+ },
+});
+
+function getLocationKey({
+ fileName,
+ lineNumber,
+ columnNumber,
+}: HookSource): string {
+ if (fileName == null || lineNumber == null || columnNumber == null) {
+ throw Error('Hook source code location not found.');
+ }
+ return `${fileName}:${lineNumber}:${columnNumber}`;
+}
+
export default async function parseHookNames(
hooksTree: HooksTree,
): Thenable {
@@ -97,8 +127,8 @@ export default async function parseHookNames(
console.log('parseHookNames() hooksList:', hooksList);
}
- // Gather the unique set of source files to load for the built-in hooks.
- const fileNameToHookSourceData: Map = new Map();
+ // Create map of unique source locations (file names plus line and column numbers) to metadata about hooks.
+ const locationKeyToHookSourceData: Map = new Map();
for (let i = 0; i < hooksList.length; i++) {
const hook = hooksList[i];
@@ -109,50 +139,47 @@ export default async function parseHookNames(
throw Error('Hook source code location not found.');
}
- const fileName = hookSource.fileName;
- if (fileName == null) {
- throw Error('Hook source code location not found.');
- } else {
- if (!fileNameToHookSourceData.has(fileName)) {
- const hookSourceData: HookSourceData = {
- hookSource,
- originalSourceAST: null,
- originalSourceCode: null,
- runtimeSourceCode: null,
- sourceConsumer: null,
- sourceMapURL: null,
- sourceMapContents: null,
- };
-
- // If we've already loaded source/source map info for this file,
- // we can skip reloading it (and more importantly, re-parsing it).
- const metadata = fileNameToMetadataCache.get(fileName);
- if (metadata != null) {
- if (__DEBUG__) {
- console.groupCollapsed(
- 'parseHookNames() Found cached metadata for file "' +
- fileName +
- '"',
- );
- console.log(metadata);
- console.groupEnd();
- }
-
- hookSourceData.originalSourceAST = metadata.originalSourceAST;
- hookSourceData.originalSourceCode = metadata.originalSourceCode;
- hookSourceData.sourceConsumer = metadata.sourceConsumer;
+ const locationKey = getLocationKey(hookSource);
+ if (!locationKeyToHookSourceData.has(locationKey)) {
+ // Can't be null because getLocationKey() would have thrown
+ const runtimeSourceURL = ((hookSource.fileName: any): string);
+
+ const hookSourceData: HookSourceData = {
+ hookSource,
+ originalSourceAST: null,
+ originalSourceCode: null,
+ originalSourceURL: null,
+ runtimeSourceCode: null,
+ runtimeSourceURL,
+ sourceConsumer: null,
+ sourceMapURL: null,
+ };
+
+ // If we've already loaded the source map info for this file,
+ // we can skip reloading it (and more importantly, re-parsing it).
+ const runtimeMetadata = runtimeURLToMetadataCache.get(
+ hookSourceData.runtimeSourceURL,
+ );
+ if (runtimeMetadata != null) {
+ if (__DEBUG__) {
+ console.groupCollapsed(
+ `parseHookNames() Found cached runtime metadata for file "${hookSourceData.runtimeSourceURL}"`,
+ );
+ console.log(runtimeMetadata);
+ console.groupEnd();
}
-
- fileNameToHookSourceData.set(fileName, hookSourceData);
+ hookSourceData.sourceConsumer = runtimeMetadata.sourceConsumer;
}
+
+ locationKeyToHookSourceData.set(locationKey, hookSourceData);
}
}
- return loadSourceFiles(fileNameToHookSourceData)
- .then(() => extractAndLoadSourceMaps(fileNameToHookSourceData))
- .then(() => parseSourceAST(fileNameToHookSourceData))
- .then(() => updateLruCache(fileNameToHookSourceData))
- .then(() => findHookNames(hooksList, fileNameToHookSourceData));
+ return loadSourceFiles(locationKeyToHookSourceData)
+ .then(() => extractAndLoadSourceMaps(locationKeyToHookSourceData))
+ .then(() => parseSourceAST(locationKeyToHookSourceData))
+ .then(() => updateLruCache(locationKeyToHookSourceData))
+ .then(() => findHookNames(hooksList, locationKeyToHookSourceData));
}
function decodeBase64String(encoded: string): Object {
@@ -170,12 +197,31 @@ function decodeBase64String(encoded: string): Object {
}
function extractAndLoadSourceMaps(
- fileNameToHookSourceData: Map,
+ locationKeyToHookSourceData: Map,
): Promise<*> {
- const promises = [];
- fileNameToHookSourceData.forEach(hookSourceData => {
- if (hookSourceData.originalSourceAST !== null) {
- // Use cached metadata.
+ // SourceMapConsumer.initialize() does nothing when running in Node (aka Jest)
+ // because the wasm file is automatically read from the file system
+ // so we can avoid triggering a warning message about this.
+ if (!__TEST__) {
+ if (__DEBUG__) {
+ console.log(
+ 'extractAndLoadSourceMaps() Initializing source-map library ...',
+ );
+ }
+
+ // $FlowFixMe
+ const wasmMappingsURL = chrome.extension.getURL('mappings.wasm');
+
+ SourceMapConsumer.initialize({'lib/mappings.wasm': wasmMappingsURL});
+ }
+
+ // Deduplicate fetches, since there can be multiple location keys per source map.
+ const fetchPromises = new Map();
+
+ const setPromises = [];
+ locationKeyToHookSourceData.forEach(hookSourceData => {
+ if (hookSourceData.sourceConsumer != null) {
+ // Use cached source map consumer.
return;
}
@@ -189,9 +235,13 @@ function extractAndLoadSourceMaps(
}
} else {
for (let i = 0; i < sourceMappingURLs.length; i++) {
+ const {runtimeSourceURL} = hookSourceData;
const sourceMappingURL = sourceMappingURLs[i];
const index = sourceMappingURL.indexOf('base64,');
if (index >= 0) {
+ // TODO (named hooks) deduplicate parsing in this branch (similar to fetching in the other branch)
+ // since there can be multiple location keys per source map.
+
// Web apps like Code Sandbox embed multiple inline source maps.
// In this case, we need to loop through and find the right one.
// We may also need to trim any part of this string that isn't based64 encoded data.
@@ -211,13 +261,17 @@ function extractAndLoadSourceMaps(
// Hook source might be a URL like "https://4syus.csb.app/src/App.js"
// Parsed source map might be a partial path like "src/App.js"
- const fileName = ((hookSourceData.hookSource.fileName: any): string);
const match = parsed.sources.find(
source =>
- source === 'Inline Babel script' || fileName.includes(source),
+ source === 'Inline Babel script' ||
+ runtimeSourceURL.endsWith(source),
);
if (match) {
- hookSourceData.sourceMapContents = parsed;
+ setPromises.push(
+ new SourceMapConsumer(parsed).then(sourceConsumer => {
+ hookSourceData.sourceConsumer = sourceConsumer;
+ }),
+ );
break;
}
} else {
@@ -227,7 +281,7 @@ function extractAndLoadSourceMaps(
);
}
- let url = sourceMappingURLs[0].split('=')[1];
+ let url = sourceMappingURLs[i].split('=')[1];
if (ABSOLUTE_URL_REGEX.test(url)) {
const baseURL = url.slice(0, url.lastIndexOf('/'));
url = `${baseURL}/${url}`;
@@ -235,19 +289,38 @@ function extractAndLoadSourceMaps(
if (!isValidUrl(url)) {
throw new Error(`Invalid source map URL "${url}"`);
}
+ } else if (!url.startsWith('/')) {
+ // Resolve paths relative to the location of the file name
+ const lastSlashIdx = runtimeSourceURL.lastIndexOf('/');
+ if (lastSlashIdx !== -1) {
+ const baseURL = runtimeSourceURL.slice(
+ 0,
+ runtimeSourceURL.lastIndexOf('/'),
+ );
+ url = `${baseURL}/${url}`;
+ }
}
hookSourceData.sourceMapURL = url;
- if (__DEBUG__) {
- console.log(
- 'extractAndLoadSourceMaps() External source map "' + url + '"',
+ const fetchPromise =
+ fetchPromises.get(url) ||
+ fetchFile(url).then(
+ sourceMapContents =>
+ new SourceMapConsumer(JSON.parse(sourceMapContents)),
);
+ if (__DEBUG__) {
+ if (!fetchPromises.has(url)) {
+ console.log(
+ `extractAndLoadSourceMaps() External source map "${url}"`,
+ );
+ }
}
- promises.push(
- fetchFile(url).then(sourceMapContents => {
- hookSourceData.sourceMapContents = JSON.parse(sourceMapContents);
+ fetchPromises.set(url, fetchPromise);
+ setPromises.push(
+ fetchPromise.then(sourceConsumer => {
+ hookSourceData.sourceConsumer = sourceConsumer;
}),
);
break;
@@ -255,7 +328,7 @@ function extractAndLoadSourceMaps(
}
}
});
- return Promise.all(promises);
+ return Promise.all(setPromises);
}
function fetchFile(url: string): Promise {
@@ -268,9 +341,15 @@ function fetchFile(url: string): Promise {
resolve(text);
})
.catch(error => {
+ if (__DEBUG__) {
+ console.log(`fetchFile() Could not read text for url "${url}"`);
+ }
reject(null);
});
} else {
+ if (__DEBUG__) {
+ console.log(`fetchFile() Got bad response for url "${url}"`);
+ }
reject(null);
}
});
@@ -279,11 +358,13 @@ function fetchFile(url: string): Promise {
function findHookNames(
hooksList: Array,
- fileNameToHookSourceData: Map,
+ locationKeyToHookSourceData: Map,
): HookNames {
const map: HookNames = new Map();
hooksList.map(hook => {
+ // TODO (named hooks) We should probably filter before this point,
+ // otherwise we are loading and parsing source maps and ASTs for nothing.
if (isNonDeclarativePrimitiveHook(hook)) {
if (__DEBUG__) {
console.log('findHookNames() Non declarative primitive hook');
@@ -300,7 +381,8 @@ function findHookNames(
return null; // Should not be reachable.
}
- const hookSourceData = fileNameToHookSourceData.get(fileName);
+ const locationKey = getLocationKey(hookSource);
+ const hookSourceData = locationKeyToHookSourceData.get(locationKey);
if (!hookSourceData) {
return null; // Should not be reachable.
}
@@ -321,7 +403,10 @@ function findHookNames(
} else {
originalSourceLineNumber = sourceConsumer.originalPositionFor({
line: lineNumber,
- column: columnNumber,
+
+ // 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;
}
@@ -346,7 +431,7 @@ function findHookNames(
);
if (__DEBUG__) {
- console.log('findHookNames() Found name "' + (name || '-') + '"');
+ console.log(`findHookNames() Found name "${name || '-'}"`);
}
map.set(hook, name);
@@ -366,103 +451,133 @@ function isValidUrl(possibleURL: string): boolean {
}
function loadSourceFiles(
- fileNameToHookSourceData: Map,
+ locationKeyToHookSourceData: Map,
): Promise<*> {
- const promises = [];
- fileNameToHookSourceData.forEach((hookSourceData, fileName) => {
- promises.push(
- fetchFile(fileName).then(runtimeSourceCode => {
+ // Deduplicate fetches, since there can be multiple location keys per file.
+ const fetchPromises = new Map();
+
+ const setPromises = [];
+ locationKeyToHookSourceData.forEach(hookSourceData => {
+ const {runtimeSourceURL} = hookSourceData;
+ const fetchPromise =
+ fetchPromises.get(runtimeSourceURL) ||
+ fetchFile(runtimeSourceURL).then(runtimeSourceCode => {
if (runtimeSourceCode.length > MAX_SOURCE_LENGTH) {
throw Error('Source code too large to parse');
}
-
if (__DEBUG__) {
console.groupCollapsed(
- 'loadSourceFiles() fileName "' + fileName + '"',
+ `loadSourceFiles() runtimeSourceURL "${runtimeSourceURL}"`,
);
console.log(runtimeSourceCode);
console.groupEnd();
}
-
+ return runtimeSourceCode;
+ });
+ fetchPromises.set(runtimeSourceURL, fetchPromise);
+ setPromises.push(
+ fetchPromise.then(runtimeSourceCode => {
hookSourceData.runtimeSourceCode = runtimeSourceCode;
}),
);
});
- return Promise.all(promises);
+ return Promise.all(setPromises);
}
async function parseSourceAST(
- fileNameToHookSourceData: Map,
+ locationKeyToHookSourceData: Map,
): Promise<*> {
- // SourceMapConsumer.initialize() does nothing when running in Node (aka Jest)
- // because the wasm file is automatically read from the file system
- // so we can avoid triggering a warning message about this.
- if (!__TEST__) {
- if (__DEBUG__) {
- console.log('parseSourceAST() Initializing source-map library ...');
- }
-
- // $FlowFixMe
- const wasmMappingsURL = chrome.extension.getURL('mappings.wasm');
-
- SourceMapConsumer.initialize({'lib/mappings.wasm': wasmMappingsURL});
- }
-
- const promises = [];
- fileNameToHookSourceData.forEach(hookSourceData => {
+ locationKeyToHookSourceData.forEach(hookSourceData => {
if (hookSourceData.originalSourceAST !== null) {
// Use cached metadata.
return;
}
- const {runtimeSourceCode, sourceMapContents} = hookSourceData;
- if (sourceMapContents !== null) {
+ const {sourceConsumer} = hookSourceData;
+ const runtimeSourceCode = ((hookSourceData.runtimeSourceCode: any): string);
+ let originalSourceURL, originalSourceCode;
+ if (sourceConsumer !== null) {
// Parse and extract the AST from the source map.
- promises.push(
- SourceMapConsumer.with(
- sourceMapContents,
- null,
- (sourceConsumer: SourceConsumer) => {
- hookSourceData.sourceConsumer = sourceConsumer;
-
- // Now that the source map has been loaded,
- // extract the original source for later.
- const source = sourceMapContents.sources[0];
- const originalSourceCode = sourceConsumer.sourceContentFor(
- source,
- true,
- );
+ const {lineNumber, columnNumber} = hookSourceData.hookSource;
+ if (lineNumber == null || columnNumber == null) {
+ throw Error('Hook source code location not found.');
+ }
+ // Now that the source map has been loaded,
+ // extract the original source for later.
+ const {source} = sourceConsumer.originalPositionFor({
+ line: lineNumber,
- if (__DEBUG__) {
- console.groupCollapsed(
- 'parseSourceAST() Extracted source code from source map',
- );
- console.log(originalSourceCode);
- console.groupEnd();
- }
+ // Column numbers are representated differently between tools/engines.
+ // For more info see https://github.com/facebook/react/issues/21792#issuecomment-873171991
+ column: columnNumber - 1,
+ });
+
+ if (source == null) {
+ // TODO (named hooks) maybe fall back to the runtime source instead of throwing?
+ throw new Error(
+ 'Could not map hook runtime location to original source location',
+ );
+ }
- hookSourceData.originalSourceCode = originalSourceCode;
+ // TODO (named hooks) maybe canonicalize this URL somehow?
+ // It can be relative if the source map specifies it that way,
+ // but we use it as a cache key across different source maps and there can be collisions.
+ originalSourceURL = (source: string);
+ originalSourceCode = (sourceConsumer.sourceContentFor(
+ source,
+ true,
+ ): string);
- // TODO Parsing should ideally be done off of the main thread.
- hookSourceData.originalSourceAST = parse(originalSourceCode, {
- sourceType: 'unambiguous',
- plugins: ['jsx', 'typescript'],
- });
- },
- ),
- );
+ if (__DEBUG__) {
+ console.groupCollapsed(
+ 'parseSourceAST() Extracted source code from source map',
+ );
+ console.log(originalSourceCode);
+ console.groupEnd();
+ }
} else {
// There's no source map to parse here so we can just parse the original source itself.
- hookSourceData.originalSourceCode = runtimeSourceCode;
+ originalSourceCode = runtimeSourceCode;
+ // TODO (named hooks) This mixes runtimeSourceURLs with source mapped URLs in the same cache key space.
+ // Namespace them?
+ originalSourceURL = hookSourceData.runtimeSourceURL;
+ }
+
+ hookSourceData.originalSourceCode = originalSourceCode;
+ hookSourceData.originalSourceURL = originalSourceURL;
- // TODO Parsing should ideally be done off of the main thread.
- hookSourceData.originalSourceAST = parse(runtimeSourceCode, {
+ // The cache also serves to deduplicate parsing by URL in our loop over
+ // location keys. This may need to change if we switch to async parsing.
+ const sourceMetadata = originalURLToMetadataCache.get(originalSourceURL);
+ if (sourceMetadata != null) {
+ if (__DEBUG__) {
+ console.groupCollapsed(
+ `parseSourceAST() Found cached source metadata for "${originalSourceURL}"`,
+ );
+ console.log(sourceMetadata);
+ console.groupEnd();
+ }
+ hookSourceData.originalSourceAST = sourceMetadata.originalSourceAST;
+ hookSourceData.originalSourceCode = sourceMetadata.originalSourceCode;
+ } else {
+ // TODO (named hooks) Parsing should ideally be done off of the main thread.
+ const originalSourceAST = parse(originalSourceCode, {
sourceType: 'unambiguous',
plugins: ['jsx', 'typescript'],
});
+ hookSourceData.originalSourceAST = originalSourceAST;
+ if (__DEBUG__) {
+ console.log(
+ `parseSourceAST() Caching source metadata for "${originalSourceURL}"`,
+ );
+ }
+ originalURLToMetadataCache.set(originalSourceURL, {
+ originalSourceAST,
+ originalSourceCode,
+ });
}
});
- return Promise.all(promises);
+ return Promise.resolve();
}
function flattenHooksList(
@@ -479,23 +594,21 @@ function flattenHooksList(
}
function updateLruCache(
- fileNameToHookSourceData: Map,
+ locationKeyToHookSourceData: Map,
): Promise<*> {
- fileNameToHookSourceData.forEach(
- ({originalSourceAST, originalSourceCode, sourceConsumer}, fileName) => {
- // Only set once to avoid triggering eviction/cleanup code.
- if (!fileNameToMetadataCache.has(fileName)) {
- if (__DEBUG__) {
- console.log('updateLruCache() Caching metada for "' + fileName + '"');
- }
-
- fileNameToMetadataCache.set(fileName, {
- originalSourceAST,
- originalSourceCode: ((originalSourceCode: any): string),
- sourceConsumer,
- });
+ locationKeyToHookSourceData.forEach(({sourceConsumer, runtimeSourceURL}) => {
+ // Only set once to avoid triggering eviction/cleanup code.
+ if (!runtimeURLToMetadataCache.has(runtimeSourceURL)) {
+ if (__DEBUG__) {
+ console.log(
+ `updateLruCache() Caching runtime metadata for "${runtimeSourceURL}"`,
+ );
}
- },
- );
+
+ runtimeURLToMetadataCache.set(runtimeSourceURL, {
+ sourceConsumer,
+ });
+ }
+ });
return Promise.resolve();
}
diff --git a/packages/react-devtools-shared/src/hookNamesCache.js b/packages/react-devtools-shared/src/hookNamesCache.js
index 6b3ca25af28..1b979c8e191 100644
--- a/packages/react-devtools-shared/src/hookNamesCache.js
+++ b/packages/react-devtools-shared/src/hookNamesCache.js
@@ -9,6 +9,7 @@
import {unstable_getCacheForType as getCacheForType} from 'react';
import {enableHookNameParsing} from 'react-devtools-feature-flags';
+import {__DEBUG__} from 'react-devtools-shared/src/constants';
import type {HooksTree} from 'react-debug-tools/src/ReactDebugHooks';
import type {Thenable, Wakeable} from 'shared/ReactTypes';
@@ -108,6 +109,10 @@ export function loadHookNames(
return;
}
+ if (__DEBUG__) {
+ console.log('[hookNamesCache] onSuccess() hookNames:', hookNames);
+ }
+
if (hookNames) {
const resolvedRecord = ((newRecord: any): ResolvedRecord);
resolvedRecord.status = Resolved;
@@ -121,6 +126,10 @@ export function loadHookNames(
wake();
},
function onError(error) {
+ if (__DEBUG__) {
+ console.log('[hookNamesCache] onError() error:', error);
+ }
+
if (didTimeout) {
return;
}
@@ -134,7 +143,11 @@ export function loadHookNames(
);
// Eventually timeout and stop trying to load names.
- let timeoutID = setTimeout(() => {
+ let timeoutID = setTimeout(function onTimeout() {
+ if (__DEBUG__) {
+ console.log('[hookNamesCache] onTimeout()');
+ }
+
timeoutID = null;
didTimeout = true;