Skip to content

Commit 8f23f6b

Browse files
committed
Merge branch 'wip/yuras/omit_nothing' and add a little more testing
2 parents 472e8cd + 078333c commit 8f23f6b

File tree

7 files changed

+85
-10
lines changed

7 files changed

+85
-10
lines changed

aeson-typescript.cabal

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ cabal-version: 1.12
44
--
55
-- see: https://github.com/sol/hpack
66
--
7-
-- hash: 4cd249b25ad05ebb75210b2d877c1c9db25c3e5ad7ea0e05ca414f3120c3d342
7+
-- hash: b77cd606ddb441b9a4bc9592c1257172003cb38a9b39c2cc9b693a90110c1b52
88

99
name: aeson-typescript
1010
version: 0.2.0.0
@@ -81,8 +81,10 @@ test-suite aeson-typescript-test
8181
, unordered-containers
8282
other-modules:
8383
HigherKind
84+
NoOmitNothingFields
8485
ObjectWithSingleFieldNoTagSingleConstructors
8586
ObjectWithSingleFieldTagSingleConstructors
87+
OmitNothingFields
8688
TaggedObjectNoTagSingleConstructors
8789
TaggedObjectTagSingleConstructors
8890
TestBoilerplate

src/Data/Aeson/TypeScript/TH.hs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -263,9 +263,9 @@ handleConstructor options (DatatypeInfo {..}) genericVariables ci@(ConstructorIn
263263
stringEncoding = (stringE [i|"#{(constructorTagModifier options) $ getTypeName (constructorName ci)}"|], Nothing, True)
264264

265265
singleConstructorEncoding = if | constructorVariant ci == NormalConstructor -> tupleEncoding
266-
| otherwise -> Just $ assembleInterfaceDeclaration (ListE (getTSFields namesAndTypes))
266+
| otherwise -> Just $ assembleInterfaceDeclaration (ListE (getTSFields options namesAndTypes))
267267

268-
taggedConstructorEncoding = Just $ assembleInterfaceDeclaration (ListE (tagField ++ getTSFields namesAndTypes))
268+
taggedConstructorEncoding = Just $ assembleInterfaceDeclaration (ListE (tagField ++ getTSFields options namesAndTypes))
269269

270270
-- * Type declaration to use
271271
interfaceName = getInterfaceName ci
@@ -300,11 +300,19 @@ handleConstructor options (DatatypeInfo {..}) genericVariables ci@(ConstructorIn
300300

301301

302302
-- | Helper for handleConstructor
303-
getTSFields :: [(String, Type)] -> [Exp]
304-
getTSFields namesAndTypes = [(AppE (AppE (AppE (ConE 'TSField) (getOptionalAsBoolExp typ))
305-
(stringE nameString))
306-
(getTypeAsStringExp typ))
307-
| (nameString, typ) <- namesAndTypes]
303+
getTSFields :: Options -> [(String, Type)] -> [Exp]
304+
getTSFields options namesAndTypes =
305+
[ (AppE (AppE (AppE (ConE 'TSField) optAsBool)
306+
(stringE nameString))
307+
fieldTyp)
308+
| (nameString, typ) <- namesAndTypes
309+
, let (fieldTyp, optAsBool) = getFieldType options typ]
310+
311+
getFieldType :: Options -> Type -> (Exp, Exp)
312+
getFieldType options (AppT (ConT name) t)
313+
| not (omitNothingFields options) && name == ''Maybe
314+
= (AppE (AppE (VarE 'mappend) (getTypeAsStringExp t)) (stringE " | null"), getOptionalAsBoolExp t)
315+
getFieldType _ typ = (getTypeAsStringExp typ, getOptionalAsBoolExp typ)
308316

309317

310318
-- * Getting type expression

test/NoOmitNothingFields.hs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{-# LANGUAGE CPP, QuasiQuotes, OverloadedStrings, TemplateHaskell, RecordWildCards, ScopedTypeVariables, NamedFieldPuns, KindSignatures #-}
2+
3+
module NoOmitNothingFields (tests) where
4+
5+
import Data.Aeson as A
6+
import Data.Aeson.TypeScript.TH
7+
import Data.Aeson.TypeScript.Types
8+
import Data.Proxy
9+
import Test.Hspec
10+
import TestBoilerplate
11+
12+
$(testDeclarations "NoOmitNothingFields" (A.defaultOptions {omitNothingFields=False}))
13+
14+
main = hspec $ describe "NoOmitNothingFields" $ do
15+
it "encodes as expected" $ do
16+
let decls = getTypeScriptDeclarations (Proxy :: Proxy Optional)
17+
18+
decls `shouldBe` [TSInterfaceDeclaration {
19+
interfaceName = "Optional"
20+
, interfaceGenericVariables = []
21+
, interfaceMembers = [
22+
TSField {fieldOptional = False
23+
, fieldName = "optionalInt"
24+
, fieldType = "number | null"}
25+
]
26+
}]
27+
28+
tests

test/OmitNothingFields.hs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{-# LANGUAGE CPP, QuasiQuotes, OverloadedStrings, TemplateHaskell, RecordWildCards, ScopedTypeVariables, NamedFieldPuns, KindSignatures #-}
2+
3+
module OmitNothingFields (tests) where
4+
5+
import Data.Aeson as A
6+
import Data.Aeson.TypeScript.TH
7+
import Data.Aeson.TypeScript.Types
8+
import Data.Proxy
9+
import Test.Hspec
10+
import TestBoilerplate
11+
12+
$(testDeclarations "OmitNothingFields" (A.defaultOptions {omitNothingFields=True}))
13+
14+
main = hspec $ describe "OmitNothingFields" $ do
15+
it "encodes as expected" $ do
16+
let decls = getTypeScriptDeclarations (Proxy :: Proxy Optional)
17+
18+
decls `shouldBe` [TSInterfaceDeclaration {
19+
interfaceName = "Optional"
20+
, interfaceGenericVariables = []
21+
, interfaceMembers = [
22+
TSField {fieldOptional = True
23+
, fieldName = "optionalInt"
24+
, fieldType = "number"}
25+
]
26+
}]
27+
28+
tests

test/Spec.hs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import qualified TwoElemArrayNoTagSingleConstructors
1212
import qualified TwoElemArrayTagSingleConstructors
1313
import qualified UntaggedNoTagSingleConstructors
1414
import qualified UntaggedTagSingleConstructors
15+
import qualified OmitNothingFields
16+
import qualified NoOmitNothingFields
1517

1618
main = hspec $ do
1719
ObjectWithSingleFieldTagSingleConstructors.tests
@@ -23,3 +25,5 @@ main = hspec $ do
2325
UntaggedTagSingleConstructors.tests
2426
UntaggedNoTagSingleConstructors.tests
2527
HigherKind.tests
28+
OmitNothingFields.tests
29+
NoOmitNothingFields.tests

test/TestBoilerplate.hs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ data TwoField = TwoField { doubleInt :: Int, doubleString :: String }
1919
data Hybrid = HybridSimple Int | HybridRecord { hybridString :: String }
2020
data TwoConstructor = Con1 { con1String :: String } | Con2 { con2String :: String, con2Int :: Int }
2121
data Complex a = Nullary | Unary Int | Product String Char a | Record { testOne :: Int, testTwo :: Bool, testThree :: Complex a} deriving Eq
22+
data Optional = Optional {optionalInt :: Maybe Int}
2223

2324

2425
testDeclarations :: String -> A.Options -> Q [Dec]
@@ -32,6 +33,7 @@ testDeclarations testName aesonOptions = do
3233
deriveInstances ''Hybrid
3334
deriveInstances ''TwoConstructor
3435
deriveInstances ''Complex
36+
deriveInstances ''Optional
3537

3638
typesAndValues :: Exp <- [e|[(getTypeScriptType (Proxy :: Proxy Unit), A.encode Unit)
3739

@@ -52,7 +54,9 @@ testDeclarations testName aesonOptions = do
5254
, (getTypeScriptType (Proxy :: Proxy (Complex Int)), A.encode (Nullary :: Complex Int))
5355
, (getTypeScriptType (Proxy :: Proxy (Complex Int)), A.encode (Unary 42 :: Complex Int))
5456
, (getTypeScriptType (Proxy :: Proxy (Complex Int)), A.encode (Product "asdf" 'g' 42 :: Complex Int))
55-
, (getTypeScriptType (Proxy :: Proxy (Complex Int)), A.encode ((Record { testOne = 3, testTwo = True, testThree = Product "test" 'A' 123}) :: Complex Int))]
57+
, (getTypeScriptType (Proxy :: Proxy (Complex Int)), A.encode ((Record { testOne = 3, testTwo = True, testThree = Product "test" 'A' 123}) :: Complex Int))
58+
, (getTypeScriptType (Proxy :: Proxy Optional), A.encode (Optional { optionalInt = Nothing }))
59+
, (getTypeScriptType (Proxy :: Proxy Optional), A.encode (Optional { optionalInt = Just 1 }))]
5660
|]
5761

5862
declarations :: Exp <- [e|getTypeScriptDeclarations (Proxy :: Proxy Unit)
@@ -63,6 +67,7 @@ testDeclarations testName aesonOptions = do
6367
<> getTypeScriptDeclarations (Proxy :: Proxy Hybrid)
6468
<> getTypeScriptDeclarations (Proxy :: Proxy TwoConstructor)
6569
<> getTypeScriptDeclarations (Proxy :: Proxy Complex)
70+
<> getTypeScriptDeclarations (Proxy :: Proxy Optional)
6671
|]
6772

6873
tests <- [d|tests = describe $(return $ LitE $ StringL testName) $ it "type checks everything with tsc" $ testTypeCheckDeclarations $(return declarations) $(return typesAndValues)|]

test/Util.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ testTypeCheckDeclarations tsDeclarations typesAndVals = withSystemTempDirectory
7070
writeFile tsFile contents
7171

7272
tsc <- getTSC
73-
(code, output, err) <- readProcessWithExitCode tsc ["--noEmit", "--skipLibCheck", "--traceResolution", "--noResolve", tsFile] ""
73+
(code, output, err) <- readProcessWithExitCode tsc ["--strict", "--noEmit", "--skipLibCheck", "--traceResolution", "--noResolve", tsFile] ""
7474

7575
when (code /= ExitSuccess) $ do
7676
error [i|TSC check failed: #{output}. File contents were\n\n#{contents}|]

0 commit comments

Comments
 (0)