Fiddle now showing compilation warnings and errors

This commit is contained in:
emizzle 2018-08-08 16:27:14 +10:00 committed by Pascal Precht
parent 52cec0a29e
commit 70f5a09d47
No known key found for this signature in database
GPG Key ID: 0EE28D8D6FD85D7D
7 changed files with 209 additions and 20 deletions

View File

@ -3,6 +3,7 @@ import AceEditor from 'react-ace';
import 'brace/mode/javascript';
import 'brace/theme/tomorrow_night_blue';
import 'ace-mode-solidity/build/remix-ide/mode-solidity';
import PropTypes from 'prop-types';
const Fiddle = ({onCodeChange, value}) => {
@ -23,4 +24,9 @@ const Fiddle = ({onCodeChange, value}) => {
);
};
Fiddle.propTypes = {
onCodeChange: PropTypes.func,
value: PropTypes.string
};
export default Fiddle;

View File

@ -0,0 +1,134 @@
import React, {Component} from 'react';
import {Card, List, Badge} from 'tabler-react';
import PropTypes from 'prop-types';
class FiddleResults extends Component{
constructor(props){
super(props);
this.state = {
errors: props.compilationResult.errors
};
}
static _removeClass(elems, className){
for(let elem of elems) {
elem.className = elem.className.replace(className, '').replace(' ', ' ');
}
}
static _toggleClass(elems, className){
for(let elem of elems) {
if(elem.className.indexOf(className) > -1){
FiddleResults._removeClass([elem], className);
}
else{
elem.className = (elem.className.length > 0 ? elem.className + ' ' : '') + className;
}
}
}
toggleCollapse(e) {
const collapsedClassName = 'card-collapsed';
const className = e.currentTarget.parentElement.className.replace('card-options', '').replace(' ', '');
const elems = document.getElementsByClassName(className + '-card');
FiddleResults._toggleClass(elems, collapsedClassName);
}
toggleFullscreen(e) {
const collapsedClassName = 'card-collapsed';
const fullscreenClassName = 'card-fullscreen';
const className = e.currentTarget.parentElement.className.replace('card-options', '').replace(' ', '');
const elems = document.getElementsByClassName(className + '-card');
FiddleResults._toggleClass(elems, fullscreenClassName);
FiddleResults._removeClass(elems, collapsedClassName);
}
render(){
const warningObjs = this.props.compilationResult.errors.filter(error => {
return error.severity === 'warning';
});
const errorObjs = this.props.compilationResult.errors.filter(error => {
return error.severity === 'error';
});
const warnings = warningObjs.map((warning, index) => {
return (
<List.GroupItem key={index} action>
<Badge color="warning" className="mr-1" key={index}>
Lines {warning.sourceLocation.start}-{warning.sourceLocation.end}
</Badge>
{warning.formattedMessage}
</List.GroupItem>
);
});
const errors = errorObjs.map((error, index) => {
return (
<List.GroupItem key={index} action>
<Badge color="danger" className="mr-1" key={index}>
Lines {error.sourceLocation.start}-{error.sourceLocation.end}
</Badge>
{error.formattedMessage}
</List.GroupItem>
);
});
const errorsCard = <Card
isCollapsible={true}
isFullscreenable={true}
statusColor="red"
statusSide="true"
className="errors-card"
key="errors">
<Card.Header>
<Card.Title color="red">Errors <Badge color="danger" className="mr-1">{errors.length}</Badge></Card.Title>
<Card.Options className="errors">
<Card.OptionsItem key="0" type="collapse" icon="chevron-up" onClick={this.toggleCollapse}/>
<Card.OptionsItem key="1" type="fullscreen" icon="maximize" onClick={this.toggleFullscreen}/>
</Card.Options>
</Card.Header>
<Card.Body>
<List.Group>
{errors}
</List.Group>
</Card.Body>
</Card>;
const warningsCard = <Card
isCollapsible={true}
isFullscreenable={true}
statusColor="warning"
statusSide="true"
className="warnings-card"
key="warnings">
<Card.Header>
<Card.Title color="warning">Warnings <Badge color="warning" className="mr-1">{warnings.length}</Badge></Card.Title>
<Card.Options className="warnings">
<Card.OptionsItem key="0" type="collapse" icon="chevron-up" onClick={this.toggleCollapse}/>
<Card.OptionsItem key="1" type="fullscreen" icon="maximize" onClick={this.toggleFullscreen}/>
</Card.Options>
</Card.Header>
<Card.Body>
<List.Group>
{warnings}
</List.Group>
</Card.Body>
</Card>;
let renderings = [];
if(!this.state.errors){
return 'Compilation successful (add green tick mark)';
}
if(errors.length) renderings.push(errorsCard);
if(warnings.length) renderings.push(warningsCard);
return (
<React.Fragment>
{renderings}
</React.Fragment>
);
}
}
FiddleResults.propTypes = {
compilationResult: PropTypes.object
};
export default FiddleResults;

View File

