Skip to content

Commit 9c11342

Browse files
Migrate to argonaut-codecs from foreign-generic (#212)
1 parent 527c3de commit 9c11342

File tree

9 files changed

+73
-136
lines changed

9 files changed

+73
-136
lines changed

ci/build.sh

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@ case $COMPONENT in
1313
cd client
1414
npm install
1515
# Use production config, since we want to use these bundles for deploys
16-
npm config set trypurescript-client:configpath "config/prod/*.purs"
17-
npm run build
16+
npm run build:production
1817
;;
1918
*)
2019
echo >&2 "Unrecognised component: $COMPONENT"

client/.travis.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
language: node_js
2-
dist: trusty
2+
dist: bionic
33
sudo: required
4-
node_js: 6
4+
node_js: 12
55
install:
66
- npm install -g bower
77
- npm install
88
- bower install --production
99
script:
10-
- npm run -s bundle
10+
- npm run -s test

client/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
},
77
"scripts": {
88
"clean": "rimraf output",
9-
"test": "spago test --path $npm_package_config_configpath",
10-
"build": "spago build --path $npm_package_config_configpath",
11-
"bundle": "spago bundle-app --path $npm_package_config_configpath --purs-args '--censor-lib --strict' --to public/js/index.js"
9+
"test": "spago test --path config/dev/Try.Config.purs",
10+
"build": "spago build --path config/dev/Try.Config.purs",
11+
"build:production": "spago bundle-app --path config/prod/Try.Config.purs --purs-args '--censor-lib --strict' --to public/js/index.js"
1212
},
1313
"devDependencies": {
1414
"purescript": "^0.13.6",

client/spago.dhall

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,19 @@ You can edit this file as you like.
66
, dependencies =
77
[ "aff"
88
, "affjax"
9+
, "argonaut-codecs"
910
, "arrays"
1011
, "assert"
1112
, "bifunctors"
1213
, "console"
1314
, "const"
14-
, "contravariant"
1515
, "control"
1616
, "debug"
17-
, "distributive"
1817
, "effect"
1918
, "either"
20-
, "enums"
2119
, "exceptions"
22-
, "exists"
2320
, "foldable-traversable"
24-
, "foreign"
25-
, "foreign-generic"
2621
, "foreign-object"
27-
, "free"
2822
, "functions"
2923
, "functors"
3024
, "generics-rep"
@@ -33,28 +27,21 @@ You can edit this file as you like.
3327
, "integers"
3428
, "jquery"
3529
, "js-timers"
36-
, "lazy"
3730
, "math"
3831
, "maybe"
3932
, "node-fs"
4033
, "ordered-collections"
4134
, "parallel"
4235
, "prelude"
4336
, "profunctor"
44-
, "proxy"
4537
, "psci-support"
46-
, "quickcheck"
4738
, "random"
4839
, "refs"
4940
, "semirings"
50-
, "st"
5141
, "strings"
52-
, "tailrec"
5342
, "transformers"
5443
, "tuples"
55-
, "typelevel-prelude"
5644
, "unfoldable"
57-
, "validation"
5845
, "web-html"
5946
]
6047
, packages = ./packages.dhall

client/src/Main.purs

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,19 @@ import Control.Monad.Except.Trans (runExceptT)
66
import Data.Array (mapMaybe)
77
import Data.Array as Array
88
import Data.Either (Either(..))
9-
import Data.Foldable (elem, fold, for_, intercalate, traverse_)
9+
import Data.Foldable (elem, fold, for_, intercalate)
1010
import Data.FoldableWithIndex (forWithIndex_)
1111
import Data.Maybe (Maybe(..), fromMaybe)
1212
import Effect (Effect)
1313
import Effect.Aff (Aff, launchAff_)
1414
import Effect.Class (liftEffect)
1515
import Effect.Console (error)
1616
import Effect.Uncurried (EffectFn1, EffectFn2, EffectFn5, mkEffectFn1, runEffectFn1, runEffectFn2, runEffectFn5)
17-
import Foreign (renderForeignError)
1817
import Foreign.Object (Object)
1918
import Foreign.Object as Object
2019
import JQuery as JQuery
2120
import JQuery.Extras as JQueryExtras
22-
import Try.API (CompileError(..), CompileResult(..), CompileWarning(..), CompilerError(..), ErrorPosition(..), FailedResult(..), SuccessResult(..))
21+
import Try.API (CompileError(..), CompileResult(..), CompilerError)
2322
import Try.API as API
2423
import Try.Config as Config
2524
import Try.Gist (getGistById, tryLoadFileFromGist, uploadGist)
@@ -43,7 +42,7 @@ displayErrors errs = do
4342
column2 <- JQuery.select "#column2"
4443
JQueryExtras.empty column2
4544

46-
forWithIndex_ errs \i (CompilerError{ message }) -> do
45+
forWithIndex_ errs \i { message } -> do
4746
h1 <- JQuery.create "<h1>"
4847
JQuery.addClass "error-banner" h1
4948
JQuery.setText ("Error " <> show (i + 1) <> " of " <> show (Array.length errs)) h1
@@ -140,7 +139,11 @@ compile = do
140139
liftEffect cleanUpMarkers
141140

142141
case res of
143-
Right (CompileSuccess (SuccessResult { js, warnings })) -> do
142+
Left err -> liftEffect do
143+
hideLoadingMessage
144+
displayPlainText "Unable to parse the response from the server"
145+
error err
146+
Right (CompileSuccess { js, warnings }) -> do
144147
showJs <- liftEffect isShowJsChecked
145148
if showJs then liftEffect do
146149
hideLoadingMessage
@@ -149,43 +152,39 @@ compile = do
149152
sources <- runExceptT $ runLoader loader (JS js)
150153
liftEffect hideLoadingMessage
151154
for_ warnings \warnings_ -> liftEffect do
152-
let toAnnotation (CompileWarning{ errorCode, position, message }) =
153-
position <#> \(ErrorPosition pos) ->
154-
{ row: pos.startLine - 1
155-
, column: pos.startColumn - 1
156-
, type: "warning"
157-
, text: message
158-
}
155+
let
156+
toAnnotation { errorCode, position, message } =
157+
position <#> \pos ->
158+
{ row: pos.startLine - 1
159+
, column: pos.startColumn - 1
160+
, type: "warning"
161+
, text: message
162+
}
159163
runEffectFn1 setAnnotations (mapMaybe toAnnotation warnings_)
160164
for_ sources (liftEffect <<< execute (JS js))
161-
Right (CompileFailed (FailedResult { error })) -> liftEffect do
165+
Right (CompileFailed { error }) -> liftEffect do
162166
hideLoadingMessage
163167
case error of
164168
CompilerErrors errs -> do
165169
displayErrors errs
166-
167-
let toAnnotation (CompilerError{ position, message }) =
168-
position <#> \(ErrorPosition pos) ->
169-
{ row: pos.startLine - 1
170-
, column: pos.startColumn - 1
171-
, type: "error"
172-
, text: message
173-
}
170+
let
171+
toAnnotation { position, message } =
172+
position <#> \pos ->
173+
{ row: pos.startLine - 1
174+
, column: pos.startColumn - 1
175+
, type: "error"
176+
, text: message
177+
}
174178
runEffectFn1 setAnnotations (mapMaybe toAnnotation errs)
175-
176-
for_ errs \(CompilerError{ position }) ->
177-
for_ position \(ErrorPosition pos) ->
179+
for_ errs \{ position } ->
180+
for_ position \pos ->
178181
runEffectFn5 addMarker
179182
"error"
180183
pos.startLine
181184
pos.startColumn
182185
pos.endLine
183186
pos.endColumn
184187
OtherError err -> displayPlainText err
185-
Left errs -> liftEffect do
186-
hideLoadingMessage
187-
displayPlainText "Unable to parse the response from the server"
188-
traverse_ (error <<< renderForeignError) errs
189188

190189
-- | Execute the compiled code in a new iframe.
191190
execute :: JS -> Object JS -> Effect Unit

client/src/Try/API.purs

Lines changed: 31 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -19,111 +19,74 @@ import Affjax.RequestBody as AXRB
1919
import Affjax.ResponseFormat as AXRF
2020
import Affjax.StatusCode (StatusCode(..))
2121
import Control.Alt ((<|>))
22-
import Control.Monad.Except (ExceptT(..), runExcept)
22+
import Control.Monad.Except (ExceptT(..))
23+
import Data.Argonaut.Decode (class DecodeJson, decodeJson, (.:))
24+
import Data.Argonaut.Encode (encodeJson)
2325
import Data.Either (Either(..))
24-
import Data.Generic.Rep (class Generic)
25-
import Data.List.NonEmpty (NonEmptyList)
2626
import Data.Maybe (Maybe(..))
27+
import Data.Traversable (traverse)
2728
import Effect.Aff (Aff)
28-
import Foreign (ForeignError, unsafeToForeign)
29-
import Foreign.Class (class Decode, decode)
30-
import Foreign.Generic (defaultOptions, genericDecode)
31-
import Foreign.Generic.Class (Options, SumEncoding(..))
32-
33-
decodingOptions :: Options
34-
decodingOptions = defaultOptions { unwrapSingleConstructors = true }
3529

3630
-- | The range of text associated with an error
37-
newtype ErrorPosition = ErrorPosition
31+
type ErrorPosition =
3832
{ startLine :: Int
3933
, endLine :: Int
4034
, startColumn :: Int
4135
, endColumn :: Int
4236
}
4337

44-
derive instance genericErrorPosition :: Generic ErrorPosition _
45-
46-
instance decodeErrorPosition :: Decode ErrorPosition where
47-
decode = genericDecode decodingOptions
48-
49-
newtype CompilerError = CompilerError
38+
type CompilerError =
5039
{ message :: String
5140
, position :: Maybe ErrorPosition
5241
}
5342

54-
derive instance genericCompilerError :: Generic CompilerError _
55-
56-
instance decodeCompilerError :: Decode CompilerError where
57-
decode = genericDecode decodingOptions
58-
5943
-- | An error reported from the compile API.
6044
data CompileError
6145
= CompilerErrors (Array CompilerError)
6246
| OtherError String
6347

64-
derive instance genericCompileError :: Generic CompileError _
65-
66-
instance decodeCompileError :: Decode CompileError where
67-
decode = genericDecode
68-
(defaultOptions
69-
{ sumEncoding =
70-
TaggedObject
71-
{ tagFieldName: "tag"
72-
, contentsFieldName: "contents"
73-
, constructorTagTransform: identity
74-
}
75-
})
76-
77-
newtype Suggestion = Suggestion
48+
instance decodeJsonCompileError :: DecodeJson CompileError where
49+
decodeJson = decodeJson >=> \obj -> do
50+
contents <- obj .: "contents"
51+
obj .: "tag" >>= case _ of
52+
"OtherError" ->
53+
map OtherError $ decodeJson contents
54+
"CompilerErrors" ->
55+
map CompilerErrors $ traverse decodeJson =<< decodeJson contents
56+
_ ->
57+
Left "Tag must be one of: OtherError, CompilerErrors"
58+
59+
type Suggestion =
7860
{ replacement :: String
7961
, replaceRange :: Maybe ErrorPosition
8062
}
8163

82-
derive instance genericSuggestion :: Generic Suggestion _
83-
84-
instance decodeSuggestion :: Decode Suggestion where
85-
decode = genericDecode decodingOptions
86-
87-
newtype CompileWarning = CompileWarning
64+
type CompileWarning =
8865
{ errorCode :: String
8966
, message :: String
9067
, position :: Maybe ErrorPosition
9168
, suggestion :: Maybe Suggestion
9269
}
9370

94-
derive instance genericCompileWarning :: Generic CompileWarning _
95-
96-
instance decodeCompileWarning :: Decode CompileWarning where
97-
decode = genericDecode decodingOptions
98-
99-
newtype SuccessResult = SuccessResult
71+
type SuccessResult =
10072
{ js :: String
10173
, warnings :: Maybe (Array CompileWarning)
10274
}
10375

104-
derive instance genericSuccessResult :: Generic SuccessResult _
105-
106-
instance decodeSuccessResult :: Decode SuccessResult where
107-
decode = genericDecode decodingOptions
108-
109-
newtype FailedResult = FailedResult
110-
{ error :: CompileError }
111-
112-
derive instance genericFailedResult :: Generic FailedResult _
113-
114-
instance decodeFailedResult :: Decode FailedResult where
115-
decode = genericDecode decodingOptions
76+
type FailedResult =
77+
{ error :: CompileError
78+
}
11679

11780
-- | The result of calling the compile API.
11881
data CompileResult
11982
= CompileSuccess SuccessResult
12083
| CompileFailed FailedResult
12184

12285
-- | Parse the result from the compile API and verify it
123-
instance decodeCompileResult :: Decode CompileResult where
124-
decode f =
125-
CompileSuccess <$> genericDecode decodingOptions f
126-
<|> CompileFailed <$> genericDecode decodingOptions f
86+
instance decodeJsonCompileResult :: DecodeJson CompileResult where
87+
decodeJson json =
88+
map CompileSuccess (decodeJson json)
89+
<|> map CompileFailed (decodeJson json)
12790

12891
get :: URL -> ExceptT String Aff String
12992
get url = ExceptT $ AX.get AXRF.string url >>= case _ of
@@ -135,13 +98,13 @@ get url = ExceptT $ AX.get AXRF.string url >>= case _ of
13598
pure $ Right body
13699

137100
-- | POST the specified code to the Try PureScript API, and wait for a response.
138-
compile :: String -> String -> ExceptT String Aff (Either (NonEmptyList ForeignError) CompileResult)
139-
compile endpoint code = ExceptT $ AX.post AXRF.json (endpoint <> "/compile") (Just requestBody) >>= case _ of
101+
compile :: String -> String -> ExceptT String Aff (Either String CompileResult)
102+
compile endpoint code = ExceptT $ AX.post AXRF.json (endpoint <> "/compile") requestBody >>= case _ of
140103
Left e ->
141104
pure $ Left $ printError e
142105
Right { status } | status >= StatusCode 400 ->
143106
pure $ Left $ "Received error status code: " <> show status
144107
Right { body } ->
145-
pure $ Right $ runExcept (decode (unsafeToForeign body))
108+
pure $ Right $ decodeJson body
146109
where
147-
requestBody = AXRB.String code
110+
requestBody = Just $ AXRB.Json $ encodeJson code

client/src/Try/Gist.purs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ import Affjax.ResponseFormat as AXRF
1414
import Affjax.StatusCode (StatusCode(..))
1515
import Control.Monad.Except.Trans (ExceptT(..))
1616
import Data.Argonaut.Core (Json, caseJsonObject, stringify, toString)
17+
import Data.Argonaut.Encode (encodeJson)
1718
import Data.Either (Either(..))
1819
import Data.Function.Uncurried (Fn2, runFn2)
1920
import Data.Maybe (Maybe(..))
2021
import Data.Nullable (Nullable, toMaybe)
2122
import Effect.Aff (Aff)
22-
import Foreign.Generic (encodeJSON)
2323
import Foreign.Object as Object
2424
import Unsafe.Coerce (unsafeCoerce)
2525

@@ -51,7 +51,7 @@ uploadGist content = ExceptT $ AX.post AXRF.json "https://api.github.com/gists"
5151
_ -> Left "Key id was not a string."
5252

5353
where
54-
requestBody = Just $ AXRB.string $ encodeJSON
54+
requestBody = Just $ AXRB.json $ encodeJson
5555
{ description: "Published with try.purescript.org"
5656
, public: false
5757
, files: { "Main.purs": { content } }

client/src/Try/Types.purs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@ module Try.Types
22
( JS(..)
33
) where
44

5+
import Data.Argonaut.Encode (class EncodeJson)
56
import Data.Newtype (class Newtype)
6-
import Foreign.Class (class Encode)
77

88
newtype JS = JS String
99

1010
derive instance newtypeJS :: Newtype JS _
11-
12-
derive newtype instance encodeJS :: Encode JS
11+
derive newtype instance encodeJsonJS :: EncodeJson JS

0 commit comments

Comments
 (0)