Skip to content

Commit b5f14ad

Browse files
authored
Experimental CodeMirror editor (#1670)
* Basic CodeMirror editor component Creates a basic CodeMirror-backed editor component. Currently hard-coded to replace the old editor component but should actually be lazy-loaded only in experimental mode. Lacks most of the features of the old editor component so far, but bare-bones functionality is there. * Add validation errors to CodeMirror editor Uses the `lint` addon, which basically does the right thing. Interface is a little strange in that you have to give it a function that returns a collection of errors (you cannot set errors imperatively). So in effect-world this means updating the editor configuration each time errors change, providing a new function to return the new set of errors. This seems to work well enough. * Add keybinding for autoformatting to CodeMirror editor * Support text zoom in CodeMirror editor * CodeMirror editor jumps to error location on click * Default to not allowing dev dependencies, then whitelist test & build files * Handle explicit save keyboard shortcut
1 parent bd9da37 commit b5f14ad

File tree

19 files changed

+802
-239
lines changed

19 files changed

+802
-239
lines changed

.eslintrc.json

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
"files": [
4545
"babel.config.js",
4646
"gulpfile.js",
47+
"jest.config.js",
4748
"karma.conf.js",
4849
"script/*.js",
4950
"webpack.config.js"
@@ -55,6 +56,12 @@
5556
},
5657
"rules": {
5758
"import/no-commonjs": "off",
59+
"import/no-extraneous-dependencies": [
60+
"error",
61+
{
62+
"devDependencies": true
63+
}
64+
],
5865
"import/no-nodejs-modules": "off",
5966
"lodash/import-scope": ["warn", "method-package"]
6067
},
@@ -74,6 +81,12 @@
7481
"jest-setup.js"
7582
],
7683
"rules": {
84+
"import/no-extraneous-dependencies": [
85+
"error",
86+
{
87+
"devDependencies": true
88+
}
89+
],
7790
"jest/no-alias-methods": "warn",
7891
"jest/no-disabled-tests": "warn",
7992
"jest/no-focused-tests": "warn",
@@ -108,27 +121,24 @@
108121
}
109122
}
110123
},
111-
{
112-
"files": "src/**/*",
113-
"rules": {
114-
"import/no-extraneous-dependencies": [
115-
"error",
116-
{
117-
"devDependencies": false
118-
}
119-
]
120-
}
121-
},
122124
{
123125
"files": "src/sagas/**/*",
124126
"rules": {
125127
"import/order": "off"
126128
}
127129
},
128130
{
129-
"files": "test/unit/**/*",
131+
"files": "test/**/*",
130132
"globals": {
131133
"sinon": true
134+
},
135+
"rules": {
136+
"import/no-extraneous-dependencies": [
137+
"error",
138+
{
139+
"devDependencies": true
140+
}
141+
]
132142
}
133143
},
134144
{
@@ -206,7 +216,12 @@
206216
],
207217
"import/no-commonjs": "warn",
208218
"import/no-cycle": "error",
209-
"import/no-extraneous-dependencies": "error",
219+
"import/no-extraneous-dependencies": [
220+
"error",
221+
{
222+
"devDependencies": false
223+
}
224+
],
210225
"import/no-mutable-exports": "warn",
211226
"import/no-named-default": "warn",
212227
"import/no-namespace": "warn",
@@ -222,6 +237,7 @@
222237
{
223238
"allow": [
224239
"brace/**/*",
240+
"codemirror/{addon,mode}/**/*",
225241
"core-js",
226242
"es6-set/implement",
227243
"firebase/*",
@@ -277,7 +293,7 @@
277293
"new-cap": [
278294
"warn",
279295
{
280-
"capIsNewExceptions": ["Slowparse.HTML", "Record"]
296+
"capIsNewExceptions": ["CodeMirror", "Slowparse.HTML", "Record"]
281297
}
282298
],
283299
"no-alert": "warn",

.renovaterc.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@
3636
"eslint-plugin-prettier",
3737
"eslint-plugin-private-props",
3838
"eslint-plugin-promise",
39-
"eslint-plugin-react"
39+
"eslint-plugin-react",
40+
"eslint-plugin-react-hooks"
4041
]
4142
},
4243
{
@@ -60,7 +61,6 @@
6061
"automerge": true,
6162
"packageNames": ["jest", "jest-extended"]
6263
},
63-
6464
{
6565
"groupName": "Karma",
6666
"automerge": true,
@@ -167,6 +167,7 @@
167167
"jscodeshift",
168168
"prettier",
169169
"sinon",
170+
"react-test-renderer",
170171
"rosie",
171172
"yarn-deduplicate"
172173
],
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import {Factory} from 'rosie';
2+
3+
export const position = new Factory().attrs({
4+
line: 0,
5+
ch: 0,
6+
});
7+
8+
export const change = new Factory()
9+
.attr('from', () => position.build())
10+
.attr('to', () => position.build())
11+
.attrs({
12+
text: 'c',
13+
removed: '',
14+
origin: '+input',
15+
});

