From 2020e9723802de6cb2adefb29438063985bcbe52 Mon Sep 17 00:00:00 2001 From: nyrosmith Date: Mon, 30 Oct 2017 18:51:14 +0100 Subject: [PATCH 01/12] Improve JSX syntax highlighting --- src/utils/source.js | 5 +++++ src/workers/parser/frameworks.js | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/utils/source.js b/src/utils/source.js index 97ee400bc7..ca376f164d 100644 --- a/src/utils/source.js +++ b/src/utils/source.js @@ -9,6 +9,7 @@ import { isOriginalId } from "devtools-source-map"; import { endTruncateStr } from "./utils"; import { basename } from "../utils/path"; import { parse as parseURL } from "url"; +import { isReactComponent } from "../workers/parser/frameworks"; import type { Source } from "../types"; @@ -206,6 +207,10 @@ function getMode(source: Source) { return { name: "text" }; } + if (isReactComponent(source)) { + return { name: "jsx" }; + } + // if the url ends with .marko we set the name to Javascript so // syntax highlighting works for marko too if (url && url.match(/\.marko$/i)) { diff --git a/src/workers/parser/frameworks.js b/src/workers/parser/frameworks.js index c0f69b9de4..0bbad0334b 100644 --- a/src/workers/parser/frameworks.js +++ b/src/workers/parser/frameworks.js @@ -21,7 +21,10 @@ function importsReact(imports) { function extendsComponent(classes) { let result = false; classes.some(classObj => { - if (classObj.parent.name === "Component") { + if ( + classObj.parent.name === "Component" || + classObj.parent.name === "PureComponent" + ) { result = true; } }); From 2e2aa7ecbdbadbe3d7be42bf1a780891ad92b57d Mon Sep 17 00:00:00 2001 From: nyrosmith Date: Fri, 3 Nov 2017 14:17:57 +0100 Subject: [PATCH 02/12] introduce AST metadata --- src/actions/ast.js | 26 +++++++++++++++++++++++++- src/actions/sources/loadSourceText.js | 3 ++- src/components/Editor/Breakpoint.js | 7 ++++--- src/components/Editor/Breakpoints.js | 8 +++++--- src/components/Editor/index.js | 10 ++++++---- src/reducers/ast.js | 14 ++++++++++++-- src/utils/editor/source-documents.js | 6 ++++-- src/utils/source.js | 5 ++--- src/workers/parser/index.js | 1 + src/workers/parser/worker.js | 4 +++- 10 files changed, 64 insertions(+), 20 deletions(-) diff --git a/src/actions/ast.js b/src/actions/ast.js index 769d649e42..03b7018676 100644 --- a/src/actions/ast.js +++ b/src/actions/ast.js @@ -14,7 +14,8 @@ import { PROMISE } from "../utils/redux/middleware/promise"; import { getSymbols, getEmptyLines, - getOutOfScopeLocations + getOutOfScopeLocations, + isReactComponent } from "../workers/parser"; import { findBestMatchExpression } from "../utils/ast"; @@ -29,6 +30,29 @@ const extraProps = { react: { displayName: "this._reactInternalInstance.getName()" } }; +export function setMetaData(sourceId: SourceId) { + return async ({ dispatch, getState }: ThunkArgs) => { + const sourceRecord = getSource(getState(), sourceId); + if (!sourceRecord) { + return; + } + + const source = sourceRecord.toJS(); + if (!source.text || source.isWasm) { + return; + } + + const isReactComp = await isReactComponent(source); + dispatch({ + type: "SET_METADATA", + source, + metaData: { + isReactComponent: isReactComp + } + }); + }; +} + export function setSymbols(sourceId: SourceId) { return async ({ dispatch, getState }: ThunkArgs) => { const sourceRecord = getSource(getState(), sourceId); diff --git a/src/actions/sources/loadSourceText.js b/src/actions/sources/loadSourceText.js index 99a7701f9c..e56b331300 100644 --- a/src/actions/sources/loadSourceText.js +++ b/src/actions/sources/loadSourceText.js @@ -1,6 +1,6 @@ // @flow import { PROMISE } from "../../utils/redux/middleware/promise"; -import { setEmptyLines, setSymbols } from "../ast"; +import { setEmptyLines, setSymbols, setMetaData } from "../ast"; import { getSource } from "../../selectors"; import { setSource } from "../../workers/parser"; import type { Source } from "../../types"; @@ -45,5 +45,6 @@ export function loadSourceText(source: Source) { await setSource(newSource); await dispatch(setSymbols(source.id)); await dispatch(setEmptyLines(source.id)); + await dispatch(setMetaData(source.id)); }; } diff --git a/src/components/Editor/Breakpoint.js b/src/components/Editor/Breakpoint.js index f2e4f9bf19..9d8b4fc1a5 100644 --- a/src/components/Editor/Breakpoint.js +++ b/src/components/Editor/Breakpoint.js @@ -24,7 +24,8 @@ function makeMarker(isDisabled: boolean) { type Props = { breakpoint: Object, selectedSource: Object, - editor: Object + editor: Object, + metaData: Object }; class Breakpoint extends Component { @@ -36,7 +37,7 @@ class Breakpoint extends Component { } addBreakpoint() { - const { breakpoint, editor, selectedSource } = this.props; + const { breakpoint, editor, selectedSource, metaData } = this.props; // Hidden Breakpoints are never rendered on the client if (breakpoint.hidden) { @@ -52,7 +53,7 @@ class Breakpoint extends Component { const sourceId = selectedSource.get("id"); const line = toEditorLine(sourceId, breakpoint.location.line); - showSourceText(editor, selectedSource.toJS()); + showSourceText(editor, selectedSource.toJS(), metaData); editor.codeMirror.setGutterMarker( line, diff --git a/src/components/Editor/Breakpoints.js b/src/components/Editor/Breakpoints.js index 030e632358..627393d0c7 100644 --- a/src/components/Editor/Breakpoints.js +++ b/src/components/Editor/Breakpoints.js @@ -6,7 +6,7 @@ import React, { Component } from "react"; import Breakpoint from "./Breakpoint"; import actions from "../../actions"; -import { getSelectedSource } from "../../selectors"; +import { getSelectedSource, getMetaData } from "../../selectors"; import getVisibleBreakpoints from "../../selectors/visibleBreakpoints"; import { makeLocationId } from "../../utils/breakpoint"; import { isLoaded } from "../../utils/source"; @@ -32,7 +32,7 @@ class Breakpoints extends Component { } render() { - const { breakpoints, selectedSource, editor } = this.props; + const { breakpoints, selectedSource, editor, metaData } = this.props; if (!selectedSource || !breakpoints || selectedSource.get("isBlackBoxed")) { return null; @@ -46,6 +46,7 @@ class Breakpoints extends Component { key={makeLocationId(bp.location)} breakpoint={bp} selectedSource={selectedSource} + metaData={metaData} editor={editor} /> ); @@ -58,7 +59,8 @@ class Breakpoints extends Component { export default connect( state => ({ breakpoints: getVisibleBreakpoints(state), - selectedSource: getSelectedSource(state) + selectedSource: getSelectedSource(state), + metaData: getMetaData(state) }), dispatch => bindActionCreators(actions, dispatch) )(Breakpoints); diff --git a/src/components/Editor/index.js b/src/components/Editor/index.js index 06c3412a5e..2c890463c1 100644 --- a/src/components/Editor/index.js +++ b/src/components/Editor/index.js @@ -20,7 +20,8 @@ import { getCoverageEnabled, getConditionalPanelLine, getFileSearchModifiers, - getFileSearchQuery + getFileSearchQuery, + getMetaData } from "../../selectors"; import actions from "../../actions"; @@ -459,7 +460,7 @@ class Editor extends PureComponent { } setText(props) { - const { selectedSource } = props; + const { selectedSource, metaData } = props; if (!this.state.editor) { return; } @@ -477,7 +478,7 @@ class Editor extends PureComponent { } if (selectedSource) { - return showSourceText(this.state.editor, selectedSource.toJS()); + return showSourceText(this.state.editor, selectedSource.toJS(), metaData); } } @@ -629,7 +630,8 @@ export default connect( query: getFileSearchQuery(state), modifiers: getFileSearchModifiers(state), coverageOn: getCoverageEnabled(state), - conditionalPanelLine: getConditionalPanelLine(state) + conditionalPanelLine: getConditionalPanelLine(state), + metaData: getMetaData(state) }; }, dispatch => bindActionCreators(actions, dispatch) diff --git a/src/reducers/ast.js b/src/reducers/ast.js index b3c1706e02..67dbe362df 100644 --- a/src/reducers/ast.js +++ b/src/reducers/ast.js @@ -38,7 +38,8 @@ export type ASTState = { symbols: SymbolsMap, emptyLines: EmptyLinesMap, outOfScopeLocations: ?Array, - preview: Preview + preview: Preview, + metaData: Object }; export function initialState() { @@ -47,7 +48,8 @@ export function initialState() { symbols: I.Map(), emptyLines: I.Map(), outOfScopeLocations: null, - preview: null + preview: null, + metaData: {} }: ASTState) )(); } @@ -111,6 +113,10 @@ function update( return initialState(); } + case "SET_METADATA": { + return state.set("metaData", action.metaData); + } + default: { return state; } @@ -167,4 +173,8 @@ export function getPreview(state: OuterState) { return state.ast.get("preview"); } +export function getMetaData(state: OuterState) { + return state.ast.get("metaData"); +} + export default update; diff --git a/src/utils/editor/source-documents.js b/src/utils/editor/source-documents.js index 2928694d7a..6c90c1ef5c 100644 --- a/src/utils/editor/source-documents.js +++ b/src/utils/editor/source-documents.js @@ -81,19 +81,21 @@ function setEditorText(editor: Object, source: Source) { * Handle getting the source document or creating a new * document with the correct mode and text. */ -function showSourceText(editor: Object, source: Source) { +function showSourceText(editor: Object, source: Source, metaData) { if (!source) { return; } let doc = getDocument(source.id); if (editor.codeMirror.doc === doc) { + editor.setMode(getMode(source, metaData)); return; } if (doc) { editor.replaceDocument(doc); updateLineNumberFormat(editor, source.id); + editor.setMode(getMode(source, metaData)); return doc; } @@ -102,7 +104,7 @@ function showSourceText(editor: Object, source: Source) { editor.replaceDocument(doc); setEditorText(editor, source); - editor.setMode(getMode(source)); + editor.setMode(getMode(source, metaData)); updateLineNumberFormat(editor, source.id); } diff --git a/src/utils/source.js b/src/utils/source.js index ca376f164d..f4fdb02ea4 100644 --- a/src/utils/source.js +++ b/src/utils/source.js @@ -9,7 +9,6 @@ import { isOriginalId } from "devtools-source-map"; import { endTruncateStr } from "./utils"; import { basename } from "../utils/path"; import { parse as parseURL } from "url"; -import { isReactComponent } from "../workers/parser/frameworks"; import type { Source } from "../types"; @@ -200,14 +199,14 @@ function getSourceLineCount(source: Source) { * @static */ -function getMode(source: Source) { +function getMode(source: Source, metaData) { const { contentType, text, isWasm, url } = source; if (!text || isWasm) { return { name: "text" }; } - if (isReactComponent(source)) { + if (metaData && metaData.isReactComponent) { return { name: "jsx" }; } diff --git a/src/workers/parser/index.js b/src/workers/parser/index.js index eedee86084..27262a5466 100644 --- a/src/workers/parser/index.js +++ b/src/workers/parser/index.js @@ -21,6 +21,7 @@ export const hasSource = dispatcher.task("hasSource"); export const setSource = dispatcher.task("setSource"); export const clearSources = dispatcher.task("clearSources"); export const hasSyntaxError = dispatcher.task("hasSyntaxError"); +export const isReactComponent = dispatcher.task("isReactComponent"); export type { SymbolDeclaration, SymbolDeclarations } from "./getSymbols"; export type { AstLocation } from "./types"; diff --git a/src/workers/parser/worker.js b/src/workers/parser/worker.js index b870be83b8..5923e20391 100644 --- a/src/workers/parser/worker.js +++ b/src/workers/parser/worker.js @@ -8,6 +8,7 @@ import getOutOfScopeLocations from "./getOutOfScopeLocations"; import { getNextStep } from "./steps"; import getEmptyLines from "./getEmptyLines"; import { hasSyntaxError } from "./validate"; +import { isReactComponent } from "./frameworks"; import { workerUtils } from "devtools-utils"; const { workerHandler } = workerUtils; @@ -26,5 +27,6 @@ self.onmessage = workerHandler({ getVariablesInScope, getNextStep, getEmptyLines, - hasSyntaxError + hasSyntaxError, + isReactComponent }); From 2f98f11698dad0adb648eed171bacda8d04ba27b Mon Sep 17 00:00:00 2001 From: nyrosmith Date: Fri, 3 Nov 2017 14:22:09 +0100 Subject: [PATCH 03/12] fix lint warning --- src/components/Editor/Breakpoints.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/Editor/Breakpoints.js b/src/components/Editor/Breakpoints.js index 627393d0c7..b7b48af87f 100644 --- a/src/components/Editor/Breakpoints.js +++ b/src/components/Editor/Breakpoints.js @@ -16,7 +16,8 @@ import type { SourceRecord, BreakpointsMap } from "../../reducers/types"; type Props = { selectedSource: SourceRecord, breakpoints: BreakpointsMap, - editor: Object + editor: Object, + metaData: Object }; class Breakpoints extends Component { From 421cf8fb2dab425b0f32217166b46ed6f3967286 Mon Sep 17 00:00:00 2001 From: nyrosmith Date: Fri, 3 Nov 2017 17:09:04 +0100 Subject: [PATCH 04/12] renamed action --- src/actions/ast.js | 2 +- src/reducers/ast.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/actions/ast.js b/src/actions/ast.js index 03b7018676..dbcfdc0c7c 100644 --- a/src/actions/ast.js +++ b/src/actions/ast.js @@ -44,7 +44,7 @@ export function setMetaData(sourceId: SourceId) { const isReactComp = await isReactComponent(source); dispatch({ - type: "SET_METADATA", + type: "SET_SOURCE_METADATA", source, metaData: { isReactComponent: isReactComp diff --git a/src/reducers/ast.js b/src/reducers/ast.js index 67dbe362df..94fe74e9c2 100644 --- a/src/reducers/ast.js +++ b/src/reducers/ast.js @@ -113,7 +113,7 @@ function update( return initialState(); } - case "SET_METADATA": { + case "SET_SOURCE_METADATA": { return state.set("metaData", action.metaData); } From dedf024b739083a3c64784c576f5fd8cca21610b Mon Sep 17 00:00:00 2001 From: nyrosmith Date: Fri, 3 Nov 2017 17:44:45 +0100 Subject: [PATCH 05/12] fix flow issue --- src/reducers/ast.js | 10 ++++++++-- src/utils/editor/source-documents.js | 3 ++- src/utils/source.js | 3 ++- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/reducers/ast.js b/src/reducers/ast.js index 94fe74e9c2..b35ce60f09 100644 --- a/src/reducers/ast.js +++ b/src/reducers/ast.js @@ -22,6 +22,12 @@ type EmptyLinesType = number[]; export type SymbolsMap = Map; export type EmptyLinesMap = Map; +export type SourceMetaDataType = { + isReactComponent: boolean +}; + +export type SourceMetaDataMap = Map; + export type Preview = | {| updating: true |} | null @@ -39,7 +45,7 @@ export type ASTState = { emptyLines: EmptyLinesMap, outOfScopeLocations: ?Array, preview: Preview, - metaData: Object + metaData: SourceMetaDataMap }; export function initialState() { @@ -49,7 +55,7 @@ export function initialState() { emptyLines: I.Map(), outOfScopeLocations: null, preview: null, - metaData: {} + metaData: I.Map() }: ASTState) )(); } diff --git a/src/utils/editor/source-documents.js b/src/utils/editor/source-documents.js index 6c90c1ef5c..5253af9dc6 100644 --- a/src/utils/editor/source-documents.js +++ b/src/utils/editor/source-documents.js @@ -5,6 +5,7 @@ import { getMode } from "../source"; import type { Source } from "debugger-html"; import { isWasm, getWasmLineNumberFormatter, renderWasmText } from "../wasm"; import { resizeBreakpointGutter, resizeToggleButton } from "../ui"; +import type { SourceMetaDataType } from "../../reducers/ast"; let sourceDocs = {}; @@ -81,7 +82,7 @@ function setEditorText(editor: Object, source: Source) { * Handle getting the source document or creating a new * document with the correct mode and text. */ -function showSourceText(editor: Object, source: Source, metaData) { +function showSourceText(editor: Object, source: Source, metaData: SourceMetaDataType) { if (!source) { return; } diff --git a/src/utils/source.js b/src/utils/source.js index f4fdb02ea4..ddb4c99455 100644 --- a/src/utils/source.js +++ b/src/utils/source.js @@ -11,6 +11,7 @@ import { basename } from "../utils/path"; import { parse as parseURL } from "url"; import type { Source } from "../types"; +import type { SourceMetaDataType } from "../reducers/ast"; type transformUrlCallback = string => string; @@ -199,7 +200,7 @@ function getSourceLineCount(source: Source) { * @static */ -function getMode(source: Source, metaData) { +function getMode(source: Source, metaData: SourceMetaDataType) { const { contentType, text, isWasm, url } = source; if (!text || isWasm) { From 7499b617f9baaff91bbbaf84fff6bc91ae762ee8 Mon Sep 17 00:00:00 2001 From: nyrosmith Date: Fri, 3 Nov 2017 17:58:17 +0100 Subject: [PATCH 06/12] Fix another flow error --- src/components/Editor/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/Editor/index.js b/src/components/Editor/index.js index 2c890463c1..8f038db4bf 100644 --- a/src/components/Editor/index.js +++ b/src/components/Editor/index.js @@ -37,6 +37,7 @@ import EmptyLines from "./EmptyLines"; import GutterMenu from "./GutterMenu"; import EditorMenu from "./EditorMenu"; import ConditionalPanel from "./ConditionalPanel"; +import type { SourceMetaDataType } from "../../reducers/ast"; import { showSourceText, @@ -85,7 +86,8 @@ type Props = { openConditionalPanel: Function, closeConditionalPanel: Function, continueToHere: Function, - setContextMenu: Function + setContextMenu: Function, + metaData: SourceMetaDataType }; type State = { From 2d0f1a98626c16198d5b2cbb3158b5b966415903 Mon Sep 17 00:00:00 2001 From: nyrosmith Date: Fri, 3 Nov 2017 18:00:33 +0100 Subject: [PATCH 07/12] prettier formatted --- src/utils/editor/source-documents.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/utils/editor/source-documents.js b/src/utils/editor/source-documents.js index 5253af9dc6..3471e81038 100644 --- a/src/utils/editor/source-documents.js +++ b/src/utils/editor/source-documents.js @@ -82,7 +82,11 @@ function setEditorText(editor: Object, source: Source) { * Handle getting the source document or creating a new * document with the correct mode and text. */ -function showSourceText(editor: Object, source: Source, metaData: SourceMetaDataType) { +function showSourceText( + editor: Object, + source: Source, + metaData: SourceMetaDataType +) { if (!source) { return; } From 5e38111b435a4232e5706377c921fec2a833d254 Mon Sep 17 00:00:00 2001 From: nyrosmith Date: Fri, 3 Nov 2017 19:58:33 +0100 Subject: [PATCH 08/12] streamlined naming of sourceMetaData --- src/actions/ast.js | 4 ++-- src/actions/sources/loadSourceText.js | 4 ++-- src/components/Editor/Breakpoint.js | 6 +++--- src/components/Editor/Breakpoints.js | 10 +++++----- src/components/Editor/index.js | 14 +++++++++----- src/reducers/ast.js | 10 +++++----- src/utils/editor/source-documents.js | 8 ++++---- src/utils/source.js | 4 ++-- 8 files changed, 32 insertions(+), 28 deletions(-) diff --git a/src/actions/ast.js b/src/actions/ast.js index dbcfdc0c7c..b84b1f6967 100644 --- a/src/actions/ast.js +++ b/src/actions/ast.js @@ -30,7 +30,7 @@ const extraProps = { react: { displayName: "this._reactInternalInstance.getName()" } }; -export function setMetaData(sourceId: SourceId) { +export function setSourceMetaData(sourceId: SourceId) { return async ({ dispatch, getState }: ThunkArgs) => { const sourceRecord = getSource(getState(), sourceId); if (!sourceRecord) { @@ -46,7 +46,7 @@ export function setMetaData(sourceId: SourceId) { dispatch({ type: "SET_SOURCE_METADATA", source, - metaData: { + sourceMetaData: { isReactComponent: isReactComp } }); diff --git a/src/actions/sources/loadSourceText.js b/src/actions/sources/loadSourceText.js index e56b331300..a61343947f 100644 --- a/src/actions/sources/loadSourceText.js +++ b/src/actions/sources/loadSourceText.js @@ -1,6 +1,6 @@ // @flow import { PROMISE } from "../../utils/redux/middleware/promise"; -import { setEmptyLines, setSymbols, setMetaData } from "../ast"; +import { setEmptyLines, setSymbols, setSourceMetaData } from "../ast"; import { getSource } from "../../selectors"; import { setSource } from "../../workers/parser"; import type { Source } from "../../types"; @@ -45,6 +45,6 @@ export function loadSourceText(source: Source) { await setSource(newSource); await dispatch(setSymbols(source.id)); await dispatch(setEmptyLines(source.id)); - await dispatch(setMetaData(source.id)); + await dispatch(setSourceMetaData(source.id)); }; } diff --git a/src/components/Editor/Breakpoint.js b/src/components/Editor/Breakpoint.js index 9d8b4fc1a5..b8c69ee5d1 100644 --- a/src/components/Editor/Breakpoint.js +++ b/src/components/Editor/Breakpoint.js @@ -25,7 +25,7 @@ type Props = { breakpoint: Object, selectedSource: Object, editor: Object, - metaData: Object + sourceMetaData: Object }; class Breakpoint extends Component { @@ -37,7 +37,7 @@ class Breakpoint extends Component { } addBreakpoint() { - const { breakpoint, editor, selectedSource, metaData } = this.props; + const { breakpoint, editor, selectedSource, sourceMetaData } = this.props; // Hidden Breakpoints are never rendered on the client if (breakpoint.hidden) { @@ -53,7 +53,7 @@ class Breakpoint extends Component { const sourceId = selectedSource.get("id"); const line = toEditorLine(sourceId, breakpoint.location.line); - showSourceText(editor, selectedSource.toJS(), metaData); + showSourceText(editor, selectedSource.toJS(), sourceMetaData); editor.codeMirror.setGutterMarker( line, diff --git a/src/components/Editor/Breakpoints.js b/src/components/Editor/Breakpoints.js index b7b48af87f..addf046572 100644 --- a/src/components/Editor/Breakpoints.js +++ b/src/components/Editor/Breakpoints.js @@ -6,7 +6,7 @@ import React, { Component } from "react"; import Breakpoint from "./Breakpoint"; import actions from "../../actions"; -import { getSelectedSource, getMetaData } from "../../selectors"; +import { getSelectedSource, getSourceMetaData } from "../../selectors"; import getVisibleBreakpoints from "../../selectors/visibleBreakpoints"; import { makeLocationId } from "../../utils/breakpoint"; import { isLoaded } from "../../utils/source"; @@ -17,7 +17,7 @@ type Props = { selectedSource: SourceRecord, breakpoints: BreakpointsMap, editor: Object, - metaData: Object + sourceMetaData: Object }; class Breakpoints extends Component { @@ -33,7 +33,7 @@ class Breakpoints extends Component { } render() { - const { breakpoints, selectedSource, editor, metaData } = this.props; + const { breakpoints, selectedSource, editor, sourceMetaData } = this.props; if (!selectedSource || !breakpoints || selectedSource.get("isBlackBoxed")) { return null; @@ -47,7 +47,7 @@ class Breakpoints extends Component { key={makeLocationId(bp.location)} breakpoint={bp} selectedSource={selectedSource} - metaData={metaData} + sourceMetaData={sourceMetaData} editor={editor} /> ); @@ -61,7 +61,7 @@ export default connect( state => ({ breakpoints: getVisibleBreakpoints(state), selectedSource: getSelectedSource(state), - metaData: getMetaData(state) + sourceMetaData: getSourceMetaData(state) }), dispatch => bindActionCreators(actions, dispatch) )(Breakpoints); diff --git a/src/components/Editor/index.js b/src/components/Editor/index.js index c4ab1b52e7..abb45f09be 100644 --- a/src/components/Editor/index.js +++ b/src/components/Editor/index.js @@ -16,7 +16,7 @@ import { getSelectedSource, getHitCountForSource, getCoverageEnabled, - getMetaData, + getSourceMetaData, getConditionalPanelLine } from "../../selectors"; @@ -76,7 +76,7 @@ type Props = { startPanelSize: number, endPanelSize: number, conditionalPanelLine: number, - metaData: SourceMetaDataType, + sourceMetaData: SourceMetaDataType, // Actions openConditionalPanel: number => void, @@ -456,7 +456,7 @@ class Editor extends PureComponent { } setText(props) { - const { selectedSource, metaData } = props; + const { selectedSource, sourceMetaData } = props; if (!this.state.editor) { return; } @@ -474,7 +474,11 @@ class Editor extends PureComponent { } if (selectedSource) { - return showSourceText(this.state.editor, selectedSource.toJS(), metaData); + return showSourceText( + this.state.editor, + selectedSource.toJS(), + sourceMetaData + ); } } @@ -601,7 +605,7 @@ const mapStateToProps = state => { selectedFrame: getSelectedFrame(state), coverageOn: getCoverageEnabled(state), conditionalPanelLine: getConditionalPanelLine(state), - metaData: getMetaData(state) + sourceMetaData: getSourceMetaData(state) }; }; diff --git a/src/reducers/ast.js b/src/reducers/ast.js index b35ce60f09..fc732258ef 100644 --- a/src/reducers/ast.js +++ b/src/reducers/ast.js @@ -45,7 +45,7 @@ export type ASTState = { emptyLines: EmptyLinesMap, outOfScopeLocations: ?Array, preview: Preview, - metaData: SourceMetaDataMap + sourceMetaData: SourceMetaDataMap }; export function initialState() { @@ -55,7 +55,7 @@ export function initialState() { emptyLines: I.Map(), outOfScopeLocations: null, preview: null, - metaData: I.Map() + sourceMetaData: I.Map() }: ASTState) )(); } @@ -120,7 +120,7 @@ function update( } case "SET_SOURCE_METADATA": { - return state.set("metaData", action.metaData); + return state.set("sourceMetaData", action.sourceMetaData); } default: { @@ -179,8 +179,8 @@ export function getPreview(state: OuterState) { return state.ast.get("preview"); } -export function getMetaData(state: OuterState) { - return state.ast.get("metaData"); +export function getSourceMetaData(state: OuterState) { + return state.ast.get("sourceMetaData"); } export default update; diff --git a/src/utils/editor/source-documents.js b/src/utils/editor/source-documents.js index 3471e81038..ffafe0c357 100644 --- a/src/utils/editor/source-documents.js +++ b/src/utils/editor/source-documents.js @@ -85,7 +85,7 @@ function setEditorText(editor: Object, source: Source) { function showSourceText( editor: Object, source: Source, - metaData: SourceMetaDataType + sourceMetaData: SourceMetaDataType ) { if (!source) { return; @@ -93,14 +93,14 @@ function showSourceText( let doc = getDocument(source.id); if (editor.codeMirror.doc === doc) { - editor.setMode(getMode(source, metaData)); + editor.setMode(getMode(source, sourceMetaData)); return; } if (doc) { editor.replaceDocument(doc); updateLineNumberFormat(editor, source.id); - editor.setMode(getMode(source, metaData)); + editor.setMode(getMode(source, sourceMetaData)); return doc; } @@ -109,7 +109,7 @@ function showSourceText( editor.replaceDocument(doc); setEditorText(editor, source); - editor.setMode(getMode(source, metaData)); + editor.setMode(getMode(source, sourceMetaData)); updateLineNumberFormat(editor, source.id); } diff --git a/src/utils/source.js b/src/utils/source.js index 06c770417d..1467604523 100644 --- a/src/utils/source.js +++ b/src/utils/source.js @@ -205,14 +205,14 @@ function getSourceLineCount(source: Source) { * @static */ -function getMode(source: Source, metaData: SourceMetaDataType) { +function getMode(source: Source, sourceMetaData: SourceMetaDataType) { const { contentType, text, isWasm, url } = source; if (!text || isWasm) { return { name: "text" }; } - if (metaData && metaData.isReactComponent) { + if (sourceMetaData && sourceMetaData.isReactComponent) { return { name: "jsx" }; } From 7b4e0c401dcceb55bdf9bf6b10df2501a8a28a94 Mon Sep 17 00:00:00 2001 From: nyrosmith Date: Sat, 4 Nov 2017 08:20:29 +0100 Subject: [PATCH 09/12] scope sourceMetaData to sourceId --- src/actions/ast.js | 2 +- src/components/Editor/Breakpoints.js | 2 +- src/components/Editor/index.js | 2 +- src/reducers/ast.js | 9 ++++++--- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/actions/ast.js b/src/actions/ast.js index b84b1f6967..b4bd57352f 100644 --- a/src/actions/ast.js +++ b/src/actions/ast.js @@ -45,7 +45,7 @@ export function setSourceMetaData(sourceId: SourceId) { const isReactComp = await isReactComponent(source); dispatch({ type: "SET_SOURCE_METADATA", - source, + sourceId: source.id, sourceMetaData: { isReactComponent: isReactComp } diff --git a/src/components/Editor/Breakpoints.js b/src/components/Editor/Breakpoints.js index addf046572..b99136e19c 100644 --- a/src/components/Editor/Breakpoints.js +++ b/src/components/Editor/Breakpoints.js @@ -61,7 +61,7 @@ export default connect( state => ({ breakpoints: getVisibleBreakpoints(state), selectedSource: getSelectedSource(state), - sourceMetaData: getSourceMetaData(state) + sourceMetaData: getSourceMetaData(state, getSelectedSource(state).id) }), dispatch => bindActionCreators(actions, dispatch) )(Breakpoints); diff --git a/src/components/Editor/index.js b/src/components/Editor/index.js index abb45f09be..b109fcf4b1 100644 --- a/src/components/Editor/index.js +++ b/src/components/Editor/index.js @@ -605,7 +605,7 @@ const mapStateToProps = state => { selectedFrame: getSelectedFrame(state), coverageOn: getCoverageEnabled(state), conditionalPanelLine: getConditionalPanelLine(state), - sourceMetaData: getSourceMetaData(state) + sourceMetaData: getSourceMetaData(state, sourceId) }; }; diff --git a/src/reducers/ast.js b/src/reducers/ast.js index fc732258ef..a220d1d612 100644 --- a/src/reducers/ast.js +++ b/src/reducers/ast.js @@ -120,7 +120,10 @@ function update( } case "SET_SOURCE_METADATA": { - return state.set("sourceMetaData", action.sourceMetaData); + return state.setIn( + ["sourceMetaData", action.sourceId], + action.sourceMetaData + ); } default: { @@ -179,8 +182,8 @@ export function getPreview(state: OuterState) { return state.ast.get("preview"); } -export function getSourceMetaData(state: OuterState) { - return state.ast.get("sourceMetaData"); +export function getSourceMetaData(state: OuterState, sourceId: string) { + return state.ast.getIn(["sourceMetaData", sourceId]) || {}; } export default update; From 3ddfe627a27df3d9d9f64dabde63ac3a08df50bc Mon Sep 17 00:00:00 2001 From: nyrosmith Date: Sat, 4 Nov 2017 09:14:19 +0100 Subject: [PATCH 10/12] set jsx syntax highlighting if source has .jsx extension --- src/utils/source.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/utils/source.js b/src/utils/source.js index 1467604523..9871baeba4 100644 --- a/src/utils/source.js +++ b/src/utils/source.js @@ -212,8 +212,11 @@ function getMode(source: Source, sourceMetaData: SourceMetaDataType) { return { name: "text" }; } - if (sourceMetaData && sourceMetaData.isReactComponent) { - return { name: "jsx" }; + if ( + (url && url.match(/\.jsx$/i)) || + (sourceMetaData && sourceMetaData.isReactComponent) + ) { + return "jsx"; } // if the url ends with .marko we set the name to Javascript so From 0df2abce58b4789ef71bb3015c6ca068c18bb892 Mon Sep 17 00:00:00 2001 From: nyrosmith Date: Sat, 4 Nov 2017 09:15:26 +0100 Subject: [PATCH 11/12] added tests for getMode --- src/utils/tests/source.spec.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/utils/tests/source.spec.js b/src/utils/tests/source.spec.js index ef7fcab428..e25b911242 100644 --- a/src/utils/tests/source.spec.js +++ b/src/utils/tests/source.spec.js @@ -127,7 +127,7 @@ describe("sources", () => { expect(getMode(source)).toBe("elm"); }); - it("jsx", () => { + it("returns jsx if contentType jsx is given", () => { const source = { contentType: "text/jsx", text: "

