Skip to content

Commit

Permalink
Print full type error in Try Flow
Browse files Browse the repository at this point in the history
Summary:
Before this change, we only printed the top-most error on Try Flow.
Increasingly, we are using the "extra" field of an error to provide essential
context for an error.

For example, given the code:

```
type A = { p: { q: string } };
type B = { +p: { +q: number } };
declare var a: A;
(a: B);
```

Try flow would only print:

```
4: (a: B);
    ^ object type. This type is incompatible with
4: (a: B);
       ^ object type
```

After this change, we see the full error:

```
4: (a: B);
    ^ object type. This type is incompatible with
4: (a: B);
       ^ object type
  Property `p` is incompatible:
    1: type A = { p: { q: string } };
                     ^ object type. This type is incompatible with
    2: type B = { +p: { +q: number } };
                      ^ object type
      Property `q` is incompatible:
        1: type A = { p: { q: string } };
                              ^ string. This type is incompatible with
        2: type B = { +p: { +q: number } };
                                ^ number
```

Reviewed By: mroch

Differential Revision: D5860352

fbshipit-source-id: bddce1a8eca450a5bb6e0eeaeba3e3659034b28f
  • Loading branch information
samwgoldman authored and facebook-github-bot committed Sep 19, 2017
1 parent b47d62b commit b6d12e4
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 48 deletions.
8 changes: 8 additions & 0 deletions website/_assets/css/_try.scss
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,14 @@ html.site-fullscreen .content {
border-top: solid #eee 1px;
}

li ul li,
li ul li + li {
padding: inherit;
padding-left: 20px;
margin: inherit;
border: none;
}

.msgHighlight,
.msgType {
cursor: pointer;
Expand Down
128 changes: 80 additions & 48 deletions website/_assets/js/tryFlow.js.es6.liquid
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ CodeMirror.defineOption('flow', null, function(editor) {
editor.performLint();
});

function printError(err, editor) {
function appendMsg(container, msg, editor) {
const clickHandler = (msg) => {
editor.getDoc().setSelection(
{line: msg.loc.start.line - 1, ch: msg.loc.start.column - 1},
Expand All @@ -21,55 +21,83 @@ function printError(err, editor) {
editor.focus();
};

return err.message.reduce((container, msg) => {
if (msg.loc && msg.context != null) {
const div = document.createElement('div');
const filename = msg.loc.source !== '-' ? `${msg.loc.source}:` : '';
const prefix = `${filename}${msg.loc.start.line}: `;

const before = msg.context.slice(0, msg.loc.start.column - 1);
const highlight = (msg.loc.start.line === msg.loc.end.line) ?
msg.context.slice(msg.loc.start.column - 1, msg.loc.end.column) :
msg.context.slice(msg.loc.start.column - 1);
const after = (msg.loc.start.line === msg.loc.end.line) ?
msg.context.slice(msg.loc.end.column) :
'';
div.appendChild(document.createTextNode(prefix + before));
const bold = document.createElement('strong');
bold.className = "msgHighlight";
bold.appendChild(document.createTextNode(highlight));
div.appendChild(bold);
div.appendChild(document.createTextNode(after));
container.appendChild(div);

const offset = msg.loc.start.column + prefix.length - 1;
const arrow = `${(prefix + before).replace(/[^ ]/g, ' ')}^ `;
container.appendChild(document.createTextNode(arrow));

const span = document.createElement('span');
span.className = "msgType";
span.appendChild(document.createTextNode(msg.descr));
container.appendChild(span);

const handler = clickHandler.bind(null, msg);
bold.addEventListener('click', handler);
span.addEventListener('click', handler);
} else {
const descr = `. ${msg.descr}\n`;
container.appendChild(document.createTextNode(descr));
}
return container;
}, document.createElement('li'));
if (msg.loc && msg.context != null) {
const div = document.createElement('div');
const filename = msg.loc.source !== '-' ? `${msg.loc.source}:` : '';
const prefix = `${filename}${msg.loc.start.line}: `;

const before = msg.context.slice(0, msg.loc.start.column - 1);
const highlight = (msg.loc.start.line === msg.loc.end.line) ?
msg.context.slice(msg.loc.start.column - 1, msg.loc.end.column) :
msg.context.slice(msg.loc.start.column - 1);
const after = (msg.loc.start.line === msg.loc.end.line) ?
msg.context.slice(msg.loc.end.column) :
'';
div.appendChild(document.createTextNode(prefix + before));
const bold = document.createElement('strong');
bold.className = "msgHighlight";
bold.appendChild(document.createTextNode(highlight));
div.appendChild(bold);
div.appendChild(document.createTextNode(after));
container.appendChild(div);

const offset = msg.loc.start.column + prefix.length - 1;
const arrow = `${(prefix + before).replace(/[^ ]/g, ' ')}^ `;
container.appendChild(document.createTextNode(arrow));

const span = document.createElement('span');
span.className = "msgType";
span.appendChild(document.createTextNode(msg.descr));
container.appendChild(span);

const handler = clickHandler.bind(null, msg);
bold.addEventListener('click', handler);
span.addEventListener('click', handler);
} else if (msg.type === "Comment") {
const descr = `. ${msg.descr}\n`;
container.appendChild(document.createTextNode(descr));
} else {
const descr = `${msg.descr}\n`;
container.appendChild(document.createTextNode(descr));
}
};

function printExtra(info, editor) {
const list = document.createElement('ul');
if (info.message) {
const li = document.createElement('li');
info.message.forEach(msg => appendMsg(li, msg, editor));
list.appendChild(li);
}
if (info.children) {
const li = document.createElement('li');
info.children.forEach(info => {
li.appendChild(printExtra(info, editor));
});
list.appendChild(li);
}
return list;
}

function printErrors(errors, editor) {
if (errors.length == 0) {
return document.createTextNode('No errors!');
function printError(err, editor) {
const li = document.createElement('li');
err.message.forEach(msg => appendMsg(li, msg, editor));

if (err.extra) {
err.extra.forEach(info => {
li.appendChild(printExtra(info, editor));
});
}
return errors.reduce((list, err) => {

return li;
}

function printErrors(errors, editor) {
const list = document.createElement('ul');
errors.forEach(err => {
list.appendChild(printError(err, editor));
return list;
}, document.createElement('ul'));
});
return list;
}

function removeChildren(node) {
Expand Down Expand Up @@ -358,8 +386,12 @@ function createEditor(

editor.on('flowErrors', errors => {
if (errorsNode) {
removeChildren(errorsNode);
errorsNode.appendChild(printErrors(errors, editor));
if (errors.length) {
removeChildren(errorsNode);
errorsNode.appendChild(printErrors(errors, editor));
} else {
errorsNode.innerText = 'No errors!';
}
}

if (jsonNode) {
Expand Down

0 comments on commit b6d12e4

Please sign in to comment.