feature(user-menu) improve error handling

This commit is contained in:
coderaiser 2019-08-20 22:29:28 +03:00
parent b8592d35c0
commit 64e6b8387a
5 changed files with 109 additions and 14 deletions

View file

@ -7,10 +7,13 @@ require('../../../css/user-menu.css');
const currify = require('currify/legacy');
const wraptile = require('wraptile/legacy');
const {promisify} = require('es6-promisify');
const fullstore = require('fullstore/legacy');
const load = require('load.js');
const createElement = require('@cloudcmd/create-element');
const tryCatch = require('try-catch');
const tryToCatch = require('try-to-catch/legacy');
const parse = require('./parse-error');
const {codeFrameColumns} = require('@babel/code-frame');
const Images = require('../../dom/images');
const Dialog = require('../../dom/dialog');
@ -18,6 +21,7 @@ const getUserMenu = require('./get-user-menu');
const navigate = require('./navigate');
const loadCSS = promisify(load.css);
const sourceStore = fullstore();
const Name = 'UserMenu';
CloudCmd[Name] = module.exports;
@ -45,12 +49,15 @@ async function show() {
const {dirPath} = CurrentInfo;
const res = await fetch(`${CloudCmd.prefix}/api/v1/user-menu?dir=${dirPath}`);
const [error, userMenu] = tryCatch(getUserMenu, await res.text());
const source = await res.text();
const [error, userMenu] = tryCatch(getUserMenu, source);
Images.hide();
if (error)
return Dialog.alert(`User menu error: ${error.message}`);
return Dialog.alert(getCodeFrame({error, source}));
sourceStore(source);
const options = Object
.keys(userMenu)
@ -132,18 +139,41 @@ const onKeyDown = currify(async (keys, options, userMenu, e) => {
const runUserMenu = async (value, options, userMenu) => {
hide();
const [e] = await tryToCatch(userMenu[value], {
const [error] = await tryToCatch(userMenu[value], {
DOM,
CloudCmd,
tryToCatch,
});
if (!e)
if (!error)
return;
if (e.name === 'Error')
return Dialog.alert(e.message);
return Dialog.alert(e.stack);
const source = sourceStore();
return Dialog.alert(getCodeFrame({
error,
source,
}));
};
function getCodeFrame({error, source}) {
if (error.code === 'frame')
return error.message;
const [line, column] = parse(error);
const start = {
line,
column,
};
const location = {
start,
};
const frame = codeFrameColumns(source, location, {
message: error.message,
highlightCode: false,
});
return `<pre>${frame}</pre>`;
}

View file

@ -0,0 +1,29 @@
'use strict';
const isNumber = (a) => typeof a === 'number';
module.exports = (error) => {
const {
lineNumber,
columnNumber,
} = error;
if (isNumber(lineNumber) && isNumber(columnNumber))
return [
lineNumber,
columnNumber,
];
const before = error.stack.indexOf('>');
const str = error.stack.slice(before + 1);
const after = str.indexOf(')');
const newStr = str.slice(1, after);
const [line, column] = newStr.split(':');
return [
Number(line),
Number(column),
];
};

View file

@ -0,0 +1,32 @@
'use strict';
const test = require('supertape');
const parseError = require('./parse-error');
test('user-menu: parse-error', (t) => {
const result = parseError({
lineNumber: 1,
columnNumber: 2,
});
const expected = [1, 2];
t.deepEqual(result, expected);
t.end();
});
test('user-menu: parse-error', (t) => {
const stack = `
ReferenceError: s is not defined
at eval (eval at module.exports (get-user-menu.js:NaN), <anonymous>:1:2)
at module.exports (get-user-menu.js:6)
at tryCatch (VM12611 try-catch.js:7)
at AsyncFunction.show (index.js:67)
`;
const result = parseError({stack});
const expected = [1, 2];
t.deepEqual(result, expected);
t.end();
});

View file

@ -162,6 +162,7 @@
"writejson": "^2.0.0"
},
"devDependencies": {
"@babel/code-frame": "^7.5.5",
"@babel/core": "^7.0.0",
"@babel/preset-env": "^7.0.0",
"@cloudcmd/clipboard": "^1.0.2",

View file

@ -72,13 +72,16 @@ async function onGET({req, res, menuName}) {
if (parseError)
return res
.type('js')
.send(`
throw Error(\`<pre>path: ${menuPath}\n\n${codeframe({
error: parseError,
source,
highlightCode: false,
})}
.send(`const e = Error(\`<pre>path: ${menuPath}\n\n${codeframe({
error: parseError,
source,
highlightCode: false,
})}
</pre>\`);
e.code = 'frame';
throw e;
`);
res