diff --git a/generator/src/build.js b/generator/src/build.js index 9f3062be..78aab870 100755 --- a/generator/src/build.js +++ b/generator/src/build.js @@ -71,7 +71,7 @@ function initWorker(basePath) { pagesReady(JSON.parse(message.data)); } else if (message.tag === "error") { process.exitCode = 1; - console.error(restoreColor(message.data.errorsJson)); + console.error(restoreColor(message.data)); buildNextPage(newWorker); } else if (message.tag === "done") { buildNextPage(newWorker); @@ -225,7 +225,7 @@ function runElmMake(elmEntrypointPath, outputPath, cwd) { resolve(); } else { process.exitCode = 1; - reject(restoreColor(JSON.parse(commandOutput).errors)); + reject(restoreColor(JSON.parse(commandOutput))); } }); }); diff --git a/generator/src/dev-server.js b/generator/src/dev-server.js index 9715d82f..f8d7bcce 100644 --- a/generator/src/dev-server.js +++ b/generator/src/dev-server.js @@ -288,11 +288,10 @@ async function start(options) { try { await pendingCliCompile; } catch (error) { - const parsedErrors = JSON.parse(error).errors; + console.log(restoreColor(JSON.parse(error))); if (req.url.includes("content.json")) { - console.log("@@@1A"); res.writeHead(500, { "Content-Type": "application/json" }); - res.end(JSON.stringify(parsedErrors)); + res.end(error); } else { res.writeHead(500, { "Content-Type": "text/html" }); res.end(errorHtml()); @@ -335,10 +334,10 @@ async function start(options) { }, function (error) { - console.log(restoreColor(error.errorsJson)); + console.log(restoreColor(error)); if (req.url.includes("content.json")) { res.writeHead(500, { "Content-Type": "application/json" }); - res.end(JSON.stringify(error.errorsJson)); + res.end(JSON.stringify(error)); } else { res.writeHead(500, { "Content-Type": "text/html" }); res.end(errorHtml()); diff --git a/generator/src/error-formatter.js b/generator/src/error-formatter.js index 8ff051de..d17b4630 100644 --- a/generator/src/error-formatter.js +++ b/generator/src/error-formatter.js @@ -9,6 +9,10 @@ const kleur = require("kleur"); * * This function takes in the error title and the path to the file with the error and formats it like elm make's regular output **/ +/** + * @param {string} title + * @param {string} path + * */ const parseHeader = (title, path) => kleur.cyan( `-- ${title.replace("-", " ")} --------------- ${path || ""} @@ -20,6 +24,9 @@ const parseHeader = (title, path) => * * This function takes in the error message and makes sure that it has the proper formatting **/ +/** + * @param {Message} msg + * */ function parseMsg(msg) { if (typeof msg === "string") { return msg; @@ -36,19 +43,31 @@ function parseMsg(msg) { } } +/** @typedef {{problems: {title: string; message: unknown}[]; path: string}[]} Errors } */ + /** * parseMsg :: { errors: Array } -> String * * This function takes in the array of compiler errors and maps over them to generate a formatted compiler error **/ -const restoreColor = (errors) => { +/** + * @param {RootObject} error + * */ +const restoreColor = (error) => { try { - return errors - .map(({ problems, path }) => - problems.map(restoreProblem(path)).join("\n\n\n") - ) - .join("\n\n\n\n\n"); - } catch (error) { + if (error.type === "compile-errors") { + return error.errors + .map(({ problems, path }) => + problems.map(restoreProblem(path)).join("\n\n\n") + ) + .join("\n\n\n\n\n"); + } else if (error.type === "error") { + return restoreProblem(error.path)(error); + } else { + throw `Unexpected error ${JSON.stringify(error, null, 2)}`; + } + } catch (e) { + console.trace("Unexpected error format", e.toString()); return error.toString(); } }; @@ -59,8 +78,22 @@ const restoreColor = (errors) => { * This function takes in the array of compiler errors and maps over them to generate a formatted compiler error **/ const restoreProblem = - (path) => - ({ title, message }) => + (/** @type {string} */ path) => + (/** @type {{title:string; message: Message[]}} */ { title, message }) => [parseHeader(title, path), ...message.map(parseMsg)].join(""); module.exports = { restoreColor }; + +/** @typedef { CompilerError | ReportError } RootObject */ + +/** @typedef { { type: "compile-errors"; errors: Error_[]; } } CompilerError */ +/** @typedef { { type: "error"; path: string; title: string; message: Message[]; } } ReportError */ + +/** @typedef { { line: number; column: number; } } Location */ + +/** @typedef { { start: Location; end: Location; } } Region */ + +/** @typedef { { title: string; region: Region; message: Message[]; } } Problem */ +/** @typedef {string | {underline: boolean; color: string?; string: string}} Message */ + +/** @typedef { { path: string; name: string; problems: Problem[]; } } Error_ */ diff --git a/generator/src/render-worker.js b/generator/src/render-worker.js index c199e2d8..9a23825d 100644 --- a/generator/src/render-worker.js +++ b/generator/src/render-worker.js @@ -32,7 +32,11 @@ async function run({ mode, pathname }) { throw `Unknown mode ${mode}`; } } catch (error) { - parentPort.postMessage({ tag: "error", data: error }); + if (error.errorsJson) { + parentPort.postMessage({ tag: "error", data: error.errorsJson }); + } else { + parentPort.postMessage({ tag: "error", data: error }); + } } console.timeEnd(`${threadId} ${pathname}`); } diff --git a/generator/static-code/hmr.js b/generator/static-code/hmr.js index daabcbfe..e4dffbe0 100644 --- a/generator/static-code/hmr.js +++ b/generator/static-code/hmr.js @@ -31,11 +31,19 @@ async function handleEvent(sendContentJsonPort, evt) { const elmJsResponse = await elmJsRequest; thenApplyHmr(elmJsResponse); } catch (errorJson) { - console.log({ errorJson }); - showError({ - type: "compile-errors", - errors: errorJson, - }); + if (typeof errorJson === "string") { + errorJson = JSON.parse(errorJson) + } + if (errorJson.type) { + showError(errorJson); + } else if (errorJson.length > 0) { + showError({ + type: "compile-errors", + errors: errorJson, + }); + } else { + showError(JSON.parse(errorJson.errorsJson.errors)); + } } } else if (evt.data === "elm.js") { showCompiling(""); @@ -74,10 +82,13 @@ async function updateContentJsonWith( hideCompiling("fast"); }); } catch (errorJson) { - showError({ - type: "compile-errors", - errors: errorJson, - }); + if (errorJson.type) { + showError(errorJson); + } else if (typeof errorJson === 'string') { + showError(JSON.parse(errorJson)); + } else { + showError(errorJson); + } } }); } @@ -240,20 +251,35 @@ const consoleMsg = ({ error, style }, msg) => ({ const joinMessage = ({ error, style }) => [error.join("")].concat(style); -const parseConsoleErrors = (path) => ({ title, message }) => +const parseConsoleErrors = (path) => +/** + * @param {{ title: string; message: Message[]}} info + * */ +(info) => joinMessage( - message.reduce(consoleMsg, { - error: [consoleHeader(title, path)], + info.message.reduce(consoleMsg, { + error: [consoleHeader(info.title, path)], style: [styleColor("blue")], }) ); -const restoreColorConsole = ({ errors }) => - errors.reduce( - (acc, { problems, path }) => - acc.concat(problems.map(parseConsoleErrors(path))), - [] - ); + /** + * @param {RootObject} error + * */ +const restoreColorConsole = (error) => { + + if (error.type === 'compile-errors' && error.errors) { + return error.errors.reduce( + (acc, { problems, path }) => + acc.concat(problems.map(parseConsoleErrors(path))), + [] + ); + } else if (error.type === 'error') { + return parseConsoleErrors(error.path)(error) + } else { + console.error(`Unknown error type ${error}`); + } +} /* |------------------------------------------------------------------------------- @@ -275,12 +301,23 @@ const htmlMsg = (acc, msg) => const parseHtmlErrors = (path) => ({ title, message }) => message.reduce(htmlMsg, htmlHeader(title, path)); -const restoreColorHtml = ({ errors }) => - errors.reduce( - (acc, { problems, path }) => - acc.concat(problems.map(parseHtmlErrors(path))), - [] - ); +const restoreColorHtml = +/** + * @param {RootObject} error + * */ +(error) => { + if (error.type === 'compile-errors') { + return error.errors.reduce( + (acc, { problems, path }) => + acc.concat(problems.map(parseHtmlErrors(path))), + [] + ); + } else if (error.type === 'error') { + return parseHtmlErrors(error.path)(error); + } else { + throw new Error(`Unknown error type ${error}`); + } +} /* |------------------------------------------------------------------------------- @@ -291,6 +328,9 @@ const restoreColorHtml = ({ errors }) => var speed = 400; var delay = 20; +/** + * @param {RootObject} error + */ function showError(error) { restoreColorConsole(error).forEach((error) => { console.log.apply(this, error); @@ -575,3 +615,16 @@ function hideCompiling(velocity) { } } } + +/** @typedef { CompilerError | ReportError } RootObject */ + +/** @typedef { { type: "compile-errors"; errors: Error_[]; } } CompilerError */ +/** @typedef { { type: "error"; path: string; title: string; message: Message[]; } } ReportError */ + +/** @typedef { { line: number; column: number; } } CodeLocation */ + +/** @typedef { { start: CodeLocation; end: CodeLocation; } } Region */ + +/** @typedef { { title: string; region: Region; message: Message[]; } } Problem */ +/** @typedef {string | {underline: boolean; color: string?; string: string}} Message */ +/** @typedef { { path: string; name: string; problems: Problem[]; } } Error_ */ \ No newline at end of file diff --git a/src/BuildError.elm b/src/BuildError.elm index 6972a325..48d74331 100644 --- a/src/BuildError.elm +++ b/src/BuildError.elm @@ -34,12 +34,21 @@ banner title = ] -encode : BuildError -> Encode.Value -encode buildError = +encode : List BuildError -> Encode.Value +encode buildErrors = Encode.object - [ ( "path", Encode.string buildError.path ) - , ( "name", Encode.string buildError.title ) - , ( "problems", Encode.list (messagesEncoder buildError.title) [ buildError.message ] ) + [ ( "type", Encode.string "compile-errors" ) + , ( "errors" + , Encode.list + (\buildError -> + Encode.object + [ ( "path", Encode.string buildError.path ) + , ( "name", Encode.string buildError.title ) + , ( "problems", Encode.list (messagesEncoder buildError.title) [ buildError.message ] ) + ] + ) + buildErrors + ) ] diff --git a/src/Pages/Internal/Platform/ToJsPayload.elm b/src/Pages/Internal/Platform/ToJsPayload.elm index 82c88830..65b64402 100644 --- a/src/Pages/Internal/Platform/ToJsPayload.elm +++ b/src/Pages/Internal/Platform/ToJsPayload.elm @@ -38,7 +38,7 @@ errorCodec = |> Codec.field "errorsJson" identity (Codec.build - (Json.Encode.list BuildError.encode) + BuildError.encode (Decode.succeed [ { title = "TODO", message = [], fatal = True, path = "" } ]) ) |> Codec.buildObject