Skip to content

Commit 4a44e67

Browse files
authored
Svelte support (codesandbox#197)
* Svelte support * Add corrections to the API, support warnings * Remove style preprocessing support (for now) * Fix styling issues * Remove css import transpiler * Download support * Specify where warnings come from, fix columns * Fix error showing
1 parent 5c6b237 commit 4a44e67

File tree

25 files changed

+423
-37
lines changed

25 files changed

+423
-37
lines changed

src/app/components/sandbox/CodeEditor/Monaco.js

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,13 @@
22
import * as React from 'react';
33
import styled from 'styled-components';
44
import { debounce } from 'lodash';
5-
import type { Preferences, ModuleError, Module, Directory } from 'common/types';
5+
import type {
6+
Preferences,
7+
ModuleError,
8+
ModuleCorrection,
9+
Module,
10+
Directory,
11+
} from 'common/types';
612
import { getModulePath } from 'app/store/entities/sandboxes/modules/selectors';
713

814
import theme from 'common/theme';
@@ -28,6 +34,7 @@ type State = {
2834
type Props = {
2935
code: ?string,
3036
errors: ?Array<ModuleError>,
37+
corrections: Array<ModuleCorrection>,
3138
id: string,
3239
sandboxId: string,
3340
title: string,
@@ -134,12 +141,12 @@ const requireAMDModule = paths =>
134141
const handleError = (
135142
monaco,
136143
editor,
137-
currentErrors: ?Array<ModuleError>,
138-
nextErrors: ?Array<ModuleError>
144+
nextErrors: ?Array<ModuleError>,
145+
nextCorrections: Array<ModuleCorrection>
139146
) => {
140147
if (!monaco) return;
141148
if (nextErrors && nextErrors.length > 0) {
142-
const markers = nextErrors
149+
const errorMarkers = nextErrors
143150
.map(error => {
144151
if (error) {
145152
return {
@@ -156,10 +163,41 @@ const handleError = (
156163
})
157164
.filter(x => x);
158165

159-
monaco.editor.setModelMarkers(editor.getModel(), 'error', markers);
166+
monaco.editor.setModelMarkers(editor.getModel(), 'error', errorMarkers);
160167
} else {
161168
monaco.editor.setModelMarkers(editor.getModel(), 'error', []);
162169
}
170+
171+
if (nextCorrections.length > 0) {
172+
const correctionMarkers = nextCorrections
173+
.map(correction => {
174+
if (correction) {
175+
return {
176+
severity:
177+
correction.severity === 'warning'
178+
? monaco.Severity.Warning
179+
: monaco.Severity.Notice,
180+
startColumn: correction.column,
181+
startLineNumber: correction.line,
182+
endColumn: 1,
183+
endLineNumber: correction.line + 1,
184+
message: correction.message,
185+
source: correction.source,
186+
};
187+
}
188+
189+
return null;
190+
})
191+
.filter(x => x);
192+
193+
monaco.editor.setModelMarkers(
194+
editor.getModel(),
195+
'correction',
196+
correctionMarkers
197+
);
198+
} else {
199+
monaco.editor.setModelMarkers(editor.getModel(), 'correction', []);
200+
}
163201
};
164202

165203
export default class CodeEditor extends React.PureComponent<Props, State> {
@@ -343,6 +381,7 @@ export default class CodeEditor extends React.PureComponent<Props, State> {
343381
nextProps.sandboxId !== this.props.sandboxId ||
344382
nextProps.id !== this.props.id ||
345383
nextProps.errors !== this.props.errors ||
384+
nextProps.corrections !== this.props.corrections ||
346385
this.props.canSave !== nextProps.canSave ||
347386
this.props.preferences !== nextProps.preferences
348387
);
@@ -369,16 +408,13 @@ export default class CodeEditor extends React.PureComponent<Props, State> {
369408
};
370409

371410
componentWillUpdate(nextProps: Props) {
372-
const {
373-
id: currentId,
374-
sandboxId: currentSandboxId,
375-
errors: currentErrors,
376-
} = this.props;
411+
const { id: currentId, sandboxId: currentSandboxId } = this.props;
377412

378413
const {
379414
id: nextId,
380415
code: nextCode,
381416
errors: nextErrors,
417+
corrections: nextCorrections,
382418
title: nextTitle,
383419
sandboxId: nextSandboxId,
384420
} = nextProps;
@@ -401,15 +437,7 @@ export default class CodeEditor extends React.PureComponent<Props, State> {
401437
nextCode,
402438
nextTitle,
403439
}).then(() => {
404-
handleError(
405-
this.monaco,
406-
this.editor,
407-
currentErrors,
408-
nextErrors,
409-
nextCode,
410-
currentId,
411-
nextId
412-
);
440+
handleError(this.monaco, this.editor, nextErrors, nextCorrections);
413441
});
414442
}
415443
}

src/app/pages/Sandbox/Editor/Content/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ class EditorPreview extends React.PureComponent<Props, State> {
162162
changeCode={moduleActions.setCode}
163163
id={currentModule.id}
164164
errors={currentModule.errors}
165+
corrections={currentModule.corrections}
165166
code={currentModule.code}
166167
title={currentModule.title}
167168
canSave={currentModule.isNotSynced}

src/app/store/entities/sandboxes/modules/actions.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ export const SET_MODULE_SYNCED = 'SET_MODULE_SYNCED';
77
export const SET_MODULE_ERROR = 'SET_MODULE_ERROR';
88
export const CLEAR_MODULE_ERRORS = 'CLEAR_MODULE_ERRORS';
99

10+
export const ADD_MODULE_CORRECTION = 'ADD_MODULE_CORRECTION';
11+
1012
export default {
1113
renameModule: (id: string, title: string) => ({
1214
type: RENAME_MODULE,
@@ -49,4 +51,31 @@ export default {
4951
column,
5052
},
5153
}),
54+
55+
addCorrection: (
56+
id: string,
57+
{
58+
message,
59+
line,
60+
column,
61+
severity,
62+
source,
63+
}: {
64+
message: string,
65+
line: number,
66+
column: number,
67+
severity: 'warning' | 'notice',
68+
source: ?string,
69+
}
70+
) => ({
71+
id,
72+
type: ADD_MODULE_CORRECTION,
73+
correction: {
74+
message,
75+
line,
76+
column,
77+
severity,
78+
source,
79+
},
80+
}),
5281
};

src/app/store/entities/sandboxes/modules/entity.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export default new schema.Entity(
3535
return {
3636
...module,
3737
errors: [],
38+
corrections: [],
3839
code,
3940
isNotSynced,
4041
};

src/app/store/entities/sandboxes/modules/reducer.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
SET_CODE,
99
SET_MODULE_SYNCED,
1010
SET_MODULE_ERROR,
11+
ADD_MODULE_CORRECTION,
1112
CLEAR_MODULE_ERRORS,
1213
} from './actions';
1314

@@ -21,6 +22,15 @@ function moduleReducer(module: Module, action): Module {
2122
return { ...module, code: action.code, isNotSynced: true };
2223
case SET_MODULE_SYNCED:
2324
return { ...module, isNotSynced: false };
25+
case ADD_MODULE_CORRECTION:
26+
if (!isEqual(action.correction, module.corrections[0])) {
27+
return {
28+
...module,
29+
corrections: [...module.corrections, action.correction],
30+
};
31+
}
32+
33+
return module;
2434
case SET_MODULE_ERROR: {
2535
if (!isEqual(action.error, module.errors[0])) {
2636
return { ...module, errors: [...module.errors, action.error] };
@@ -46,6 +56,7 @@ export default function reducer(
4656
case MOVE_MODULE:
4757
case SET_CODE:
4858
case SET_MODULE_SYNCED:
59+
case ADD_MODULE_CORRECTION:
4960
case SET_MODULE_ERROR: {
5061
const module = state[action.id];
5162
if (module) {
@@ -57,7 +68,7 @@ export default function reducer(
5768
return state;
5869
}
5970
case CLEAR_MODULE_ERRORS: {
60-
return mapValues(state, m => ({ ...m, errors: [] }));
71+
return mapValues(state, m => ({ ...m, errors: [], corrections: [] }));
6172
}
6273
default:
6374
return state;

src/app/store/entities/sandboxes/utils/create-zip/index.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import JSZip from 'jszip';
33
import { saveAs } from 'file-saver';
44

55
import type { Sandbox, Module, Directory } from 'common/types';
6-
import { react, reactTs, vue, preact } from 'common/templates/index';
6+
import { react, reactTs, vue, preact, svelte } from 'common/templates/index';
77

88
const CSSTag = (resource: string) =>
99
`<link rel="stylesheet" type="text/css" href="${resource}" media="all">`;
@@ -117,6 +117,10 @@ export default (async function createZip(
117117
promise = import('./preact-cli').then(generator =>
118118
generator.default(zip, sandbox, modules, directories)
119119
);
120+
} else if (sandbox.template === svelte.name) {
121+
promise = import('./svelte').then(generator =>
122+
generator.default(zip, sandbox, modules, directories)
123+
);
120124
}
121125
if (promise) {
122126
await promise;
Binary file not shown.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import type { Sandbox, Module, Directory } from 'common/types';
2+
import files from 'buffer-loader!./files.zip'; // eslint-disable-line import/no-webpack-loader-syntax
3+
import { createPackageJSON, createDirectoryWithFiles } from '../';
4+
5+
export default function createZip(
6+
zip,
7+
sandbox: Sandbox,
8+
modules: Array<Module>,
9+
directories: Array<Directory>
10+
) {
11+
return zip.loadAsync(files).then(srcFolder => {
12+
const src = srcFolder.folder('src');
13+
14+
modules
15+
.filter(x => x.directoryShortid == null)
16+
.filter(x => x.title !== 'index.html') // This will be included in the body
17+
.forEach(x => src.file(x.title, x.code));
18+
19+
directories
20+
.filter(x => x.directoryShortid == null)
21+
.forEach(x => createDirectoryWithFiles(modules, directories, x, src));
22+
23+
zip.file(
24+
'package.json',
25+
createPackageJSON(
26+
sandbox,
27+
{},
28+
{
29+
rollup: '^0.47.6',
30+
'rollup-plugin-buble': '^0.15.0',
31+
'rollup-plugin-commonjs': '^8.1.0',
32+
'rollup-plugin-node-resolve': '^3.0.0',
33+
'rollup-plugin-svelte': '^3.1.0',
34+
'rollup-plugin-uglify': '^2.0.1',
35+
'rollup-watch': '^4.3.1',
36+
serve: '^6.0.6',
37+
},
38+
{
39+
build: 'rollup -c',
40+
dev: 'serve public & rollup -c -w',
41+
start: 'serve public',
42+
}
43+
)
44+
);
45+
});
46+
}

src/app/store/preview-actions-api/actions.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ export default {
1616
case 'show-error': {
1717
return dispatch(moduleActions.setError(action.moduleId, action));
1818
}
19+
case 'show-correction': {
20+
return dispatch(moduleActions.addCorrection(action.moduleId, action));
21+
}
1922
case 'source.module.rename': {
2023
const { sandboxId, moduleId, title } = action;
2124
return dispatch(

src/common/templates/index.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ export const vue = {
2323
color: decorateSelector(() => '#41B883'),
2424
};
2525

26+
export const svelte = {
27+
name: 'svelte',
28+
url: 'https://github.com/sveltejs/svelte',
29+
color: decorateSelector(() => '#AA1E1E'),
30+
};
31+
2632
export const preact = {
2733
name: 'preact-cli',
2834
url: 'https://github.com/developit/preact-cli',
@@ -49,6 +55,8 @@ export default function getDefinition(
4955
return preact;
5056
case reactTs.name:
5157
return reactTs;
58+
case svelte.name:
59+
return svelte;
5260
default:
5361
return react;
5462
}

0 commit comments

Comments
 (0)