From 7f918babd5e22a3fc5c4374a28854c7221bb883e Mon Sep 17 00:00:00 2001 From: Shinyaigeek Date: Tue, 19 Jul 2022 00:23:46 +0900 Subject: [PATCH] Fix(transformer/elm): handle elm error --- packages/core/integration-tests/test/elm.js | 43 ++++++++++++++++ .../test/integration/elm-error/elm.json | 24 +++++++++ .../test/integration/elm-error/index.js | 5 ++ .../test/integration/elm-error/package.json | 1 + .../test/integration/elm-error/src/Main.elm | 49 +++++++++++++++++++ .../test/integration/elm-error/yarn.lock | 0 .../transformers/elm/src/ElmTransformer.js | 46 +++++++++++------ 7 files changed, 154 insertions(+), 14 deletions(-) create mode 100644 packages/core/integration-tests/test/integration/elm-error/elm.json create mode 100644 packages/core/integration-tests/test/integration/elm-error/index.js create mode 100644 packages/core/integration-tests/test/integration/elm-error/package.json create mode 100644 packages/core/integration-tests/test/integration/elm-error/src/Main.elm create mode 100644 packages/core/integration-tests/test/integration/elm-error/yarn.lock diff --git a/packages/core/integration-tests/test/elm.js b/packages/core/integration-tests/test/elm.js index 702be99b4f1..1d66e5b9757 100644 --- a/packages/core/integration-tests/test/elm.js +++ b/packages/core/integration-tests/test/elm.js @@ -133,4 +133,47 @@ describe('elm', function () { }, ); }); + + it('should produce correct formatting and indentation when elm fails without errors property', async function () { + await assert.rejects( + () => + bundle(path.join(__dirname, 'integration/elm-error/index.js'), { + mode: 'production', + }), + + { + name: 'BuildError', + diagnostics: [ + { + message: + '\n' + + '-- DEBUG REMNANTS ------------------------------------------------------------- \n' + + '\n' + + 'There are uses of the `Debug` module in the following modules:\n' + + '\n' + + ' **Main**\n' + + '\n' + + 'But the --optimize flag only works if all `Debug` functions are removed!\n' + + '\n' + + '__Note__: The issue is that --optimize strips out info needed by `Debug` functions.\n' + + 'Here are two examples:\n' + + '\n' + + ' (1) It shortens record field names. This makes the generated JavaScript is\n' + + ' smaller, but `Debug.toString` cannot know the real field names anymore.\n' + + '\n' + + ' (2) Values like `type Height = Height Float` are unboxed. This reduces\n' + + ' allocation, but it also means that `Debug.toString` cannot tell if it is\n' + + ' looking at a `Height` or `Float` value.\n' + + '\n' + + 'There are a few other cases like that, and it will be much worse once we start\n' + + 'inlining code. That optimization could move `Debug.log` and `Debug.todo` calls,\n' + + 'resulting in unpredictable behavior. I hope that clarifies why this restriction\n' + + 'exists!', + origin: '@parcel/elm-transformer', + stack: '', + }, + ], + }, + ); + }); }); diff --git a/packages/core/integration-tests/test/integration/elm-error/elm.json b/packages/core/integration-tests/test/integration/elm-error/elm.json new file mode 100644 index 00000000000..dea3450db11 --- /dev/null +++ b/packages/core/integration-tests/test/integration/elm-error/elm.json @@ -0,0 +1,24 @@ +{ + "type": "application", + "source-directories": [ + "src" + ], + "elm-version": "0.19.1", + "dependencies": { + "direct": { + "elm/browser": "1.0.2", + "elm/core": "1.0.5", + "elm/html": "1.0.0" + }, + "indirect": { + "elm/json": "1.1.3", + "elm/time": "1.0.0", + "elm/url": "1.0.0", + "elm/virtual-dom": "1.0.2" + } + }, + "test-dependencies": { + "direct": {}, + "indirect": {} + } +} diff --git a/packages/core/integration-tests/test/integration/elm-error/index.js b/packages/core/integration-tests/test/integration/elm-error/index.js new file mode 100644 index 00000000000..61906ed5a66 --- /dev/null +++ b/packages/core/integration-tests/test/integration/elm-error/index.js @@ -0,0 +1,5 @@ +var local = require('./src/Main.elm'); + +module.exports = function () { + return local; +}; \ No newline at end of file diff --git a/packages/core/integration-tests/test/integration/elm-error/package.json b/packages/core/integration-tests/test/integration/elm-error/package.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/packages/core/integration-tests/test/integration/elm-error/package.json @@ -0,0 +1 @@ +{} diff --git a/packages/core/integration-tests/test/integration/elm-error/src/Main.elm b/packages/core/integration-tests/test/integration/elm-error/src/Main.elm new file mode 100644 index 00000000000..df95eb026dd --- /dev/null +++ b/packages/core/integration-tests/test/integration/elm-error/src/Main.elm @@ -0,0 +1,49 @@ +module Main exposing (main) + +import Browser +import Html exposing (Html, button, div, text) +import Html.Events exposing (onClick) + + +type alias Model = + { count : Int } + + +initialModel : Model +initialModel = + { count = 0 } + + +type Msg + = Increment + | Decrement + + +update : Msg -> Model -> Model +update msg model = + case msg of + Increment -> + Debug.log "incremented!!" + { model | count = model.count + 1 } + + Decrement -> + Debug.log "decremented!!" + { model | count = model.count - 1 } + + +view : Model -> Html Msg +view model = + div [] + [ button [ onClick Increment ] [ text "+1" ] + , div [] [ text <| String.fromInt model.count ] + , button [ onClick Decrement ] [ text "-1" ] + ] + + +main : Program () Model Msg +main = + Browser.sandbox + { init = initialModel + , view = view + , update = update + } diff --git a/packages/core/integration-tests/test/integration/elm-error/yarn.lock b/packages/core/integration-tests/test/integration/elm-error/yarn.lock new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/transformers/elm/src/ElmTransformer.js b/packages/transformers/elm/src/ElmTransformer.js index 2ae6fa1f9e5..0e7c8fcad07 100644 --- a/packages/transformers/elm/src/ElmTransformer.js +++ b/packages/transformers/elm/src/ElmTransformer.js @@ -64,6 +64,20 @@ export default (new Transformer({ let compilerJson = e.message.split('\n')[1]; let compilerDiagnostics = JSON.parse(compilerJson); + // sometimes, `errors` property does not exist on the error object thrown by `compileToString` module. + // In such case, a content equal to `error.errors[num].problems[num]` is expanded. + // so this line handle such a case. + if (!compilerDiagnostics.errors) { + throw new ThrowableDiagnostic({ + diagnostic: elmProblemToParcelDiagnostic( + compilerDiagnostics, + compilerDiagnostics.path + ? path.relative(process.cwd(), compilerDiagnostics.path) + : '', + ), + }); + } + throw new ThrowableDiagnostic({ diagnostic: compilerDiagnostics.errors.flatMap( elmErrorToParcelDiagnostics, @@ -173,22 +187,26 @@ function formatMessagePiece(piece) { return md`${piece}`; } +function elmProblemToParcelDiagnostic(problem, relativePath) { + const padLength = 80 - 5 - problem.title.length - relativePath.length; + const dashes = '-'.repeat(padLength); + const message = [ + '', + `-- ${problem.title} ${dashes} ${relativePath}`, + '', + problem.message.map(formatMessagePiece).join(''), + ].join('\n'); + + return { + message, + origin: '@parcel/elm-transformer', + stack: '', // set stack to empty since it is not useful + }; +} + function elmErrorToParcelDiagnostics(error) { const relativePath = path.relative(process.cwd(), error.path); return error.problems.map(problem => { - const padLength = 80 - 5 - problem.title.length - relativePath.length; - const dashes = '-'.repeat(padLength); - const message = [ - '', - `-- ${problem.title} ${dashes} ${relativePath}`, - '', - problem.message.map(formatMessagePiece).join(''), - ].join('\n'); - - return { - message, - origin: '@parcel/elm-transformer', - stack: '', // set stack to empty since it is not useful - }; + return elmProblemToParcelDiagnostic(problem, relativePath); }); }