", @@ -136,6 +136,22 @@ describe("sources", () => { expect(getMode(source)).toBe("jsx"); }); + it("returns jsx if sourceMetaData says it's a react component", () => { + const source = { + text: "

", + url: "" + }; + expect(getMode(source, { isReactComponent: true })).toBe("jsx"); + }); + + it("returns jsx if the fileExtension is .jsx", () => { + const source = { + text: "

", + url: "myComponent.jsx" + }; + expect(getMode(source)).toBe("jsx"); + }); + it("typescript", () => { const source = { contentType: "text/typescript", From 7b46bf2868a53a083e893fb3ff418a4d54a8d463 Mon Sep 17 00:00:00 2001 From: nyrosmith Date: Sat, 4 Nov 2017 09:16:19 +0100 Subject: [PATCH 12/12] added test for "setsourceMetaData" --- src/actions/tests/ast.spec.js | 30 ++++++++++++++++++-- src/actions/tests/fixtures/reactComponent.js | 7 +++++ 2 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 src/actions/tests/fixtures/reactComponent.js diff --git a/src/actions/tests/ast.spec.js b/src/actions/tests/ast.spec.js index 4f8139db79..4306848ea8 100644 --- a/src/actions/tests/ast.spec.js +++ b/src/actions/tests/ast.spec.js @@ -6,7 +6,12 @@ import { } from "../../utils/test-head"; import readFixture from "./helpers/readFixture"; -const { getSymbols, getEmptyLines, getOutOfScopeLocations } = selectors; +const { + getSymbols, + getEmptyLines, + getOutOfScopeLocations, + getSourceMetaData +} = selectors; import getInScopeLines from "../../selectors/linesInScope"; const threadClient = { @@ -31,7 +36,8 @@ const threadClient = { const sourceTexts = { "base.js": "function base(boo) {}", "foo.js": "function base(boo) { return this.bazz; } outOfScope", - "scopes.js": readFixture("scopes.js") + "scopes.js": readFixture("scopes.js"), + "reactComponent.js": readFixture("reactComponent.js") }; const evaluationResult = { @@ -51,6 +57,26 @@ describe("ast", () => { expect(emptyLines).toMatchSnapshot(); }); }); + describe("setSourceMetaData", () => { + it("should detect react components", async () => { + const { dispatch, getState } = createStore(threadClient); + const source = makeSource("reactComponent.js"); + await dispatch(actions.newSource(source)); + await dispatch(actions.loadSourceText({ id: "reactComponent.js" })); + + const sourceMetaData = getSourceMetaData(getState(), source.id); + expect(sourceMetaData).toEqual({ isReactComponent: true }); + }); + it("should not give false positive on non react components", async () => { + const { dispatch, getState } = createStore(threadClient); + const source = makeSource("base.js"); + await dispatch(actions.newSource(source)); + await dispatch(actions.loadSourceText({ id: "base.js" })); + + const sourceMetaData = getSourceMetaData(getState(), source.id); + expect(sourceMetaData).toEqual({ isReactComponent: false }); + }); + }); describe("setSymbols", () => { describe("when the source is loaded", () => { it("should be able to set symbols", async () => { diff --git a/src/actions/tests/fixtures/reactComponent.js b/src/actions/tests/fixtures/reactComponent.js new file mode 100644 index 0000000000..526c852d99 --- /dev/null +++ b/src/actions/tests/fixtures/reactComponent.js @@ -0,0 +1,7 @@ +import React, { Component } from "react"; + +class FixtureComponent extends Component { + render() { + return null; + } +}