From 2dc9aa5a900673031670d8928d561f0c723ff0d4 Mon Sep 17 00:00:00 2001 From: Jason Laster Date: Mon, 1 Apr 2019 12:49:18 +0000 Subject: [PATCH] Bug 1539493 - Remove source metadata. r=loganfsmyth Differential Revision: https://phabricator.services.mozilla.com/D25122 --HG-- extra : moz-landing-system : lando --- .../debugger/new/bin/module-manifest.json | 14 +-- .../client/debugger/new/dist/parser-worker.js | 53 ++++----- .../client/debugger/new/src/actions/ast.js | 59 +--------- .../debugger/new/src/actions/sources/index.js | 1 + .../new/src/actions/sources/moz.build | 1 + .../new/src/actions/sources/prettyPrint.js | 2 +- .../new/src/actions/sources/select.js | 3 +- .../new/src/actions/sources/symbols.js | 39 +++++++ .../src/actions/sources/tests/select.spec.js | 7 +- .../new/src/actions/tests/ast.spec.js | 69 ++++++------ .../new/src/actions/types/ASTAction.js | 6 -- .../new/src/components/shared/SourceIcon.js | 14 +-- .../client/debugger/new/src/reducers/ast.js | 30 ++---- .../client/debugger/new/src/reducers/types.js | 2 +- .../debugger/new/src/selectors/inComponent.js | 11 +- .../client/debugger/new/src/utils/source.js | 14 +-- .../new/src/utils/tests/source.spec.js | 3 +- .../new/src/workers/parser/frameworks.js | 30 ++---- .../new/src/workers/parser/getSymbols.js | 6 +- .../__snapshots__/getSymbols.spec.js.snap | 72 +++++++++---- .../workers/parser/tests/framework.spec.js | 102 +++++++++--------- .../src/workers/parser/utils/formatSymbols.js | 9 ++ .../debugger/new/test/mochitest/helpers.js | 7 +- .../tests/debugger/debugger-helpers.js | 11 +- 24 files changed, 265 insertions(+), 300 deletions(-) create mode 100644 devtools/client/debugger/new/src/actions/sources/symbols.js diff --git a/devtools/client/debugger/new/bin/module-manifest.json b/devtools/client/debugger/new/bin/module-manifest.json index be3b8dc32b26..ca68be21115e 100644 --- a/devtools/client/debugger/new/bin/module-manifest.json +++ b/devtools/client/debugger/new/bin/module-manifest.json @@ -15,7 +15,7 @@ "byName": {}, "byBlocks": {}, "usedIds": { - "0": 0 + "1": 1 } } } @@ -36,7 +36,7 @@ "byName": {}, "byBlocks": {}, "usedIds": { - "0": 0 + "1": 1 } } } @@ -57,7 +57,7 @@ "byName": {}, "byBlocks": {}, "usedIds": { - "0": 0 + "1": 1 } } } @@ -78,7 +78,7 @@ "byName": {}, "byBlocks": {}, "usedIds": { - "0": 0 + "1": 1 } } } @@ -99,7 +99,7 @@ "byName": {}, "byBlocks": {}, "usedIds": { - "0": 0 + "1": 1 } } } @@ -120,7 +120,7 @@ "byName": {}, "byBlocks": {}, "usedIds": { - "0": 0 + "1": 1 } } } @@ -141,7 +141,7 @@ "byName": {}, "byBlocks": {}, "usedIds": { - "0": 0 + "1": 1 } } } diff --git a/devtools/client/debugger/new/dist/parser-worker.js b/devtools/client/debugger/new/dist/parser-worker.js index a87c14d0a017..bf9b53a5d8fe 100644 --- a/devtools/client/debugger/new/dist/parser-worker.js +++ b/devtools/client/debugger/new/dist/parser-worker.js @@ -15207,15 +15207,15 @@ var _getFunctionName = __webpack_require__(158); var _getFunctionName2 = _interopRequireDefault(_getFunctionName); +var _frameworks = __webpack_require__(159); + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at . */ - -let symbolDeclarations = new Map(); +let symbolDeclarations = new Map(); /* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ function getUniqueIdentifiers(identifiers) { const newIdentifiers = []; @@ -15401,7 +15401,8 @@ function extractSymbols(sourceId) { literals: [], hasJsx: false, hasTypes: false, - loading: false + loading: false, + framework: undefined }; const state = { @@ -15424,6 +15425,7 @@ function extractSymbols(sourceId) { // comments are extracted separately from the AST symbols.comments = (0, _helpers.getComments)(ast); symbols.identifiers = getUniqueIdentifiers(symbols.identifiers); + symbols.framework = (0, _frameworks.getFramework)(symbols); return symbols; } @@ -17464,32 +17466,23 @@ var _types = __webpack_require__(3); var t = _interopRequireWildcard(_types); -var _getSymbols = __webpack_require__(117); - function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at . */ - -function getFramework(sourceId) { - const sourceSymbols = (0, _getSymbols.getSymbols)(sourceId); - - if (isReactComponent(sourceSymbols)) { +function getFramework(symbols) { + if (isReactComponent(symbols)) { return "React"; } - if (isAngularComponent(sourceSymbols)) { + if (isAngularComponent(symbols)) { return "Angular"; } - if (isVueComponent(sourceSymbols)) { + if (isVueComponent(symbols)) { return "Vue"; } -} +} /* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ -// React - -function isReactComponent(sourceSymbols) { - const { imports, classes, callExpressions } = sourceSymbols; +function isReactComponent({ imports, classes, callExpressions }) { return importsReact(imports) || requiresReact(callExpressions) || extendsReactComponent(classes); } @@ -17505,19 +17498,13 @@ function extendsReactComponent(classes) { return classes.some(classObj => t.isIdentifier(classObj.parent, { name: "Component" }) || t.isIdentifier(classObj.parent, { name: "PureComponent" }) || t.isMemberExpression(classObj.parent, { computed: false }) && t.isIdentifier(classObj.parent, { name: "Component" })); } -// Angular - -const isAngularComponent = sourceSymbols => { - const { memberExpressions } = sourceSymbols; +function isAngularComponent({ memberExpressions }) { return memberExpressions.some(item => item.expression == "angular.controller" || item.expression == "angular.module"); -}; +} -// Vue - -const isVueComponent = sourceSymbols => { - const { identifiers } = sourceSymbols; +function isVueComponent({ identifiers }) { return identifiers.some(identifier => identifier.name == "Vue"); -}; +} /***/ }), /* 160 */ diff --git a/devtools/client/debugger/new/src/actions/ast.js b/devtools/client/debugger/new/src/actions/ast.js index 01d42754faf9..676ecc905b31 100644 --- a/devtools/client/debugger/new/src/actions/ast.js +++ b/devtools/client/debugger/new/src/actions/ast.js @@ -4,18 +4,7 @@ // @flow -import { - getSource, - getSourceFromId, - getSourceThreads, - getSymbols, - getSelectedLocation -} from "../selectors"; - -import { mapFrames } from "./pause"; -import { updateTab } from "./tabs"; - -import { PROMISE } from "./utils/middleware/promise"; +import { getSourceFromId, getSelectedLocation } from "../selectors"; import { setInScopeLines } from "./ast/setInScopeLines"; @@ -23,54 +12,8 @@ import * as parser from "../workers/parser"; import { isLoaded } from "../utils/source"; -import type { SourceId } from "../types"; import type { ThunkArgs, Action } from "./types"; -export function setSourceMetaData(sourceId: SourceId) { - return async ({ dispatch, getState }: ThunkArgs) => { - const source = getSource(getState(), sourceId); - if (!source || !isLoaded(source) || source.isWasm) { - return; - } - - const framework = await parser.getFramework(source.id); - if (framework) { - dispatch(updateTab(source, framework)); - } - - dispatch( - ({ - type: "SET_SOURCE_METADATA", - sourceId: source.id, - sourceMetaData: { - framework - } - }: Action) - ); - }; -} - -export function setSymbols(sourceId: SourceId) { - return async ({ dispatch, getState, sourceMaps }: ThunkArgs) => { - const source = getSourceFromId(getState(), sourceId); - - if (source.isWasm || getSymbols(getState(), source) || !isLoaded(source)) { - return; - } - - await dispatch({ - type: "SET_SYMBOLS", - sourceId, - [PROMISE]: parser.getSymbols(sourceId) - }); - - const threads = getSourceThreads(getState(), source); - await Promise.all(threads.map(thread => dispatch(mapFrames(thread)))); - - await dispatch(setSourceMetaData(sourceId)); - }; -} - export function setOutOfScopeLocations() { return async ({ dispatch, getState }: ThunkArgs) => { const location = getSelectedLocation(getState()); diff --git a/devtools/client/debugger/new/src/actions/sources/index.js b/devtools/client/debugger/new/src/actions/sources/index.js index 458d35509dd2..8bd752ddc775 100644 --- a/devtools/client/debugger/new/src/actions/sources/index.js +++ b/devtools/client/debugger/new/src/actions/sources/index.js @@ -8,3 +8,4 @@ export * from "./loadSourceText"; export * from "./newSources"; export * from "./prettyPrint"; export * from "./select"; +export { setSymbols } from "./symbols"; diff --git a/devtools/client/debugger/new/src/actions/sources/moz.build b/devtools/client/debugger/new/src/actions/sources/moz.build index 20989c0d024b..009f83777652 100644 --- a/devtools/client/debugger/new/src/actions/sources/moz.build +++ b/devtools/client/debugger/new/src/actions/sources/moz.build @@ -14,4 +14,5 @@ CompiledModules( 'newSources.js', 'prettyPrint.js', 'select.js', + 'symbols.js' ) diff --git a/devtools/client/debugger/new/src/actions/sources/prettyPrint.js b/devtools/client/debugger/new/src/actions/sources/prettyPrint.js index 924019f88051..2f50cf1b57bc 100644 --- a/devtools/client/debugger/new/src/actions/sources/prettyPrint.js +++ b/devtools/client/debugger/new/src/actions/sources/prettyPrint.js @@ -8,7 +8,7 @@ import assert from "../../utils/assert"; import { recordEvent } from "../../utils/telemetry"; import { remapBreakpoints } from "../breakpoints"; -import { setSymbols } from "../ast"; +import { setSymbols } from "./symbols"; import { prettyPrint } from "../../workers/pretty-print"; import { getPrettySourceURL, isLoaded } from "../../utils/source"; import { loadSourceText } from "./loadSourceText"; diff --git a/devtools/client/debugger/new/src/actions/sources/select.js b/devtools/client/debugger/new/src/actions/sources/select.js index 5616679c4685..85a373da641d 100644 --- a/devtools/client/debugger/new/src/actions/sources/select.js +++ b/devtools/client/debugger/new/src/actions/sources/select.js @@ -13,7 +13,8 @@ import { isOriginalId } from "devtools-source-map"; import { getSourceFromId } from "../../reducers/sources"; import { getSourcesForTabs } from "../../reducers/tabs"; -import { setOutOfScopeLocations, setSymbols } from "../ast"; +import { setOutOfScopeLocations } from "../ast"; +import { setSymbols } from "./symbols"; import { closeActiveSearch, updateActiveFileSearch } from "../ui"; import { togglePrettyPrint } from "./prettyPrint"; diff --git a/devtools/client/debugger/new/src/actions/sources/symbols.js b/devtools/client/debugger/new/src/actions/sources/symbols.js new file mode 100644 index 000000000000..ba82957a4be5 --- /dev/null +++ b/devtools/client/debugger/new/src/actions/sources/symbols.js @@ -0,0 +1,39 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at . */ +import { getSourceFromId, getSourceThreads, getSymbols } from "../../selectors"; + +import { PROMISE } from "../utils/middleware/promise"; +import { mapFrames } from "../pause"; +import { updateTab } from "../tabs"; + +import * as parser from "../../workers/parser"; + +import { isLoaded } from "../../utils/source"; + +import type { SourceId } from "../../types"; +import type { ThunkArgs } from "../types"; + +export function setSymbols(sourceId: SourceId) { + return async ({ dispatch, getState, sourceMaps }: ThunkArgs) => { + const source = getSourceFromId(getState(), sourceId); + + if (source.isWasm || getSymbols(getState(), source) || !isLoaded(source)) { + return; + } + + await dispatch({ + type: "SET_SYMBOLS", + sourceId, + [PROMISE]: parser.getSymbols(sourceId) + }); + + const threads = getSourceThreads(getState(), source); + await Promise.all(threads.map(thread => dispatch(mapFrames(thread)))); + + const symbols = getSymbols(getState(), source); + if (symbols.framework) { + dispatch(updateTab(source, symbols.framework)); + } + }; +} diff --git a/devtools/client/debugger/new/src/actions/sources/tests/select.spec.js b/devtools/client/debugger/new/src/actions/sources/tests/select.spec.js index 891bc271c48f..94c07c61270e 100644 --- a/devtools/client/debugger/new/src/actions/sources/tests/select.spec.js +++ b/devtools/client/debugger/new/src/actions/sources/tests/select.spec.js @@ -19,7 +19,6 @@ const { getSourceCount, getSelectedSource, getSourceTabs, - getSourceMetaData, getOutOfScopeLocations, getSelectedLocation } = selectors; @@ -67,11 +66,7 @@ describe("sources", () => { } expect(source.id).toEqual("foo1"); - await waitForState( - store, - state => - getOutOfScopeLocations(state) && getSourceMetaData(state, source.id) - ); + await waitForState(store, state => getOutOfScopeLocations(state)); const locations = getOutOfScopeLocations(getState()); expect(locations).toHaveLength(1); }); diff --git a/devtools/client/debugger/new/src/actions/tests/ast.spec.js b/devtools/client/debugger/new/src/actions/tests/ast.spec.js index c57c555b026f..116e021381f0 100644 --- a/devtools/client/debugger/new/src/actions/tests/ast.spec.js +++ b/devtools/client/debugger/new/src/actions/tests/ast.spec.js @@ -20,9 +20,9 @@ const { getSource, getSymbols, getOutOfScopeLocations, - getSourceMetaData, getInScopeLines, - isSymbolsLoading + isSymbolsLoading, + getFramework } = selectors; import { prefs } from "../../utils/prefs"; @@ -63,41 +63,6 @@ const evaluationResult = { }; describe("ast", () => { - describe("setSourceMetaData", () => { - it("should detect react components", async () => { - const store = createStore(threadClient, {}, sourceMaps); - const { dispatch, getState } = store; - const source = makeOriginalSource("reactComponent.js"); - - await dispatch(actions.newSource(makeSource("reactComponent.js"))); - - await dispatch(actions.newSource(source)); - - await dispatch(actions.loadSourceText(getSource(getState(), source.id))); - await dispatch(actions.setSourceMetaData(source.id)); - - await waitForState(store, state => { - const metaData = getSourceMetaData(state, source.id); - return metaData && metaData.framework; - }); - - const sourceMetaData = getSourceMetaData(getState(), source.id); - expect(sourceMetaData.framework).toBe("React"); - }); - - it("should not give false positive on non react components", async () => { - const store = createStore(threadClient); - const { dispatch, getState } = store; - const base = makeSource("base.js"); - await dispatch(actions.newSource(base)); - await dispatch(actions.loadSourceText(base)); - await dispatch(actions.setSourceMetaData("base.js")); - - const sourceMetaData = getSourceMetaData(getState(), base.id); - expect(sourceMetaData.framework).toBe(undefined); - }); - }); - describe("setSymbols", () => { describe("when the source is loaded", () => { it("should be able to set symbols", async () => { @@ -132,6 +97,36 @@ describe("ast", () => { expect(baseSymbols).toEqual(null); }); }); + + describe("frameworks", () => { + it("should detect react components", async () => { + const store = createStore(threadClient, {}, sourceMaps); + const { dispatch, getState } = store; + const source = makeOriginalSource("reactComponent.js"); + + await dispatch(actions.newSource(makeSource("reactComponent.js"))); + + await dispatch(actions.newSource(source)); + + await dispatch( + actions.loadSourceText(getSource(getState(), source.id)) + ); + await dispatch(actions.setSymbols(source.id)); + + expect(getFramework(getState(), source)).toBe("React"); + }); + + it("should not give false positive on non react components", async () => { + const store = createStore(threadClient); + const { dispatch, getState } = store; + const base = makeSource("base.js"); + await dispatch(actions.newSource(base)); + await dispatch(actions.loadSourceText(base)); + await dispatch(actions.setSymbols("base.js")); + + expect(getFramework(getState(), base)).toBe(undefined); + }); + }); }); describe("getOutOfScopeLocations", () => { diff --git a/devtools/client/debugger/new/src/actions/types/ASTAction.js b/devtools/client/debugger/new/src/actions/types/ASTAction.js index 2e3b5e287f0c..407a68cba56d 100644 --- a/devtools/client/debugger/new/src/actions/types/ASTAction.js +++ b/devtools/client/debugger/new/src/actions/types/ASTAction.js @@ -5,7 +5,6 @@ // @flow import type { SymbolDeclarations, AstLocation } from "../../workers/parser"; -import type { SourceMetaDataType } from "../../reducers/types"; import type { PromiseAction } from "../utils/middleware/promise"; export type ASTAction = @@ -36,11 +35,6 @@ export type ASTAction = cursorPos: any } > - | {| - +type: "SET_SOURCE_METADATA", - +sourceId: string, - +sourceMetaData: SourceMetaDataType - |} | {| +type: "CLEAR_SELECTION" |}; diff --git a/devtools/client/debugger/new/src/components/shared/SourceIcon.js b/devtools/client/debugger/new/src/components/shared/SourceIcon.js index 777b860ddd89..32903e766f6a 100644 --- a/devtools/client/debugger/new/src/components/shared/SourceIcon.js +++ b/devtools/client/debugger/new/src/components/shared/SourceIcon.js @@ -12,17 +12,17 @@ import AccessibleImage from "./AccessibleImage"; import { getSourceClassnames } from "../../utils/source"; import { getFramework } from "../../utils/tabs"; -import { getSourceMetaData, getTabs } from "../../selectors"; +import { getSymbols, getTabs } from "../../selectors"; import type { Source } from "../../types"; -import type { SourceMetaDataType } from "../../reducers/ast"; +import type { Symbols } from "../../reducers/types"; import "./SourceIcon.css"; type Props = { source: Source, - // sourceMetaData will provide framework information - sourceMetaData: SourceMetaDataType, + // symbols will provide framework information + symbols: Symbols, // An additional validator for the icon returned shouldHide?: Function, framework?: string @@ -30,10 +30,10 @@ type Props = { class SourceIcon extends PureComponent { render() { - const { shouldHide, source, sourceMetaData, framework } = this.props; + const { shouldHide, source, symbols, framework } = this.props; const iconClass = framework ? framework.toLowerCase() - : getSourceClassnames(source, sourceMetaData); + : getSourceClassnames(source, symbols); if (shouldHide && shouldHide(iconClass)) { return null; @@ -45,7 +45,7 @@ class SourceIcon extends PureComponent { export default connect((state, props) => { return { - sourceMetaData: getSourceMetaData(state, props.source.id), + symbols: getSymbols(state, props.source), framework: getFramework(getTabs(state), props.source.url) }; })(SourceIcon); diff --git a/devtools/client/debugger/new/src/reducers/ast.js b/devtools/client/debugger/new/src/reducers/ast.js index 4e63ae97aa56..29a1d861b0fd 100644 --- a/devtools/client/debugger/new/src/reducers/ast.js +++ b/devtools/client/debugger/new/src/reducers/ast.js @@ -43,8 +43,7 @@ export type ASTState = { +emptyLines: EmptyLinesMap, +outOfScopeLocations: ?Array, +inScopeLines: ?Array, - +preview: Preview, - +sourceMetaData: SourceMetaDataMap + +preview: Preview }; export function initialASTState(): ASTState { @@ -53,8 +52,7 @@ export function initialASTState(): ASTState { emptyLines: {}, outOfScopeLocations: null, inScopeLines: null, - preview: null, - sourceMetaData: {} + preview: null }; } @@ -113,14 +111,6 @@ function update(state: ASTState = initialASTState(), action: Action): ASTState { return initialASTState(); } - case "SET_SOURCE_METADATA": { - const { sourceId, sourceMetaData } = action; - return { - ...state, - sourceMetaData: { ...state.sourceMetaData, [sourceId]: sourceMetaData } - }; - } - default: { return state; } @@ -149,6 +139,13 @@ export function hasSymbols(state: OuterState, source: Source): boolean { return !symbols.loading; } +export function getFramework(state: OuterState, source: Source): ?string { + const symbols = getSymbols(state, source); + if (symbols && !symbols.loading) { + return symbols.framework; + } +} + export function isSymbolsLoading(state: OuterState, source: ?Source): boolean { const symbols = getSymbols(state, source); if (!symbols) { @@ -166,15 +163,6 @@ export function getPreview(state: OuterState) { return state.ast.preview; } -const emptySourceMetaData = {}; -export function getSourceMetaData(state: OuterState, sourceId: string) { - return state.ast.sourceMetaData[sourceId] || emptySourceMetaData; -} - -export function hasSourceMetaData(state: OuterState, sourceId: string) { - return state.ast.sourceMetaData[sourceId]; -} - export function getInScopeLines(state: OuterState) { return state.ast.inScopeLines; } diff --git a/devtools/client/debugger/new/src/reducers/types.js b/devtools/client/debugger/new/src/reducers/types.js index ad30f9ecc647..122450d755b1 100644 --- a/devtools/client/debugger/new/src/reducers/types.js +++ b/devtools/client/debugger/new/src/reducers/types.js @@ -50,4 +50,4 @@ export type { SourcesMap, SourcesMapByThread } from "./sources"; export type { ActiveSearchType, OrientationType } from "./ui"; export type { BreakpointsMap, XHRBreakpointsList } from "./breakpoints"; export type { Command } from "./pause"; -export type { SourceMetaDataMap, SourceMetaDataType } from "./ast"; +export type { Symbols } from "./ast"; diff --git a/devtools/client/debugger/new/src/selectors/inComponent.js b/devtools/client/debugger/new/src/selectors/inComponent.js index 99ef46687479..6647e0a6bb4c 100644 --- a/devtools/client/debugger/new/src/selectors/inComponent.js +++ b/devtools/client/debugger/new/src/selectors/inComponent.js @@ -6,7 +6,6 @@ import { getSymbols, getSource, getSelectedFrame, getCurrentThread } from "."; import { findClosestClass } from "../utils/ast"; -import { getSourceMetaData } from "../reducers/ast"; import type { State } from "../reducers/types"; @@ -24,7 +23,7 @@ export function inComponent(state: State) { const symbols = getSymbols(state, source); - if (!symbols) { + if (!symbols || symbols.loading) { return; } @@ -33,13 +32,7 @@ export function inComponent(state: State) { return null; } - const sourceMetaData = getSourceMetaData(state, source.id); - - if (!sourceMetaData || !sourceMetaData.framework) { - return; - } - - const inReactFile = sourceMetaData.framework == "React"; + const inReactFile = symbols.framework == "React"; const { parent } = closestClass; const isComponent = parent && parent.name.includes("Component"); diff --git a/devtools/client/debugger/new/src/utils/source.js b/devtools/client/debugger/new/src/utils/source.js index cfb1a46c0b7e..3cbbc17258f0 100644 --- a/devtools/client/debugger/new/src/utils/source.js +++ b/devtools/client/debugger/new/src/utils/source.js @@ -22,8 +22,7 @@ import { getURL, getFileExtension } from "./sources-tree"; import { prefs, features } from "./prefs"; import type { Source, SourceLocation, JsSource } from "../types"; -import type { SourceMetaDataType } from "../reducers/ast"; -import type { SymbolDeclarations } from "../workers/parser"; +import type { Symbols } from "../reducers/types"; type transformUrlCallback = string => string; @@ -316,7 +315,7 @@ export function getSourceLineCount(source: Source) { export function getMode( source: Source, - symbols?: SymbolDeclarations + symbols?: Symbols ): { name: string, base?: Object } { if (source.isWasm) { return { name: "text" }; @@ -430,10 +429,7 @@ export function getTextAtPosition(source: ?Source, location: SourceLocation) { return lineText.slice(column, column + 100).trim(); } -export function getSourceClassnames( - source: Object, - sourceMetaData?: SourceMetaDataType -) { +export function getSourceClassnames(source: Object, symbols?: Symbols) { // Conditionals should be ordered by priority of icon! const defaultClassName = "file"; @@ -449,8 +445,8 @@ export function getSourceClassnames( return "blackBox"; } - if (sourceMetaData && sourceMetaData.framework) { - return sourceMetaData.framework.toLowerCase(); + if (symbols && !symbols.loading && symbols.framework) { + return symbols.framework.toLowerCase(); } return sourceTypes[getFileExtension(source)] || defaultClassName; diff --git a/devtools/client/debugger/new/src/utils/tests/source.spec.js b/devtools/client/debugger/new/src/utils/tests/source.spec.js index 127d6ed84454..7cf4de8aa151 100644 --- a/devtools/client/debugger/new/src/utils/tests/source.spec.js +++ b/devtools/client/debugger/new/src/utils/tests/source.spec.js @@ -30,7 +30,8 @@ const defaultSymbolDeclarations = { literals: [], hasJsx: false, hasTypes: false, - loading: false + loading: false, + framework: undefined }; describe("sources", () => { diff --git a/devtools/client/debugger/new/src/workers/parser/frameworks.js b/devtools/client/debugger/new/src/workers/parser/frameworks.js index 35dfe0534cd7..f5fd40429ae8 100644 --- a/devtools/client/debugger/new/src/workers/parser/frameworks.js +++ b/devtools/client/debugger/new/src/workers/parser/frameworks.js @@ -5,26 +5,22 @@ // @flow import * as t from "@babel/types"; -import { getSymbols } from "./getSymbols"; -export function getFramework(sourceId: string): ?string { - const sourceSymbols = getSymbols(sourceId); +import type { SymbolDeclarations } from "./getSymbols"; - if (isReactComponent(sourceSymbols)) { +export function getFramework(symbols: SymbolDeclarations): ?string { + if (isReactComponent(symbols)) { return "React"; } - if (isAngularComponent(sourceSymbols)) { + if (isAngularComponent(symbols)) { return "Angular"; } - if (isVueComponent(sourceSymbols)) { + if (isVueComponent(symbols)) { return "Vue"; } } -// React - -function isReactComponent(sourceSymbols) { - const { imports, classes, callExpressions } = sourceSymbols; +function isReactComponent({ imports, classes, callExpressions }) { return ( importsReact(imports) || requiresReact(callExpressions) || @@ -58,20 +54,14 @@ function extendsReactComponent(classes) { ); } -// Angular - -const isAngularComponent = sourceSymbols => { - const { memberExpressions } = sourceSymbols; +function isAngularComponent({ memberExpressions }) { return memberExpressions.some( item => item.expression == "angular.controller" || item.expression == "angular.module" ); -}; +} -// Vue - -const isVueComponent = sourceSymbols => { - const { identifiers } = sourceSymbols; +function isVueComponent({ identifiers }) { return identifiers.some(identifier => identifier.name == "Vue"); -}; +} diff --git a/devtools/client/debugger/new/src/workers/parser/getSymbols.js b/devtools/client/debugger/new/src/workers/parser/getSymbols.js index 6618e85e276e..18be448fc596 100644 --- a/devtools/client/debugger/new/src/workers/parser/getSymbols.js +++ b/devtools/client/debugger/new/src/workers/parser/getSymbols.js @@ -23,6 +23,7 @@ import { import { inferClassName } from "./utils/inferClassName"; import getFunctionName from "./utils/getFunctionName"; +import { getFramework } from "./frameworks"; import type { SimplePath, Node, TraversalAncestors } from "./utils/simple-path"; @@ -80,6 +81,7 @@ export type SymbolDeclarations = {| literals: Array, hasJsx: boolean, hasTypes: boolean, + framework: ?string, loading: false |}; @@ -276,7 +278,8 @@ function extractSymbols(sourceId): SymbolDeclarations { literals: [], hasJsx: false, hasTypes: false, - loading: false + loading: false, + framework: undefined }; const state = { @@ -299,6 +302,7 @@ function extractSymbols(sourceId): SymbolDeclarations { // comments are extracted separately from the AST symbols.comments = getComments(ast); symbols.identifiers = getUniqueIdentifiers(symbols.identifiers); + symbols.framework = getFramework(symbols); return symbols; } diff --git a/devtools/client/debugger/new/src/workers/parser/tests/__snapshots__/getSymbols.spec.js.snap b/devtools/client/debugger/new/src/workers/parser/tests/__snapshots__/getSymbols.spec.js.snap index f8997cda19d4..eff1ee3d0f39 100644 --- a/devtools/client/debugger/new/src/workers/parser/tests/__snapshots__/getSymbols.spec.js.snap +++ b/devtools/client/debugger/new/src/workers/parser/tests/__snapshots__/getSymbols.spec.js.snap @@ -85,7 +85,9 @@ hasJsx: false hasTypes: false -loading: false" +loading: false + +framework: undefined" `; exports[`Parser.getSymbols call expression 1`] = ` @@ -151,7 +153,9 @@ hasJsx: false hasTypes: false -loading: false" +loading: false + +framework: undefined" `; exports[`Parser.getSymbols call sites 1`] = ` @@ -197,7 +201,9 @@ hasJsx: false hasTypes: false -loading: false" +loading: false + +framework: undefined" `; exports[`Parser.getSymbols class 1`] = ` @@ -249,7 +255,9 @@ hasJsx: false hasTypes: false -loading: false" +loading: false + +framework: undefined" `; exports[`Parser.getSymbols component 1`] = ` @@ -411,7 +419,9 @@ hasJsx: true hasTypes: false -loading: false" +loading: false + +framework: undefined" `; exports[`Parser.getSymbols destruct 1`] = ` @@ -500,7 +510,9 @@ hasJsx: false hasTypes: false -loading: false" +loading: false + +framework: undefined" `; exports[`Parser.getSymbols es6 1`] = ` @@ -538,7 +550,9 @@ hasJsx: false hasTypes: false -loading: false" +loading: false + +framework: undefined" `; exports[`Parser.getSymbols expression 1`] = ` @@ -719,7 +733,9 @@ hasJsx: false hasTypes: false -loading: false" +loading: false + +framework: undefined" `; exports[`Parser.getSymbols finds symbols in an html file 1`] = ` @@ -799,7 +815,9 @@ hasJsx: false hasTypes: false -loading: false" +loading: false + +framework: undefined" `; exports[`Parser.getSymbols flow 1`] = ` @@ -839,7 +857,9 @@ hasJsx: false hasTypes: true -loading: false" +loading: false + +framework: undefined" `; exports[`Parser.getSymbols func 1`] = ` @@ -922,7 +942,9 @@ hasJsx: false hasTypes: false -loading: false" +loading: false + +framework: undefined" `; exports[`Parser.getSymbols function names 1`] = ` @@ -1047,7 +1069,9 @@ hasJsx: false hasTypes: false -loading: false" +loading: false + +framework: undefined" `; exports[`Parser.getSymbols jsx 1`] = ` @@ -1085,7 +1109,9 @@ hasJsx: true hasTypes: false -loading: false" +loading: false + +framework: undefined" `; exports[`Parser.getSymbols math 1`] = ` @@ -1138,7 +1164,9 @@ hasJsx: false hasTypes: false -loading: false" +loading: false + +framework: undefined" `; exports[`Parser.getSymbols object expressions 1`] = ` @@ -1220,7 +1248,9 @@ hasJsx: false hasTypes: false -loading: false" +loading: false + +framework: undefined" `; exports[`Parser.getSymbols proto 1`] = ` @@ -1279,7 +1309,9 @@ hasJsx: false hasTypes: false -loading: false" +loading: false + +framework: undefined" `; exports[`Parser.getSymbols react component 1`] = ` @@ -1317,7 +1349,9 @@ hasJsx: false hasTypes: false -loading: false" +loading: false + +framework: React" `; exports[`Parser.getSymbols var 1`] = ` @@ -1385,5 +1419,7 @@ hasJsx: false hasTypes: false -loading: false" +loading: false + +framework: undefined" `; diff --git a/devtools/client/debugger/new/src/workers/parser/tests/framework.spec.js b/devtools/client/debugger/new/src/workers/parser/tests/framework.spec.js index e89260d7a31b..6d51b32dd430 100644 --- a/devtools/client/debugger/new/src/workers/parser/tests/framework.spec.js +++ b/devtools/client/debugger/new/src/workers/parser/tests/framework.spec.js @@ -4,58 +4,54 @@ // @flow -import { getFramework } from "../frameworks"; -import { getSource, getOriginalSource } from "./helpers"; +import { getSymbols } from "../getSymbols"; +import { getOriginalSource } from "./helpers"; import { setSource } from "../sources"; +import cases from "jest-in-case"; -describe("Parser.frameworks", () => { - describe("no framework", () => { - it("is undefined when no framework", () => { - const source = getOriginalSource("frameworks/plainJavascript"); - setSource(source); - expect(getFramework(source.id)).toBeUndefined(); - }); - - it("does not get confused with angular (#6833)", () => { - const source = getOriginalSource("frameworks/angular1FalsePositive"); - setSource(source); - expect(getFramework(source.id)).toBeUndefined(); - }); - }); - - describe("react", () => { - it("recognizes ES6 React component", () => { - const source = getOriginalSource("frameworks/reactComponent"); - setSource(source); - expect(getFramework(source.id)).toBe("React"); - }); - - it("recognizes ES5 React component", () => { - const source = getSource("frameworks/reactComponentEs5"); - setSource(source); - expect(getFramework(source.id)).toBe("React"); - }); - }); - - describe("angular 1.*", () => { - it("recognizes Angular 1 module", () => { - const source = getOriginalSource("frameworks/angular1Module"); - setSource(source); - expect(getFramework(source.id)).toBe("Angular"); - }); - }); - - describe("vue", () => { - it("recognizes declarative Vue file", () => { - const source = getOriginalSource("frameworks/vueFileDeclarative"); - setSource(source); - expect(getFramework(source.id)).toBe("Vue"); - }); - - it("recognizes component Vue file", () => { - const source = getOriginalSource("frameworks/vueFileComponent"); - setSource(source); - expect(getFramework(source.id)).toBe("Vue"); - }); - }); -}); +cases( + "Parser.getFramework", + ({ name, file, value }) => { + const source = getOriginalSource("frameworks/plainJavascript"); + setSource(source); + const symbols = getSymbols(source.id); + expect(symbols.framework).toBeUndefined(); + }, + [ + { + name: "is undefined when no framework", + file: "frameworks/plainJavascript", + value: undefined + }, + { + name: "does not get confused with angular (#6833)", + file: "frameworks/angular1FalsePositive", + value: undefined + }, + { + name: "recognizes ES6 React component", + file: "frameworks/reactComponent", + value: "React" + }, + { + name: "recognizes ES5 React component", + file: "frameworks/reactComponentEs5", + value: "React" + }, + { + name: "recognizes Angular 1 module", + file: "frameworks/angular1Module", + value: "Angular" + }, + { + name: "recognizes declarative Vue file", + file: "frameworks/vueFileDeclarative", + value: "Vue" + }, + { + name: "recognizes component Vue file", + file: "frameworks/vueFileComponent", + value: "Vue" + } + ] +); diff --git a/devtools/client/debugger/new/src/workers/parser/utils/formatSymbols.js b/devtools/client/debugger/new/src/workers/parser/utils/formatSymbols.js index ea54cd38ed97..105484549170 100644 --- a/devtools/client/debugger/new/src/workers/parser/utils/formatSymbols.js +++ b/devtools/client/debugger/new/src/workers/parser/utils/formatSymbols.js @@ -40,15 +40,24 @@ function summarize(symbol) { return `${loc} ${expression} ${name}${params} ${klass} ${names} ${values} ${index}`.trim(); // eslint-disable-line max-len } const bools = ["hasJsx", "hasTypes", "loading"]; +const strings = ["framework"]; function formatBool(name, symbols) { return `${name}: ${symbols[name] ? "true" : "false"}`; } +function formatString(name, symbols) { + return `${name}: ${symbols[name]}`; +} + function formatKey(name: string, symbols: any) { if (bools.includes(name)) { return formatBool(name, symbols); } + if (strings.includes(name)) { + return formatString(name, symbols); + } + return `${name}:\n${symbols[name].map(summarize).join("\n")}`; } diff --git a/devtools/client/debugger/new/test/mochitest/helpers.js b/devtools/client/debugger/new/test/mochitest/helpers.js index 2340c352db92..854313785feb 100644 --- a/devtools/client/debugger/new/test/mochitest/helpers.js +++ b/devtools/client/debugger/new/test/mochitest/helpers.js @@ -214,7 +214,6 @@ function waitForSelectedSource(dbg, url) { const { getSelectedSource, hasSymbols, - hasSourceMetaData, hasBreakpointPositions } = dbg.selectors; @@ -236,9 +235,9 @@ function waitForSelectedSource(dbg, url) { return false; } - return hasSymbols(state, source) && - hasSourceMetaData( state, source.id) && - hasBreakpointPositions(state, source.id); + return ( + hasSymbols(state, source) && hasBreakpointPositions(state, source.id) + ); }, "selected source" ); diff --git a/testing/talos/talos/tests/devtools/addon/content/tests/debugger/debugger-helpers.js b/testing/talos/talos/tests/devtools/addon/content/tests/debugger/debugger-helpers.js index 1f902fe0edc2..7b8aac940b06 100644 --- a/testing/talos/talos/tests/devtools/addon/content/tests/debugger/debugger-helpers.js +++ b/testing/talos/talos/tests/devtools/addon/content/tests/debugger/debugger-helpers.js @@ -100,15 +100,12 @@ function waitForText(dbg, url, text) { }, "text is visible"); } -function waitForMetaData(dbg) { +function waitForSymbols(dbg) { return waitUntil( () => { const state = dbg.store.getState(); const source = dbg.selectors.getSelectedSource(state); - // wait for metadata -- this involves parsing the file to determine its type. - // if the object is empty, the data has not yet loaded - const metaData = dbg.selectors.getSourceMetaData(state, source.id); - return !!Object.keys(metaData).length; + return dbg.selectors.hasSymbols(state, source); }, "has file metadata" ); @@ -219,7 +216,7 @@ async function openDebuggerAndLog(label, expected) { await waitForSource(dbg, expected.sourceURL); await selectSource(dbg, expected.file); await waitForText(dbg, expected.file, expected.text); - await waitForMetaData(dbg); + await waitForSymbols(dbg); }; const toolbox = await openToolboxAndLog(label + ".jsdebugger", "jsdebugger", onLoad); @@ -234,7 +231,7 @@ async function reloadDebuggerAndLog(label, toolbox, expected) { await waitForDispatch(dbg, "NAVIGATE"); await waitForSources(dbg, expected.sources); await waitForText(dbg, expected.file, expected.text); - await waitForMetaData(dbg); + await waitForSymbols(dbg); }; await reloadPageAndLog(`${label}.jsdebugger`, toolbox, onReload); }