__factories__/records/Error.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import {List} from 'immutable';
2+
import {Factory} from 'rosie';
3+
4+
import Error from '../../src/records/Error';
5+
6+
export const errorFactory = new Factory(Error).attrs({
7+
row: 3,
8+
column: 2,
9+
reason: 'bad-code',
10+
payload: {},
11+
suppresses: new List(),
12+
text: 'Bad code',
13+
raw: 'Bad code',
14+
});

__mocks__/bowser.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import constant from 'lodash-es/constant';
2+
3+
export default {
4+
getParser: constant({
5+
isOS: jest.fn().mockReturnValue(false),
6+
}),
7+
};

__mocks__/codemirror.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import assignIn from 'lodash-es/assignIn';
2+
import tap from 'lodash-es/tap';
3+
4+
export const Doc = jest.fn(() => ({}));
5+
6+
export default tap(
7+
jest.fn(() => ({
8+
focus: jest.fn(),
9+
getDoc: jest.fn().mockReturnValue({setCursor: jest.fn()}),
10+
on: jest.fn(),
11+
off: jest.fn(),
12+
performLint: jest.fn(),
13+
scrollIntoView: jest.fn(),
14+
setOption: jest.fn(),
15+
setSize: jest.fn(),
16+
swapDoc: jest.fn(),
17+
getValue: jest.fn().mockReturnValue(''),
18+
setValue: jest.fn(),
19+
})),
20+
CodeMirror => assignIn(CodeMirror, {Doc}),
21+
);

gulpfile.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ const srcDir = 'src';
2424
const distDir = 'dist';
2525
const stylesheetsDir = path.join(srcDir, 'css');
2626
const highlightStylesheetsDir = 'node_modules/highlight.js/styles';
27+
const codemirrorStylesheets = [
28+
'node_modules/codemirror/lib/codemirror.css',
29+
'node_modules/codemirror/addon/lint/lint.css',
30+
];
2731
const staticDir = path.join(srcDir, 'static');
2832
const bowerComponents = 'bower_components';
2933

@@ -60,6 +64,7 @@ gulp.task('css', () => {
6064
.src([
6165
path.join(bowerComponents, 'normalize-css/normalize.css'),
6266
path.join(highlightStylesheetsDir, 'github.css'),
67+
...codemirrorStylesheets,
6368
path.join(stylesheetsDir, '**/*.css'),
6469
])
6570
.pipe(concat('application.css'))

jest.config.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
/* eslint-env node */
2-
/* eslint-disable import/no-commonjs */
3-
4-
// For a detailed explanation regarding each configuration property, visit:
5-
// https://jestjs.io/docs/en/configuration.html
6-
71
module.exports = {
82
clearMocks: true,
93
moduleNameMapper: {

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@
207207
"brace": "0.11.1",
208208
"chrono-node": "1.3.11",
209209
"classnames": "2.2.6",
210+
"codemirror": "5.49.0",
210211
"core-js": "3.5.0",
211212
"css": "2.2.4",
212213
"delay": "4.3.0",
@@ -233,6 +234,7 @@
233234
"loadjs": "4.2.0",
234235
"lodash-es": "4.17.15",
235236
"loop-breaker": "0.1.1",
237+
"lru-cache": "5.1.1",
236238
"moment": "2.24.0",
237239
"mousetrap": "1.6.3",
238240
"object-inspect": "1.7.0",
@@ -373,6 +375,7 @@
373375
"postcss-preset-env": "6.7.0",
374376
"prettier": "1.19.1",
375377
"raw-loader": "4.0.0",
378+
"react-test-renderer": "16.10.2",
376379
"redux-saga-test-plan": "4.0.0-rc.3",
377380
"rosie": "2.0.1",
378381
"script-ext-html-webpack-plugin": "2.1.4",

0 commit comments

Comments
 (0)