Skip to content

Commit 3db14d6

Browse files
committed
moved expression building into a selector
1 parent 423f127 commit 3db14d6

File tree

4 files changed

+75
-60
lines changed

4 files changed

+75
-60
lines changed

src/actions/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import {
33
} from 'actions/types';
44

55
export function updateCode(code) {
6+
localStorage.setItem('code', code);
7+
68
return {
79
type: DID_UPDATE_CODE,
810
payload: code

src/components/viewer.js

Lines changed: 5 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import _ from 'lodash';
2-
import { connect } from 'react-redux';
32
import React, { Component } from 'react';
4-
import { transform } from 'babel-standalone';
5-
import esprima from 'esprima';
3+
import { connect } from 'react-redux';
4+
import parseExpressions from 'selectors/parse_expressions';
65

76
window.React = React;
87
window.Component = Component;
@@ -17,59 +16,6 @@ const DELIMITER_MAP = {
1716
};
1817

1918
class Viewer extends Component {
20-
constructor(props) {
21-
super(props);
22-
23-
// this.renderExpressions = _.memoize(code => this._renderExpressions(code, []));
24-
}
25-
26-
lineHasMoreDelimiters({ column }, lineContents) {
27-
return _.intersection(_.takeRight(lineContents, lineContents.length - column), OPEN_DELIMITERS).length;
28-
}
29-
30-
buildExpressions(code) {
31-
const transformedCode = transform(code, { presets: ['react']}).code;
32-
const codeByLine = transformedCode.split('\n');
33-
const tokenized = esprima.tokenize(transformedCode, { loc: true });
34-
35-
const parens = { '(': 0, '{': 0, '[': 0 };
36-
let wasOpen = false;
37-
const exp = _.reduce(tokenized, (expressions, { value, loc: { end } }, index) => {
38-
const lineNumber = end.line;
39-
const lineContents = codeByLine[lineNumber - 1];
40-
const lineHasMoreDelimiters = this.lineHasMoreDelimiters(end, lineContents);
41-
const endOfLine = end.column === lineContents.length;
42-
43-
if (expressions[lineNumber]) { return expressions; }
44-
45-
if (OPEN_DELIMITERS.includes(value)) {
46-
parens[value] += 1;
47-
wasOpen = true;
48-
}
49-
50-
if (CLOSE_DELIMITERS.includes(value)) {
51-
parens[DELIMITER_MAP[value]] -= 1;
52-
}
53-
54-
if (!lineHasMoreDelimiters && wasOpen && _.every(parens, count => count === 0)) {
55-
wasOpen = false;
56-
expressions[lineNumber] = _.take(codeByLine, lineNumber).join('\n');
57-
58-
return expressions;
59-
}
60-
61-
if (!lineHasMoreDelimiters && _.every(parens, count => count === 0)) {
62-
expressions[lineNumber] = _.take(codeByLine, lineNumber).join('\n');
63-
64-
return expressions;
65-
}
66-
67-
return expressions;
68-
}, {});
69-
70-
return exp;
71-
}
72-
7319
evaluateExpressions(expressions) {
7420
const formattedExpressions = _.mapValues(expressions, expression => {
7521
const result = eval(expression);
@@ -93,7 +39,7 @@ class Viewer extends Component {
9339
}
9440

9541
renderExpressions(code) {
96-
return this.evaluateExpressions(this.buildExpressions(code));
42+
return this.evaluateExpressions(this.props.expressions);
9743
}
9844

9945
render() {
@@ -105,8 +51,8 @@ class Viewer extends Component {
10551
}
10652
}
10753

108-
function mapStateToProps({ code }){
109-
return { code };
54+
function mapStateToProps(state){
55+
return { expressions: parseExpressions(state) };
11056
}
11157

11258
export default connect(mapStateToProps)(Viewer);

src/reducers/code_reducer.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { DID_UPDATE_CODE } from 'actions/types';
22

3-
export default function(state = '', action) {
3+
const INITIAL_STATE = localStorage.getItem('code') || '';
4+
5+
export default function(state = INITIAL_STATE, action) {
46
switch (action.type) {
57
case DID_UPDATE_CODE:
68
return action.payload

src/selectors/parse_expressions.js

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import _ from 'lodash';
2+
import { createSelector } from 'reselect';
3+
import { transform } from 'babel-standalone';
4+
import esprima from 'esprima';
5+
6+
const codeSelector = state => state.code;
7+
const OPEN_DELIMITERS = [ '(', '{', '[', '`' ];
8+
const CLOSE_DELIMITERS = [ ')', '}', ']', '`' ];
9+
const DELIMITER_MAP = {
10+
')': '(',
11+
'}': '{',
12+
']': '[',
13+
'`': '`'
14+
};
15+
16+
const findDelimiters = ({ column }, lineContents) =>
17+
_.intersection(_.takeRight(lineContents, lineContents.length - column), OPEN_DELIMITERS).length
18+
19+
const parseExpressions = (code) => {
20+
const transformedCode = transform(code, { presets: ['react']}).code;
21+
const codeByLine = transformedCode.split('\n');
22+
const tokenized = esprima.tokenize(transformedCode, { loc: true });
23+
24+
const parens = { '(': 0, '{': 0, '[': 0 };
25+
let wasOpen = false;
26+
const exp = _.reduce(tokenized, (expressions, { value, loc: { end } }, index) => {
27+
const lineNumber = end.line;
28+
const lineContents = codeByLine[lineNumber - 1];
29+
const lineHasMoreDelimiters = findDelimiters(end, lineContents);
30+
const endOfLine = end.column === lineContents.length;
31+
32+
if (expressions[lineNumber]) { return expressions; }
33+
34+
if (OPEN_DELIMITERS.includes(value)) {
35+
parens[value] += 1;
36+
wasOpen = true;
37+
}
38+
39+
if (CLOSE_DELIMITERS.includes(value)) {
40+
parens[DELIMITER_MAP[value]] -= 1;
41+
}
42+
43+
if (!lineHasMoreDelimiters && wasOpen && _.every(parens, count => count === 0)) {
44+
wasOpen = false;
45+
expressions[lineNumber] = _.take(codeByLine, lineNumber).join('\n');
46+
47+
return expressions;
48+
}
49+
50+
if (!lineHasMoreDelimiters && _.every(parens, count => count === 0)) {
51+
expressions[lineNumber] = _.take(codeByLine, lineNumber).join('\n');
52+
53+
return expressions;
54+
}
55+
56+
return expressions;
57+
}, {});
58+
59+
return exp;
60+
}
61+
62+
export default createSelector(
63+
codeSelector,
64+
parseExpressions
65+
);

0 commit comments

Comments
 (0)