@ -1,29 +1,49 @@
/* eslint multiline-ternary: "off" */
/* eslint operator-linebreak: "off" */
import React, {Component} from 'react';
import {connect} from 'react-redux';
import PropTypes from 'prop-types';
import {fetchCodeCompilation} from '../actions';
import Fiddle from '../components/Fiddle';
import FiddleResults from '../components/FiddleResults';
class FiddleContainer extends Component {
constructor(props){
super(props)
this.state = { value: ''};
super(props);
this.state = {
value: ''
};
this.compileTimeout = null;
}
componentDidMount(){
if(this.state.value){
this.props.fetchCodeCompilation(this.state.value);
}
}
onCodeChange(newValue) {
this.setState({value: newValue});
this.props.fetchCodeCompilation(newValue);
if(this.compileTimeout) clearTimeout(this.compileTimeout);
this.compileTimeout = setTimeout(() => {
this.props.fetchCodeCompilation(newValue);
}, 1000);
}
render() {
const { fiddles } = this.props;
const {fiddles} = this.props;
let renderings = [<Fiddle key="0" value={this.state.value} onCodeChange={(n) => this.onCodeChange(n)} />];
if(fiddles.compilationResult) {
renderings.push(<FiddleResults key="1" compilationResult={fiddles.compilationResult}/>);
}
else renderings.push('Nothing to compile');
return (
<React.Fragment>
<Fiddle value={this.state.value} onCodeChange={(n) => this.onCodeChange(n)} />
<h2>Result</h2>
<p>{ fiddles.data ? JSON.stringify(fiddles.data) : 'No compilation results yet'}</p>
<React.Fragment>
{renderings}
</React.Fragment>
);
}

View File

@ -24,3 +24,6 @@
.text__new-line {
white-space: pre-line;
}
.card.card-fullscreen{
z-index:4;
}

View File

@ -3,7 +3,7 @@ import {RECEIVE_COMPILE_CODE, RECEIVE_COMPILE_CODE_ERROR} from "../actions";
export default function processes(state = {}, action) {
switch (action.type) {
case RECEIVE_COMPILE_CODE:
return Object.assign({}, state, {data: action.compilationResult});
return Object.assign({}, state, {compilationResult: action.compilationResult});
case RECEIVE_COMPILE_CODE_ERROR:
return Object.assign({}, state, {error: true});
default:

View File

@ -157,16 +157,19 @@ export function *watchCommunicationVersion() {
yield takeEvery(actions.MESSAGE_VERSION[actions.REQUEST], fetchCommunicationVersion);
}
export function* fetchCodeCompilation(action) {
export function *fetchCodeCompilation(action) {
try {
const codeCompilationResult = yield call(api.fetchCodeCompilation, action.codeToCompile);
yield put(actions.receiveCodeCompilation(codeCompilationResult));
const compilationResponse = yield call(api.fetchCodeCompilation, action.codeToCompile);
if(compilationResponse.status !== 200){
yield put(actions.receiveCodeCompilationError(compilationResponse.data));
}
else yield put(actions.receiveCodeCompilation(compilationResponse.data));
} catch (e) {
yield put(actions.receiveCodeCompilationError(e));
}
}
export function* watchFetchCodeCompilation() {
export function *watchFetchCodeCompilation() {
yield takeEvery(actions.FETCH_COMPILE_CODE, fetchCodeCompilation);
}

View File

@ -18,7 +18,7 @@ class Solidity {
this.events.setCommandHandler("contract:compile", (contractCode, cb) => {
const input = {'fiddler': {content: contractCode.replace(/\r\n/g, '\n')}};
this.compile_solidity_code(input, {}, cb);
this.compile_solidity_code(input, {}, true, cb);
});
embark.registerAPICall(
@ -26,15 +26,38 @@ class Solidity {
'/embark-api/contract/compile',
(req, res) => {
console.log('=====> POST contract/compile, req = ' + JSON.stringify(req.body));
this.events.request("contract:compile", req.body.code, (error, compilationResult) => {
console.log('=====> POST contract/compile, result = ' + JSON.stringify(compilationResult));
res.send(JSON.stringify({compilationResult}));
this.events.request("contract:compile", req.body.code, (errors, compilationResult) => {
console.log('=====> POST contract/compile, errors = ' + JSON.stringify(errors));
console.log('=====> POST contract/compile, compilationResult = ' + JSON.stringify(compilationResult));
res.send({errors:errors, compilationResult: compilationResult});
});
}
);
}
compile_solidity_code(codeInputs, originalFilepaths, cb){
_compile(jsonObj, returnAllErrors, callback){
this.solcW.compile(jsonObj, (err, output) => {
if(err){
return callback(err);
}
if(output.errors && returnAllErrors){
return callback(output.errors);
}
if (output.errors) {
for (let i=0; i<output.errors.length; i++) {
if (output.errors[i].type === 'Warning') {
this.logger.warn(output.errors[i].formattedMessage);
}
if (output.errors[i].type === 'Error' || output.errors[i].severity === 'error') {
return callback(new Error("Solidity errors: " + output.errors[i].formattedMessage).message);
}
}
}
callback(null, output);
});
}
compile_solidity_code(codeInputs, originalFilepaths, returnAllErrors, cb){
const self = this;
async.waterfall([
@ -204,7 +227,7 @@ class Solidity {
);
},
function compile(callback) {
self.compile_solidity_code(input, originalFilepath, callback);
self.compile_solidity_code(input, originalFilepath, false, callback);
}
], function (err, result) {
cb(err, result);