aeson-typescript 0.4.2.0 → 0.5.0.0
raw patch · 36 files changed
+462/−439 lines, 36 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Data.Aeson.TypeScript.Internal: [fieldDoc] :: TSField -> Maybe String
+ Data.Aeson.TypeScript.Internal: [interfaceDoc] :: TSDeclaration -> Maybe String
+ Data.Aeson.TypeScript.Internal: [typeDoc] :: TSDeclaration -> Maybe String
+ Data.Aeson.TypeScript.LegalName: checkIllegalNameChars :: NonEmpty Char -> Maybe (NonEmpty Char)
+ Data.Aeson.TypeScript.TH: defaultNameFormatter :: String -> String
- Data.Aeson.TypeScript.Internal: TSField :: Bool -> String -> String -> TSField
+ Data.Aeson.TypeScript.Internal: TSField :: Bool -> String -> String -> Maybe String -> TSField
- Data.Aeson.TypeScript.Internal: TSInterfaceDeclaration :: String -> [String] -> [TSField] -> TSDeclaration
+ Data.Aeson.TypeScript.Internal: TSInterfaceDeclaration :: String -> [String] -> [TSField] -> Maybe String -> TSDeclaration
- Data.Aeson.TypeScript.Internal: TSTypeAlternatives :: String -> [String] -> [String] -> TSDeclaration
+ Data.Aeson.TypeScript.Internal: TSTypeAlternatives :: String -> [String] -> [String] -> Maybe String -> TSDeclaration
Files
- CHANGELOG.md +12/−0
- README.md +2/−0
- aeson-typescript.cabal +31/−3
- src/Data/Aeson/TypeScript/Formatting.hs +62/−12
- src/Data/Aeson/TypeScript/Instances.hs +3/−7
- src/Data/Aeson/TypeScript/LegalName.hs +39/−0
- src/Data/Aeson/TypeScript/Lookup.hs +4/−13
- src/Data/Aeson/TypeScript/Recursive.hs +1/−11
- src/Data/Aeson/TypeScript/TH.hs +18/−21
- src/Data/Aeson/TypeScript/Transform.hs +0/−9
- src/Data/Aeson/TypeScript/TypeManipulation.hs +0/−9
- src/Data/Aeson/TypeScript/Types.hs +49/−12
- src/Data/Aeson/TypeScript/Util.hs +21/−11
- test/Basic.hs +5/−17
- test/ClosedTypeFamilies.hs +20/−33
- test/Formatting.hs +65/−20
- test/Generic.hs +11/−32
- test/GetDoc.hs +33/−0
- test/HigherKind.hs +10/−24
- test/LegalNameSpec.hs +24/−0
- test/NoOmitNothingFields.hs +2/−24
- test/ObjectWithSingleFieldNoTagSingleConstructors.hs +0/−12
- test/ObjectWithSingleFieldTagSingleConstructors.hs +0/−12
- test/OmitNothingFields.hs +2/−15
- test/OpenTypeFamilies.hs +20/−33
- test/Spec.hs +19/−10
- test/TaggedObjectNoTagSingleConstructors.hs +0/−12
- test/TaggedObjectTagSingleConstructors.hs +0/−12
- test/TestBoilerplate.hs +0/−12
- test/TwoElemArrayNoTagSingleConstructors.hs +0/−12
- test/TwoElemArrayTagSingleConstructors.hs +0/−12
- test/UntaggedNoTagSingleConstructors.hs +0/−11
- test/UntaggedTagSingleConstructors.hs +0/−11
- test/UnwrapUnaryRecords.hs +4/−15
- test/Util.hs +3/−2
- test/Util/Aeson.hs +2/−0
CHANGELOG.md view
@@ -1,5 +1,17 @@ # Change log ++## (unreleased)++## 0.5.0.0++* [#35](https://github.com/codedownio/aeson-typescript/pull/35)+ * Add `Data.Aeson.TypeScript.LegalName` module for checking whether a name is a legal JavaScript name or not.+ * The `defaultFormatter` will `error` if the name contains illegal characters.+* Be able to transfer Haddock comments to emitted TypeScript (requires GHC >= 9.2 and `-haddock` flag)+* Add support for @no-emit-typescript in Haddocks for constructors and record fields (requires GHC >= 9.2 and `-haddock` flag)+* Support GHC 9.6.1+ ## 0.4.2.0 * Fix TypeScript (A.KeyMap a) instance
README.md view
@@ -16,6 +16,7 @@ | Product String Char a | Record { testOne :: Double , testTwo :: Bool+ -- | This docstring will go into the generated TypeScript! , testThree :: D a } deriving Eq ```@@ -41,6 +42,7 @@ tag: "record"; One: number; Two: boolean;+ // This docstring will go into the generated TypeScript! Three: D<T>; } ```
aeson-typescript.cabal view
@@ -1,11 +1,11 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.35.0.+-- This file has been generated from package.yaml by hpack version 0.35.1. -- -- see: https://github.com/sol/hpack name: aeson-typescript-version: 0.4.2.0+version: 0.5.0.0 synopsis: Generate TypeScript definition files from your ADTs description: Please see the README on Github at <https://github.com/codedownio/aeson-typescript#readme> category: Text, Web, JSON@@ -36,6 +36,7 @@ Data.Aeson.TypeScript.TH Data.Aeson.TypeScript.Internal Data.Aeson.TypeScript.Recursive+ Data.Aeson.TypeScript.LegalName other-modules: Data.Aeson.TypeScript.Formatting Data.Aeson.TypeScript.Instances@@ -47,6 +48,16 @@ Paths_aeson_typescript hs-source-dirs: src+ default-extensions:+ LambdaCase+ MultiWayIf+ NamedFieldPuns+ OverloadedStrings+ QuasiQuotes+ RecordWildCards+ ScopedTypeVariables+ TupleSections+ ViewPatterns build-depends: aeson , base >=4.7 && <5@@ -68,7 +79,9 @@ ClosedTypeFamilies Formatting Generic+ GetDoc HigherKind+ LegalNameSpec NoOmitNothingFields ObjectWithSingleFieldNoTagSingleConstructors ObjectWithSingleFieldTagSingleConstructors@@ -87,6 +100,7 @@ Data.Aeson.TypeScript.Formatting Data.Aeson.TypeScript.Instances Data.Aeson.TypeScript.Internal+ Data.Aeson.TypeScript.LegalName Data.Aeson.TypeScript.Lookup Data.Aeson.TypeScript.Recursive Data.Aeson.TypeScript.TH@@ -98,7 +112,21 @@ hs-source-dirs: test src- ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N+ default-extensions:+ LambdaCase+ MultiWayIf+ NamedFieldPuns+ OverloadedStrings+ QuasiQuotes+ RecordWildCards+ ScopedTypeVariables+ TupleSections+ ViewPatterns+ FlexibleContexts+ KindSignatures+ TemplateHaskell+ TypeFamilies+ ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N -haddock -fno-warn-unused-top-binds -fno-warn-orphans build-depends: aeson , aeson-typescript
src/Data/Aeson/TypeScript/Formatting.hs view
@@ -1,8 +1,11 @@-{-# LANGUAGE QuasiQuotes, OverloadedStrings, TemplateHaskell, RecordWildCards, ScopedTypeVariables, NamedFieldPuns, CPP #-}+{-# LANGUAGE CPP #-} module Data.Aeson.TypeScript.Formatting where import Data.Aeson.TypeScript.Types+import Data.Function ((&))+import qualified Data.List as L+import Data.Maybe import Data.String.Interpolate import qualified Data.Text as T @@ -17,34 +20,61 @@ -- | Format a single TypeScript declaration. This version accepts a FormattingOptions object in case you want more control over the output. formatTSDeclaration :: FormattingOptions -> TSDeclaration -> String-formatTSDeclaration (FormattingOptions {..}) (TSTypeAlternatives name genericVariables names) =- case typeAlternativesFormat of- Enum -> [i|#{exportPrefix exportMode}enum #{typeNameModifier name} { #{alternativesEnum} }|]- EnumWithType -> [i|#{exportPrefix exportMode}enum #{typeNameModifier name} { #{alternativesEnumWithType} }#{enumType}|]- TypeAlias -> [i|#{exportPrefix exportMode}type #{typeNameModifier name}#{getGenericBrackets genericVariables} = #{alternatives};|]+formatTSDeclaration (FormattingOptions {..}) (TSTypeAlternatives name genericVariables names maybeDoc) =+ makeDocPrefix maybeDoc <> mainDeclaration where+ mainDeclaration = case typeAlternativesFormat of+ Enum -> [i|#{exportPrefix exportMode}enum #{typeNameModifier name} { #{alternativesEnum} }|]+ EnumWithType -> [i|#{exportPrefix exportMode}enum #{typeNameModifier name} { #{alternativesEnumWithType} }#{enumType}|]+ TypeAlias -> [i|#{exportPrefix exportMode}type #{typeNameModifier name}#{getGenericBrackets genericVariables} = #{alternatives};|]+ alternatives = T.intercalate " | " (fmap T.pack names) alternativesEnum = T.intercalate ", " $ [toEnumName entry | entry <- T.pack <$> names] alternativesEnumWithType = T.intercalate ", " $ [toEnumName entry <> "=" <> entry | entry <- T.pack <$> names] enumType = [i|\n\ntype #{name} = keyof typeof #{typeNameModifier name};|] :: T.Text toEnumName = T.replace "\"" "" -formatTSDeclaration (FormattingOptions {..}) (TSInterfaceDeclaration interfaceName genericVariables members) =- [i|#{exportPrefix exportMode}interface #{modifiedInterfaceName}#{getGenericBrackets genericVariables} {+formatTSDeclaration (FormattingOptions {..}) (TSInterfaceDeclaration interfaceName genericVariables (filter (not . isNoEmitTypeScriptField) -> members) maybeDoc) =+ makeDocPrefix maybeDoc <> [i|#{exportPrefix exportMode}interface #{modifiedInterfaceName}#{getGenericBrackets genericVariables} { #{ls}-}|] where ls = T.intercalate "\n" $ fmap T.pack [(replicate numIndentSpaces ' ') <> formatTSField member <> ";"| member <- members]- modifiedInterfaceName = (\(li, name) -> li <> interfaceNameModifier name) . splitAt 1 $ interfaceName+}|] where+ ls = T.intercalate "\n" $ [indentTo numIndentSpaces (T.pack (formatTSField member <> ";")) | member <- members]+ modifiedInterfaceName = (\(li, name) -> li <> interfaceNameModifier name) . splitAt 1 $ interfaceName formatTSDeclaration _ (TSRawDeclaration text) = text +indentTo :: Int -> T.Text -> T.Text+indentTo numIndentSpaces input = T.intercalate "\n" [padding <> line | line <- T.splitOn "\n" input]+ where padding = T.replicate numIndentSpaces " "+ exportPrefix :: ExportMode -> String exportPrefix ExportEach = "export " exportPrefix ExportNone = "" -- | Format a list of TypeScript declarations into a string, suitable for putting directly into a @.d.ts@ file. formatTSDeclarations' :: FormattingOptions -> [TSDeclaration] -> String-formatTSDeclarations' options declarations = T.unpack $ T.intercalate "\n\n" (fmap (T.pack . formatTSDeclaration (validateFormattingOptions options declarations)) declarations)+formatTSDeclarations' options allDeclarations =+ declarations & fmap (T.pack . formatTSDeclaration (validateFormattingOptions options declarations))+ & T.intercalate "\n\n"+ & T.unpack+ where+ removedDeclarations = filter isNoEmitTypeScriptDeclaration allDeclarations + getDeclarationName :: TSDeclaration -> Maybe String+ getDeclarationName (TSInterfaceDeclaration {..}) = Just interfaceName+ getDeclarationName (TSTypeAlternatives {..}) = Just typeName+ _ = Nothing++ removedDeclarationNames = mapMaybe getDeclarationName removedDeclarations++ removeReferencesToRemovedNames :: [String] -> TSDeclaration -> TSDeclaration+ removeReferencesToRemovedNames removedNames decl@(TSTypeAlternatives {..}) = decl { alternativeTypes = [x | x <- alternativeTypes, not (x `L.elem` removedNames)] }+ removeReferencesToRemovedNames _ x = x++ declarations = allDeclarations+ & filter (not . isNoEmitTypeScriptDeclaration)+ & fmap (removeReferencesToRemovedNames removedDeclarationNames)+ validateFormattingOptions :: FormattingOptions -> [TSDeclaration] -> FormattingOptions validateFormattingOptions options@FormattingOptions{..} decls | typeAlternativesFormat == Enum && isPlainSumType decls = options@@ -60,8 +90,28 @@ isPlainSumType ds = (not . any isInterface $ ds) && length ds == 1 formatTSField :: TSField -> String-formatTSField (TSField optional name typ) = [i|#{name}#{if optional then ("?" :: String) else ""}: #{typ}|]+formatTSField (TSField optional name typ maybeDoc) = makeDocPrefix maybeDoc <> [i|#{name}#{if optional then ("?" :: String) else ""}: #{typ}|] +makeDocPrefix :: Maybe String -> String+makeDocPrefix maybeDoc = case maybeDoc of+ Nothing -> ""+ Just (T.pack -> text) -> ["// " <> line | line <- T.splitOn "\n" text]+ & T.intercalate "\n"+ & (<> "\n")+ & T.unpack+ getGenericBrackets :: [String] -> String getGenericBrackets [] = "" getGenericBrackets xs = [i|<#{T.intercalate ", " (fmap T.pack xs)}>|]++-- * Support for @no-emit-typescript++noEmitTypeScriptAnnotation :: String+noEmitTypeScriptAnnotation = "@no-emit-typescript"++isNoEmitTypeScriptField (TSField {fieldDoc=(Just doc)}) = noEmitTypeScriptAnnotation `L.isInfixOf` doc+isNoEmitTypeScriptField _ = False++isNoEmitTypeScriptDeclaration (TSInterfaceDeclaration {interfaceDoc=(Just doc)}) = noEmitTypeScriptAnnotation `L.isInfixOf` doc+isNoEmitTypeScriptDeclaration (TSTypeAlternatives {typeDoc=(Just doc)}) = noEmitTypeScriptAnnotation `L.isInfixOf` doc+isNoEmitTypeScriptDeclaration _ = False
src/Data/Aeson/TypeScript/Instances.hs view
@@ -1,8 +1,4 @@-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE OverlappingInstances #-}@@ -89,9 +85,9 @@ instance (TypeScript a, TypeScript b) => TypeScript (Either a b) where getTypeScriptType _ = [i|Either<#{getTypeScriptType (Proxy :: Proxy a)}, #{getTypeScriptType (Proxy :: Proxy b)}>|]- getTypeScriptDeclarations _ = [TSTypeAlternatives "Either" ["T1", "T2"] ["Left<T1>", "Right<T2>"]- , TSInterfaceDeclaration "Left" ["T"] [TSField False "Left" "T"]- , TSInterfaceDeclaration "Right" ["T"] [TSField False "Right" "T"]+ getTypeScriptDeclarations _ = [TSTypeAlternatives "Either" ["T1", "T2"] ["Left<T1>", "Right<T2>"] Nothing+ , TSInterfaceDeclaration "Left" ["T"] [TSField False "Left" "T" Nothing] Nothing+ , TSInterfaceDeclaration "Right" ["T"] [TSField False "Right" "T" Nothing] Nothing ] getParentTypes _ = L.nub [ (TSType (Proxy :: Proxy a)) , (TSType (Proxy :: Proxy b))
+ src/Data/Aeson/TypeScript/LegalName.hs view
@@ -0,0 +1,39 @@+-- | This module defines functions which are useful for determining if+-- a given name is a legal JavaScript name according to+-- <https://stackoverflow.com/questions/1661197/what-characters-are-valid-for-javascript-variable-names this post>.+module Data.Aeson.TypeScript.LegalName where++import Data.Char+import Data.List.NonEmpty (NonEmpty (..))+import qualified Data.List.NonEmpty as NonEmpty+import qualified Data.Set as Set+++-- | The return type is the illegal characters that are in the name. If the+-- input has no illegal characters, then you have 'Nothing'.+checkIllegalNameChars :: NonEmpty Char -> Maybe (NonEmpty Char)+checkIllegalNameChars (firstChar :| restChars) = NonEmpty.nonEmpty $+ let+ legalFirstCategories =+ Set.fromList+ [ UppercaseLetter+ , LowercaseLetter+ , TitlecaseLetter+ , ModifierLetter+ , OtherLetter+ , LetterNumber+ ]+ legalRestCategories =+ Set.fromList+ [ NonSpacingMark+ , SpacingCombiningMark+ , DecimalNumber+ , ConnectorPunctuation+ ]+ `Set.union` legalFirstCategories+ isIllegalFirstChar c = not $+ c `elem` ['$', '_'] || generalCategory c `Set.member` legalFirstCategories+ isIllegalRestChar c = not $+ generalCategory c `Set.member` legalRestCategories+ in+ filter isIllegalFirstChar [firstChar] <> filter isIllegalRestChar restChars
src/Data/Aeson/TypeScript/Lookup.hs view
@@ -1,17 +1,8 @@ {-# LANGUAGE CPP #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE MultiWayIf #-}-{-# LANGUAGE ViewPatterns #-} {-# LANGUAGE PolyKinds #-}-{-# LANGUAGE LambdaCase #-} module Data.Aeson.TypeScript.Lookup where @@ -46,16 +37,16 @@ fields <- forM eqns $ \case #if MIN_VERSION_template_haskell(2,15,0) TySynEqn Nothing (AppT (ConT _) (ConT arg)) result -> do- [| TSField False (getTypeScriptType (Proxy :: Proxy $(conT arg))) (getTypeScriptType (Proxy :: Proxy $(return result))) |]+ [| TSField False (getTypeScriptType (Proxy :: Proxy $(conT arg))) (getTypeScriptType (Proxy :: Proxy $(return result))) Nothing |] TySynEqn Nothing (AppT (ConT _) (PromotedT arg)) result -> do- [| TSField False (getTypeScriptType (Proxy :: Proxy $(promotedT arg))) (getTypeScriptType (Proxy :: Proxy $(return result))) |]+ [| TSField False (getTypeScriptType (Proxy :: Proxy $(promotedT arg))) (getTypeScriptType (Proxy :: Proxy $(return result))) Nothing |] #else TySynEqn [ConT arg] result -> do- [| TSField False (getTypeScriptType (Proxy :: Proxy $(conT arg))) (getTypeScriptType (Proxy :: Proxy $(return result))) |]+ [| TSField False (getTypeScriptType (Proxy :: Proxy $(conT arg))) (getTypeScriptType (Proxy :: Proxy $(return result))) Nothing |] #endif x -> fail [i|aeson-typescript doesn't know yet how to handle this type family equation: '#{x}'|] - [| TSInterfaceDeclaration $(TH.stringE $ nameBase name) [] (L.sortBy (compare `on` fieldName) $(listE $ fmap return fields)) |]+ [| TSInterfaceDeclaration $(TH.stringE $ nameBase name) [] (L.sortBy (compare `on` fieldName) $(listE $ fmap return fields)) Nothing |] getClosedTypeFamilyImage :: [TySynEqn] -> Q [Type] getClosedTypeFamilyImage eqns = do
src/Data/Aeson/TypeScript/Recursive.hs view
@@ -1,14 +1,6 @@-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE MultiWayIf #-}-{-# LANGUAGE ViewPatterns #-}-{-# LANGUAGE LambdaCase #-} {-# LANGUAGE PolyKinds #-} module Data.Aeson.TypeScript.Recursive (@@ -29,6 +21,7 @@ import Control.Monad.Writer import Data.Aeson.TypeScript.Instances () import Data.Aeson.TypeScript.TH+import Data.Aeson.TypeScript.Util (nothingOnFail) import Data.Bifunctor import Data.Function import qualified Data.List as L@@ -135,6 +128,3 @@ addIfNotPresent :: (Eq a) => a -> [a] -> [a] addIfNotPresent x xs | x `L.elem` xs = xs addIfNotPresent x xs = x : xs--nothingOnFail :: Q a -> Q (Maybe a)-nothingOnFail action = recover (return Nothing) (Just <$> action)
src/Data/Aeson/TypeScript/TH.hs view
@@ -1,17 +1,8 @@ {-# LANGUAGE CPP #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE MultiWayIf #-}-{-# LANGUAGE ViewPatterns #-} {-# LANGUAGE PolyKinds #-}-{-# LANGUAGE LambdaCase #-} {-| Module: Data.Aeson.TypeScript.TH@@ -127,6 +118,7 @@ , formatTSDeclaration , FormattingOptions(..) , defaultFormattingOptions+ , defaultNameFormatter , SumTypeFormat(..) , ExportMode(..) @@ -194,7 +186,7 @@ xs -> zip xs allStarConstructors'' genericVariablesAndSuffixes <- forM varsAndTVars $ \(var, tvar) -> do (_, genericInfos) <- runWriterT $ forM_ (datatypeCons datatypeInfo') $ \ci ->- forM_ (namesAndTypes options [] ci) $ \(_, typ) -> do+ forM_ (namesAndTypes options [] ci) $ \(_, _, typ) -> do searchForConstraints extraOptions typ var return (var, (unifyGenericVariable genericInfos, tvar)) @@ -216,10 +208,11 @@ let typeVariablePreds :: [Pred] = [AppT (ConT ''TypeScript) x | x <- getDataTypeVars dti] -- Build the declarations- (types, (extraDeclsOrGenericInfosInitial <>) -> extraDeclsOrGenericInfos) <- runWriterT $ mapM (handleConstructor options dti genericVariablesAndSuffixes) (datatypeCons dti)+ (types, (extraDeclsOrGenericInfosInitial <>) -> extraDeclsOrGenericInfos) <- runWriterT $ mapM (handleConstructor extraOptions options dti genericVariablesAndSuffixes) (datatypeCons dti) typeDeclaration <- [|TSTypeAlternatives $(TH.stringE $ getTypeName (datatypeName dti)) $(genericVariablesListExpr True genericVariablesAndSuffixes)- $(listE $ fmap return types)|]+ $(listE $ fmap return types)+ $(tryGetDoc (haddockModifier extraOptions) (datatypeName dti))|] declarationsFunctionBody <- [| $(return typeDeclaration) : $(listE (fmap return [x | ExtraDecl x <- extraDeclsOrGenericInfos])) |] @@ -243,8 +236,8 @@ return (mconcat [x | ExtraTopLevelDecs x <- extraDeclsOrGenericInfos] <> inst) -- | Return a string to go in the top-level type declaration, plus an optional expression containing a declaration-handleConstructor :: Options -> DatatypeInfo -> [(Name, (Suffix, Var))] -> ConstructorInfo -> WriterT [ExtraDeclOrGenericInfo] Q Exp-handleConstructor options (DatatypeInfo {..}) genericVariables ci = do+handleConstructor :: ExtraTypeScriptOptions -> Options -> DatatypeInfo -> [(Name, (Suffix, Var))] -> ConstructorInfo -> WriterT [ExtraDeclOrGenericInfo] Q Exp+handleConstructor (ExtraTypeScriptOptions {..}) options (DatatypeInfo {..}) genericVariables ci = do if | (length datatypeCons == 1) && not (getTagSingleConstructors options) -> do writeSingleConstructorEncoding brackets <- lift $ getBracketsExpression False genericVariables@@ -269,7 +262,7 @@ lift [|$(TH.stringE interfaceName) <> $(return brackets)|] | otherwise -> do tagField :: [Exp] <- lift $ case sumEncoding options of- TaggedObject tagFieldName _ -> (: []) <$> [|TSField False $(TH.stringE tagFieldName) $(TH.stringE [i|"#{constructorNameToUse options ci}"|])|]+ TaggedObject tagFieldName _ -> (: []) <$> [|TSField False $(TH.stringE tagFieldName) $(TH.stringE [i|"#{constructorNameToUse options ci}"|]) Nothing|] _ -> return [] tsFields <- getTSFields@@ -294,7 +287,8 @@ _ -> getTypeAsStringExp typ alternatives <- lift [|TSTypeAlternatives $(TH.stringE interfaceName) $(genericVariablesListExpr True genericVariables)- [$(return stringExp)]|]+ [$(return stringExp)]+ $(tryGetDoc haddockModifier (constructorName ci))|] tell [ExtraDecl alternatives] #endif @@ -309,21 +303,24 @@ tupleEncoding = lift [|TSTypeAlternatives $(TH.stringE interfaceName) $(genericVariablesListExpr True genericVariables)- [getTypeScriptType (Proxy :: Proxy $(return (contentsTupleTypeSubstituted genericVariables ci)))]|]+ [getTypeScriptType (Proxy :: Proxy $(return (contentsTupleTypeSubstituted genericVariables ci)))]+ $(tryGetDoc haddockModifier (constructorName ci))|] assembleInterfaceDeclaration members = [|TSInterfaceDeclaration $(TH.stringE interfaceName) $(genericVariablesListExpr True genericVariables)- $(return members)|]+ $(return members)+ $(tryGetDoc haddockModifier (constructorName ci))|] getTSFields :: WriterT [ExtraDeclOrGenericInfo] Q [Exp]- getTSFields = forM (namesAndTypes options genericVariables ci) $ \(nameString, typ) -> do+ getTSFields = forM (namesAndTypes options genericVariables ci) $ \(name, nameString, typ) -> do (fieldTyp, optAsBool) <- lift $ case typ of (AppT (ConT name) t) | name == ''Maybe && not (omitNothingFields options) -> ( , ) <$> [|$(getTypeAsStringExp t) <> " | null"|] <*> getOptionalAsBoolExp t _ -> ( , ) <$> getTypeAsStringExp typ <*> getOptionalAsBoolExp typ- lift $ [| TSField $(return optAsBool) $(TH.stringE nameString) $(return fieldTyp) |] - isSingleRecordConstructor (constructorVariant -> RecordConstructor [x]) = True+ lift [| TSField $(return optAsBool) $(TH.stringE nameString) $(return fieldTyp) $(tryGetDoc haddockModifier name) |]++ isSingleRecordConstructor (constructorVariant -> RecordConstructor [_]) = True isSingleRecordConstructor _ = False -- * Convenience functions
src/Data/Aeson/TypeScript/Transform.hs view
@@ -1,17 +1,8 @@ {-# LANGUAGE CPP #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE MultiWayIf #-}-{-# LANGUAGE ViewPatterns #-} {-# LANGUAGE PolyKinds #-}-{-# LANGUAGE LambdaCase #-} module Data.Aeson.TypeScript.Transform (
src/Data/Aeson/TypeScript/TypeManipulation.hs view
@@ -1,17 +1,8 @@ {-# LANGUAGE CPP #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE TupleSections #-}-{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE MultiWayIf #-}-{-# LANGUAGE ViewPatterns #-} {-# LANGUAGE PolyKinds #-}-{-# LANGUAGE LambdaCase #-} module Data.Aeson.TypeScript.TypeManipulation ( searchForConstraints
src/Data/Aeson/TypeScript/Types.hs view
@@ -1,8 +1,4 @@-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE StandaloneDeriving #-}@@ -10,8 +6,12 @@ module Data.Aeson.TypeScript.Types where import qualified Data.Aeson as A+import Data.Aeson.TypeScript.LegalName+import Data.Function ((&))+import qualified Data.List.NonEmpty as NonEmpty import Data.Proxy import Data.String+import qualified Data.Text as T import Data.Typeable import Language.Haskell.TH @@ -84,16 +84,22 @@ data TSDeclaration = TSInterfaceDeclaration { interfaceName :: String , interfaceGenericVariables :: [String]- , interfaceMembers :: [TSField] }+ , interfaceMembers :: [TSField]+ , interfaceDoc :: Maybe String } | TSTypeAlternatives { typeName :: String , typeGenericVariables :: [String]- , alternativeTypes :: [String]}+ , alternativeTypes :: [String]+ , typeDoc :: Maybe String } | TSRawDeclaration { text :: String } deriving (Show, Eq, Ord) -data TSField = TSField { fieldOptional :: Bool- , fieldName :: String- , fieldType :: String } deriving (Show, Eq, Ord)+data TSField = TSField+ { fieldOptional :: Bool+ , fieldName :: String+ , fieldType :: String+ , fieldDoc :: Maybe String+ -- ^ Haddock documentation for the field, if present+ } deriving (Show, Eq, Ord) newtype TSString a = TSString { unpackTSString :: String } deriving Show @@ -131,12 +137,30 @@ defaultFormattingOptions :: FormattingOptions defaultFormattingOptions = FormattingOptions { numIndentSpaces = 2- , interfaceNameModifier = id- , typeNameModifier = id+ , interfaceNameModifier = defaultNameFormatter+ , typeNameModifier = defaultNameFormatter , exportMode = ExportNone , typeAlternativesFormat = TypeAlias } +-- | The 'defaultNameFormatter' in the 'FormattingOptions' checks to see if+-- the name is a legal TypeScript name. If it is not, then it throws+-- a runtime error.+defaultNameFormatter :: String -> String+defaultNameFormatter str =+ case NonEmpty.nonEmpty str of+ Nothing ->+ error "Name cannot be empty"+ Just nameChars ->+ case checkIllegalNameChars nameChars of+ Just badChars ->+ error $ concat+ [ "The name ", str, " contains illegal characters: ", NonEmpty.toList badChars+ , "\nConsider setting a default name formatter that replaces these characters, or renaming the type."+ ]+ Nothing ->+ str+ -- | Convenience typeclass class you can use to "attach" a set of Aeson encoding options to a type. class HasJSONOptions a where getJSONOptions :: (Proxy a) -> A.Options@@ -178,11 +202,24 @@ data ExtraTypeScriptOptions = ExtraTypeScriptOptions { typeFamiliesToMapToTypeScript :: [Name]+ , keyType :: Maybe String++ -- | Function which is applied to all Haddocks we read in.+ -- By default, just drops leading whitespace from each line.+ , haddockModifier :: String -> String } defaultExtraTypeScriptOptions :: ExtraTypeScriptOptions-defaultExtraTypeScriptOptions = ExtraTypeScriptOptions [] Nothing+defaultExtraTypeScriptOptions = ExtraTypeScriptOptions [] Nothing stripStartEachLine+ where+ stripStartEachLine :: String -> String+ stripStartEachLine s = s+ & T.pack+ & T.splitOn "\n"+ & fmap T.stripStart+ & T.intercalate "\n"+ & T.unpack data ExtraDeclOrGenericInfo = ExtraDecl Exp | ExtraGeneric GenericInfo
src/Data/Aeson/TypeScript/Util.hs view
@@ -1,14 +1,7 @@ {-# LANGUAGE CPP #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE MultiWayIf #-}-{-# LANGUAGE ViewPatterns #-} {-# LANGUAGE PolyKinds #-} module Data.Aeson.TypeScript.Util where@@ -148,14 +141,14 @@ mkInstance = InstanceD #endif -namesAndTypes :: Options -> [(Name, (Suffix, Var))] -> ConstructorInfo -> [(String, Type)]+namesAndTypes :: Options -> [(Name, (Suffix, Var))] -> ConstructorInfo -> [(Name, String, Type)] namesAndTypes options genericVariables ci = case constructorVariant ci of- RecordConstructor names -> zip (fmap ((fieldLabelModifier options) . lastNameComponent') names) (constructorFields ci)+ RecordConstructor names -> zip3 names (fmap ((fieldLabelModifier options) . lastNameComponent') names) (constructorFields ci) _ -> case sumEncoding options of TaggedObject _ contentsFieldName | isConstructorNullary ci -> []- | otherwise -> [(contentsFieldName, contentsTupleTypeSubstituted genericVariables ci)]- _ -> [(constructorNameToUse options ci, contentsTupleTypeSubstituted genericVariables ci)]+ | otherwise -> [(mkName "", contentsFieldName, contentsTupleTypeSubstituted genericVariables ci)]+ _ -> [(constructorName ci, constructorNameToUse options ci, contentsTupleTypeSubstituted genericVariables ci)] constructorNameToUse :: Options -> ConstructorInfo -> String constructorNameToUse options ci = (constructorTagModifier options) $ lastNameComponent' (constructorName ci)@@ -224,3 +217,20 @@ isStarType :: Type -> Maybe Name isStarType (SigT (VarT n) StarT) = Just n isStarType _ = Nothing++nothingOnFail :: Q a -> Q (Maybe a)+nothingOnFail action = recover (return Nothing) (Just <$> action)++tryGetDoc :: (String -> String) -> Name -> Q Exp+tryGetDoc haddockModifier n = do+#if MIN_VERSION_template_haskell(2,18,0)+ maybeDoc <- nothingOnFail (getDoc (DeclDoc n)) >>= \case+ Just (Just doc) -> return $ Just $ Just $ haddockModifier doc+ x -> return x+#else+ let maybeDoc = Nothing+#endif++ case maybeDoc of+ Just (Just doc) -> [|Just $(TH.stringE doc)|]+ _ -> [|Nothing|]
test/Basic.hs view
@@ -1,17 +1,3 @@-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE UndecidableInstances #-}-{-# OPTIONS_GHC -fno-warn-unused-top-binds #-} module Basic (tests) where @@ -36,12 +22,14 @@ describe "tagSingleConstructors and constructorTagModifier" $ do it [i|Works with a normal unit|] $ do (getTypeScriptDeclarations (Proxy :: Proxy Unit1)) `shouldBe` ([- TSTypeAlternatives "Unit1" [] ["IUnit1"]- , TSTypeAlternatives "IUnit1" [] ["void[]"]+ TSTypeAlternatives "Unit1" [] ["IUnit1"] Nothing+ , TSTypeAlternatives "IUnit1" [] ["void[]"] Nothing ]) it [i|Works with a unit with constructorTagModifier|] $ do- (getTypeScriptDeclarations (Proxy :: Proxy Unit2)) `shouldBe` ([])+ (getTypeScriptDeclarations (Proxy :: Proxy Unit2)) `shouldBe` ([+ TSTypeAlternatives "Unit2" [] ["\"foo\""] Nothing+ ]) main :: IO ()
test/ClosedTypeFamilies.hs view
@@ -1,18 +1,5 @@-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeFamilyDependencies #-}-{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE UndecidableInstances #-}-{-# OPTIONS_GHC -fno-warn-unused-top-binds #-} module ClosedTypeFamilies (tests) where @@ -53,38 +40,38 @@ it [i|makes the declaration and types correctly|] $ do (getTypeScriptDeclarationsRecursively (Proxy :: Proxy (Simple T))) `shouldBe` ([ TSInterfaceDeclaration "DeployEnvironment2" [] [- TSField False "\"k8s_env\"" "\"k8s\""- , TSField False "\"single_node_env\"" "\"single\""- , TSField False "T" "void"- ]- , TSTypeAlternatives "ISimple" ["T extends keyof DeployEnvironment2"] ["DeployEnvironment2[T]"]- , TSTypeAlternatives "Simple" ["T extends keyof DeployEnvironment2"] ["ISimple<T>"]+ TSField False "\"k8s_env\"" "\"k8s\"" Nothing+ , TSField False "\"single_node_env\"" "\"single\"" Nothing+ , TSField False "T" "void" Nothing+ ] Nothing+ , TSTypeAlternatives "ISimple" ["T extends keyof DeployEnvironment2"] ["DeployEnvironment2[T]"] Nothing+ , TSTypeAlternatives "Simple" ["T extends keyof DeployEnvironment2"] ["ISimple<T>"] Nothing ]) describe "Complicated Beam-like user type" $ do it [i|makes the declaration and types correctly|] $ do (getTypeScriptDeclarations (Proxy :: Proxy (UserT T Identity))) `shouldBe` ([- TSTypeAlternatives "UserT" ["T extends keyof DeployEnvironment"] ["IUser<T>"]+ TSTypeAlternatives "UserT" ["T extends keyof DeployEnvironment"] ["IUser<T>"] Nothing , TSInterfaceDeclaration "IUser" ["T extends keyof DeployEnvironment"] [- TSField False "_userUsername" "string"- , TSField False "_userCreatedAt" "number"- , TSField False "_userDeployEnvironment" "DeployEnvironment[T]"- ]+ TSField False "_userUsername" "string" Nothing+ , TSField False "_userCreatedAt" "number" Nothing+ , TSField False "_userDeployEnvironment" "DeployEnvironment[T]" Nothing+ ] Nothing ]) it [i|get the declarations recursively|] $ do (getTypeScriptDeclarationsRecursively (Proxy :: Proxy (UserT T Identity))) `shouldBe` ([ TSInterfaceDeclaration "DeployEnvironment" [] [- TSField False "\"k8s_env\"" "\"k8s\""- , TSField False "\"single_node_env\"" "\"single\""- , TSField False "T" "void"- ]+ TSField False "\"k8s_env\"" "\"k8s\"" Nothing+ , TSField False "\"single_node_env\"" "\"single\"" Nothing+ , TSField False "T" "void" Nothing+ ] Nothing , TSInterfaceDeclaration "IUser" ["T extends keyof DeployEnvironment"] [- TSField False "_userUsername" "string"- , TSField False "_userCreatedAt" "number"- , TSField False "_userDeployEnvironment" "DeployEnvironment[T]"- ]- , TSTypeAlternatives "UserT" ["T extends keyof DeployEnvironment"] ["IUser<T>"]+ TSField False "_userUsername" "string" Nothing+ , TSField False "_userCreatedAt" "number" Nothing+ , TSField False "_userDeployEnvironment" "DeployEnvironment[T]" Nothing+ ] Nothing+ , TSTypeAlternatives "UserT" ["T extends keyof DeployEnvironment"] ["IUser<T>"] Nothing ]) main :: IO ()
test/Formatting.hs view
@@ -1,34 +1,79 @@-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE CPP #-} {-# LANGUAGE TypeApplications #-}-{-# LANGUAGE QuasiQuotes #-} module Formatting (tests) where +import Control.Exception import Data.Aeson (defaultOptions) import Data.Aeson.TypeScript.TH-import Data.Aeson.TypeScript.Types import Data.Proxy import Data.String.Interpolate import Test.Hspec -data D = S | F deriving (Eq, Show) +data D = S | F deriving (Eq, Show) $(deriveTypeScript defaultOptions ''D) +data PrimeInType' = PrimeInType+$(deriveTypeScript defaultOptions ''PrimeInType')++data PrimeInConstr = PrimeInConstr'+$(deriveTypeScript defaultOptions ''PrimeInConstr)++data FooBar =+ Foo {+ -- | @no-emit-typescript+ recordString :: String+ , recordInt :: Int+ }+ |+ -- | @no-emit-typescript+ Bar {+ barInt :: Int+ }+$(deriveTypeScript defaultOptions ''FooBar)++data NormalConstructors =+ -- | @no-emit-typescript+ Con1 String+ | Con2 Int+$(deriveTypeScript defaultOptions ''NormalConstructors)+ tests :: Spec-tests = do- describe "Formatting" $- describe "when given a Sum Type" $ do- describe "and the TypeAlias format option is set" $- it "should generate a TS string literal type" $- formatTSDeclarations' defaultFormattingOptions (getTypeScriptDeclarations @D Proxy) `shouldBe`- [i|type D = "S" | "F";|]- describe "and the Enum format option is set" $- it "should generate a TS Enum" $- formatTSDeclarations' (defaultFormattingOptions { typeAlternativesFormat = Enum }) (getTypeScriptDeclarations @D Proxy) `shouldBe`- [i|enum D { S, F }|]- describe "and the EnumWithType format option is set" $- it "should generate a TS Enum with a type declaration" $- formatTSDeclarations' (defaultFormattingOptions { typeAlternativesFormat = EnumWithType }) (getTypeScriptDeclarations @D Proxy) `shouldBe`- [i|enum DEnum { S="S", F="F" }\n\ntype D = keyof typeof DEnum;|]+tests = describe "Formatting" $ do+ describe "when given a Sum Type" $ do+ describe "and the TypeAlias format option is set" $+ it "should generate a TS string literal type" $+ formatTSDeclarations' defaultFormattingOptions (getTypeScriptDeclarations @D Proxy) `shouldBe`+ [i|type D = "S" | "F";|]++ describe "and the Enum format option is set" $+ it "should generate a TS Enum" $+ formatTSDeclarations' (defaultFormattingOptions { typeAlternativesFormat = Enum }) (getTypeScriptDeclarations @D Proxy) `shouldBe`+ [i|enum D { S, F }|]++ describe "and the EnumWithType format option is set" $+ it "should generate a TS Enum with a type declaration" $+ formatTSDeclarations' (defaultFormattingOptions { typeAlternativesFormat = EnumWithType }) (getTypeScriptDeclarations @D Proxy) `shouldBe`+ [i|enum DEnum { S="S", F="F" }\n\ntype D = keyof typeof DEnum;|]++ describe "when the name has an apostrophe" $ do+ describe "in the type" $ do+ it "throws an error" $ do+ evaluate (formatTSDeclarations' defaultFormattingOptions (getTypeScriptDeclarations @PrimeInType' Proxy)) `shouldThrow` anyErrorCall++ describe "in the constructor" $ do+ it "throws an error" $ do+ evaluate (formatTSDeclarations' defaultFormattingOptions (getTypeScriptDeclarations @PrimeInConstr Proxy)) `shouldThrow` anyErrorCall++#if MIN_VERSION_template_haskell(2,18,0)+ describe "when @no-emit-typescript is present" $ do+ it [i|works on records and constructors of record types|] $ do+ formatTSDeclarations' defaultFormattingOptions (getTypeScriptDeclarations @FooBar Proxy) `shouldBe` [i|type FooBar = IFoo;\n\ninterface IFoo {\n tag: "Foo";\n recordInt: number;\n}|]++ it [i|works on normal constructors|] $ do+ formatTSDeclarations' defaultFormattingOptions (getTypeScriptDeclarations @NormalConstructors Proxy) `shouldBe` [i|type NormalConstructors = ICon2;\n\ninterface ICon2 {\n tag: "Con2";\n contents: number;\n}|]+#endif++main :: IO ()+main = hspec tests
test/Generic.hs view
@@ -1,18 +1,3 @@-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeFamilyDependencies #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE UndecidableInstances #-}-{-# OPTIONS_GHC -fno-warn-unused-top-binds #-} module Generic (tests) where @@ -44,38 +29,32 @@ tests = describe "Generic instances" $ do it [i|Complex makes the declaration and types correctly|] $ do (getTypeScriptDeclarationsRecursively (Proxy :: Proxy (Complex String))) `shouldBe` [- TSInterfaceDeclaration {interfaceName = "IProduct", interfaceGenericVariables = ["T"], interfaceMembers = [TSField {fieldOptional = False, fieldName = "tag", fieldType = "\"Product\""},TSField {fieldOptional = False, fieldName = "contents", fieldType = "[number, T]"}]}- ,TSInterfaceDeclaration {interfaceName = "IUnary", interfaceGenericVariables = ["T"], interfaceMembers = [TSField {fieldOptional = False, fieldName = "tag", fieldType = "\"Unary\""},TSField {fieldOptional = False, fieldName = "contents", fieldType = "number"}]}- ,TSTypeAlternatives {typeName = "Complex", typeGenericVariables = ["T"], alternativeTypes = ["IProduct<T>","IUnary<T>"]}+ TSInterfaceDeclaration "IProduct" ["T"] [TSField False "tag" "\"Product\"" Nothing, TSField False "contents" "[number, T]" Nothing] Nothing+ ,TSInterfaceDeclaration "IUnary" ["T"] [TSField False "tag" "\"Unary\"" Nothing, TSField False "contents" "number" Nothing] Nothing+ ,TSTypeAlternatives "Complex" ["T"] ["IProduct<T>","IUnary<T>"] Nothing ] it [i|Complex2 makes the declaration and types correctly|] $ do (getTypeScriptDeclarationsRecursively (Proxy :: Proxy (Complex2 String))) `shouldBe` [- TSTypeAlternatives {typeName = "Complex2", typeGenericVariables = ["T"], alternativeTypes = ["IProduct2<T>"]}- ,TSTypeAlternatives {typeName = "IProduct2", typeGenericVariables = ["T"], alternativeTypes = ["[number, T]"]}+ TSTypeAlternatives "Complex2" ["T"] ["IProduct2<T>"] Nothing+ ,TSTypeAlternatives "IProduct2" ["T"] ["[number, T]"] Nothing ] it [i|Complex3 makes the declaration and types correctly|] $ do (getTypeScriptDeclarationsRecursively (Proxy :: Proxy (Complex3 String))) `shouldBe` [- TSInterfaceDeclaration {interfaceName = "IProduct3", interfaceGenericVariables = ["T"], interfaceMembers = [- TSField {fieldOptional = False, fieldName = "record3", fieldType = "T[]"}- ]}- ,TSTypeAlternatives {typeName = "Complex3", typeGenericVariables = ["T"], alternativeTypes = ["IProduct3<T>"]}+ TSInterfaceDeclaration "IProduct3" ["T"] [TSField False "record3" "T[]" Nothing] Nothing+ ,TSTypeAlternatives "Complex3" ["T"] ["IProduct3<T>"] Nothing ] (getTypeScriptDeclarationsRecursively (Proxy :: Proxy (Complex3 Int))) `shouldBe` [- TSInterfaceDeclaration {interfaceName = "IProduct3", interfaceGenericVariables = ["T"], interfaceMembers = [- TSField {fieldOptional = False, fieldName = "record3", fieldType = "T[]"}- ]}- ,TSTypeAlternatives {typeName = "Complex3", typeGenericVariables = ["T"], alternativeTypes = ["IProduct3<T>"]}+ TSInterfaceDeclaration "IProduct3" ["T"] [TSField False "record3" "T[]" Nothing] Nothing+ ,TSTypeAlternatives "Complex3" ["T"] ["IProduct3<T>"] Nothing ] it [i|Complex4 makes the declaration and types correctly|] $ do (getTypeScriptDeclarationsRecursively (Proxy :: Proxy (Complex4 String))) `shouldBe` [- TSInterfaceDeclaration {interfaceName = "IProduct4", interfaceGenericVariables = ["T"], interfaceMembers = [- TSField {fieldOptional = False, fieldName = "record4", fieldType = "{[k in string]?: T}"}- ]}- ,TSTypeAlternatives {typeName = "Complex4", typeGenericVariables = ["T"], alternativeTypes = ["IProduct4<T>"]}+ TSInterfaceDeclaration "IProduct4" ["T"] [TSField False "record4" "{[k in string]?: T}" Nothing] Nothing+ ,TSTypeAlternatives "Complex4" ["T"] ["IProduct4<T>"] Nothing ] main :: IO ()
+ test/GetDoc.hs view
@@ -0,0 +1,33 @@++module GetDoc (tests) where++import Data.Aeson as A+import Data.Aeson.TypeScript.TH+import Data.Aeson.TypeScript.Types+import Data.Proxy+import Data.String.Interpolate+import Prelude hiding (Double)+import Test.Hspec+++-- | OneField type doc+data OneField =+ -- | OneField constructor doc+ OneField {+ -- | This is a simple string+ simpleString :: String+ }+$(deriveTypeScript A.defaultOptions ''OneField)++tests :: SpecWith ()+tests = describe "getDoc tests" $ do+ it [i|Works with a simple record type|] $ do+ (getTypeScriptDeclarations (Proxy :: Proxy OneField)) `shouldBe` ([+ TSTypeAlternatives "OneField" [] ["IOneField"] (Just "OneField type doc")+ , TSInterfaceDeclaration "IOneField" [] [+ TSField False "simpleString" "string" (Just "This is a simple string")+ ] (Just "OneField constructor doc")+ ])++main :: IO ()+main = hspec tests
test/HigherKind.hs view
@@ -1,17 +1,3 @@-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE UndecidableInstances #-}-{-# OPTIONS_GHC -fno-warn-unused-top-binds #-} module HigherKind (tests) where @@ -50,8 +36,8 @@ describe "Kind * -> *" $ do it [i|makes the declaration and types correctly|] $ do (getTypeScriptDeclarations (Proxy :: Proxy (HigherKind T))) `shouldBe` ([- TSTypeAlternatives "HigherKind" ["T"] ["IHigherKind<T>"],- TSInterfaceDeclaration "IHigherKind" ["T"] [TSField False "higherKindList" "T[]"]+ TSTypeAlternatives "HigherKind" ["T"] ["IHigherKind<T>"] Nothing,+ TSInterfaceDeclaration "IHigherKind" ["T"] [TSField False "higherKindList" "T[]" Nothing] Nothing ]) (getTypeScriptType (Proxy :: Proxy (HigherKind Int))) `shouldBe` "HigherKind<number>"@@ -59,23 +45,23 @@ it [i|works when referenced in another type|] $ do (getTypeScriptDeclarations (Proxy :: Proxy Foo)) `shouldBe` ([- TSTypeAlternatives "Foo" [] ["IFoo"],- TSInterfaceDeclaration "IFoo" [] [TSField False "fooString" "string"- , TSField False "fooHigherKindReference" "HigherKind<string>"]+ TSTypeAlternatives "Foo" [] ["IFoo"] Nothing,+ TSInterfaceDeclaration "IFoo" [] [TSField False "fooString" "string" Nothing+ , TSField False "fooHigherKindReference" "HigherKind<string>" Nothing] Nothing ]) it [i|works with an interface inside|] $ do (getTypeScriptDeclarations (Proxy :: Proxy (HigherKindWithUnary T))) `shouldBe` ([- TSTypeAlternatives "HigherKindWithUnary" ["T"] ["IUnary<T>"],- TSTypeAlternatives "IUnary" ["T"] ["number"]+ TSTypeAlternatives "HigherKindWithUnary" ["T"] ["IUnary<T>"] Nothing,+ TSTypeAlternatives "IUnary" ["T"] ["number"] Nothing ]) describe "Kind * -> * -> *" $ do it [i|makes the declaration and type correctly|] $ do (getTypeScriptDeclarations (Proxy :: Proxy (DoubleHigherKind T1 T2))) `shouldBe` ([- TSTypeAlternatives "DoubleHigherKind" ["T1","T2"] ["IDoubleHigherKind<T1, T2>"],- TSInterfaceDeclaration "IDoubleHigherKind" ["T1","T2"] [TSField False "someList" "T2[]"- , TSField False "higherKindThing" "HigherKind<T1>"]+ TSTypeAlternatives "DoubleHigherKind" ["T1","T2"] ["IDoubleHigherKind<T1, T2>"] Nothing,+ TSInterfaceDeclaration "IDoubleHigherKind" ["T1","T2"] [TSField False "someList" "T2[]" Nothing+ , TSField False "higherKindThing" "HigherKind<T1>" Nothing] Nothing ]) (getTypeScriptType (Proxy :: Proxy (DoubleHigherKind Int String))) `shouldBe` "DoubleHigherKind<number, string>"
+ test/LegalNameSpec.hs view
@@ -0,0 +1,24 @@++module LegalNameSpec where++import Data.Aeson.TypeScript.LegalName+import Data.List.NonEmpty (NonEmpty (..))+import Test.Hspec++tests :: Spec+tests = describe "Data.Aeson.TypeScript.LegalName" $ do+ describe "checkIllegalNameChars" $ do+ describe "legal Haskell names" $ do+ it "allows an uppercase letter" $ do+ checkIllegalNameChars ('A' :| [])+ `shouldBe` Nothing+ it "allows an underscore" $ do+ checkIllegalNameChars ('_' :| "asdf")+ `shouldBe` Nothing+ it "reports that ' is illegal" $ do+ checkIllegalNameChars ('F' :| "oo'")+ `shouldBe` Just ('\'' :| [])+ describe "illegal Haskell names" $ do+ it "allows a $" $ do+ checkIllegalNameChars ('$' :| "asdf")+ `shouldBe` Nothing
test/NoOmitNothingFields.hs view
@@ -1,15 +1,3 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE MonoLocalBinds #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TemplateHaskell #-}-{-# OPTIONS_GHC -fno-warn-orphans #-} module NoOmitNothingFields (allTests) where @@ -27,17 +15,7 @@ it "encodes as expected" $ do let decls = getTypeScriptDeclarations (Proxy :: Proxy Optional) - decls `shouldBe` [TSTypeAlternatives {- typeName = "Optional"- , typeGenericVariables = []- , alternativeTypes = ["IOptional"]- }- , TSInterfaceDeclaration {- interfaceName = "IOptional"- , interfaceGenericVariables = []- , interfaceMembers = [TSField {fieldOptional = False- , fieldName = "optionalInt"- , fieldType = "number | null"}]- }]+ decls `shouldBe` [TSTypeAlternatives "Optional" [] ["IOptional"] Nothing+ , TSInterfaceDeclaration "IOptional" [] [TSField False "optionalInt" "number | null" Nothing] Nothing] tests
test/ObjectWithSingleFieldNoTagSingleConstructors.hs view
@@ -1,15 +1,3 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE MonoLocalBinds #-}-{-# OPTIONS_GHC -fno-warn-orphans #-} module ObjectWithSingleFieldNoTagSingleConstructors (main, tests) where
test/ObjectWithSingleFieldTagSingleConstructors.hs view
@@ -1,15 +1,3 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE MonoLocalBinds #-}-{-# OPTIONS_GHC -fno-warn-orphans #-} module ObjectWithSingleFieldTagSingleConstructors (main, tests) where
test/OmitNothingFields.hs view
@@ -1,15 +1,3 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE MonoLocalBinds #-}-{-# OPTIONS_GHC -fno-warn-orphans #-} module OmitNothingFields (main, tests) where @@ -31,10 +19,9 @@ interfaceName = "Optional" , interfaceGenericVariables = [] , interfaceMembers = [- TSField {fieldOptional = True- , fieldName = "optionalInt"- , fieldType = "number"}+ TSField True "optionalInt" "number" Nothing ]+ , interfaceDoc = Nothing }] tests
test/OpenTypeFamilies.hs view
@@ -1,18 +1,5 @@-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeFamilyDependencies #-}-{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE UndecidableInstances #-}-{-# OPTIONS_GHC -fno-warn-unused-top-binds #-} module OpenTypeFamilies (tests) where @@ -53,38 +40,38 @@ it [i|makes the declaration and types correctly|] $ do (getTypeScriptDeclarationsRecursively (Proxy :: Proxy (Simple T))) `shouldBe` ([ TSInterfaceDeclaration "DeployEnvironment2" [] [- TSField False "\"single_node_env\"" "\"single\""- , TSField False "\"k8s_env\"" "\"k8s\""- , TSField False "T" "void"- ]- , TSTypeAlternatives "ISimple" ["T extends keyof DeployEnvironment2"] ["DeployEnvironment2[T]"]- , TSTypeAlternatives "Simple" ["T extends keyof DeployEnvironment2"] ["ISimple<T>"]+ TSField False "\"single_node_env\"" "\"single\"" Nothing+ , TSField False "\"k8s_env\"" "\"k8s\"" Nothing+ , TSField False "T" "void" Nothing+ ] Nothing+ , TSTypeAlternatives "ISimple" ["T extends keyof DeployEnvironment2"] ["DeployEnvironment2[T]"] Nothing+ , TSTypeAlternatives "Simple" ["T extends keyof DeployEnvironment2"] ["ISimple<T>"] Nothing ]) describe "Complicated Beam-like user type" $ do it [i|makes the declaration and types correctly|] $ do (getTypeScriptDeclarations (Proxy :: Proxy (UserT T Identity))) `shouldBe` ([- TSTypeAlternatives "UserT" ["T extends keyof DeployEnvironment"] ["IUser<T>"]+ TSTypeAlternatives "UserT" ["T extends keyof DeployEnvironment"] ["IUser<T>"] Nothing , TSInterfaceDeclaration "IUser" ["T extends keyof DeployEnvironment"] [- TSField False "_userUsername" "string"- , TSField False "_userCreatedAt" "number"- , TSField False "_userDeployEnvironment" "DeployEnvironment[T]"- ]+ TSField False "_userUsername" "string" Nothing+ , TSField False "_userCreatedAt" "number" Nothing+ , TSField False "_userDeployEnvironment" "DeployEnvironment[T]" Nothing+ ] Nothing ]) it [i|get the declarations recursively|] $ do (getTypeScriptDeclarationsRecursively (Proxy :: Proxy (UserT T Identity))) `shouldBe` ([ TSInterfaceDeclaration "DeployEnvironment" [] [- TSField False "\"single_node_env\"" "\"single\""- , TSField False "\"k8s_env\"" "\"k8s\""- , TSField False "T" "void"- ]+ TSField False "\"single_node_env\"" "\"single\"" Nothing+ , TSField False "\"k8s_env\"" "\"k8s\"" Nothing+ , TSField False "T" "void" Nothing+ ] Nothing , TSInterfaceDeclaration "IUser" ["T extends keyof DeployEnvironment"] [- TSField False "_userUsername" "string"- , TSField False "_userCreatedAt" "number"- , TSField False "_userDeployEnvironment" "DeployEnvironment[T]"- ]- , TSTypeAlternatives "UserT" ["T extends keyof DeployEnvironment"] ["IUser<T>"]+ TSField False "_userUsername" "string" Nothing+ , TSField False "_userCreatedAt" "number" Nothing+ , TSField False "_userDeployEnvironment" "DeployEnvironment[T]" Nothing+ ] Nothing+ , TSTypeAlternatives "UserT" ["T extends keyof DeployEnvironment"] ["IUser<T>"] Nothing ]) main :: IO ()
test/Spec.hs view
@@ -1,41 +1,50 @@+{-# LANGUAGE CPP #-} module Main where import Test.Hspec +import qualified Basic import qualified Formatting import qualified Generic+import qualified GetDoc import qualified HigherKind import qualified ClosedTypeFamilies +import qualified LegalNameSpec+import qualified NoOmitNothingFields import qualified ObjectWithSingleFieldNoTagSingleConstructors import qualified ObjectWithSingleFieldTagSingleConstructors+import qualified OmitNothingFields import qualified TaggedObjectNoTagSingleConstructors import qualified TaggedObjectTagSingleConstructors import qualified TwoElemArrayNoTagSingleConstructors import qualified TwoElemArrayTagSingleConstructors import qualified UntaggedNoTagSingleConstructors import qualified UntaggedTagSingleConstructors-import qualified OmitNothingFields-import qualified NoOmitNothingFields import qualified UnwrapUnaryRecords main :: IO ()-main = hspec $ do+main = hspec $ parallel $ do+ Basic.tests+ ClosedTypeFamilies.tests Formatting.tests Generic.tests+#if MIN_VERSION_template_haskell(2,18,0)+ GetDoc.tests+#endif HigherKind.tests- ClosedTypeFamilies.tests - ObjectWithSingleFieldTagSingleConstructors.tests+ LegalNameSpec.tests+ NoOmitNothingFields.allTests ObjectWithSingleFieldNoTagSingleConstructors.tests- TaggedObjectTagSingleConstructors.tests+ ObjectWithSingleFieldTagSingleConstructors.tests+ OmitNothingFields.tests TaggedObjectNoTagSingleConstructors.tests- TwoElemArrayTagSingleConstructors.tests+ TaggedObjectTagSingleConstructors.tests TwoElemArrayNoTagSingleConstructors.tests- UntaggedTagSingleConstructors.tests+ TwoElemArrayTagSingleConstructors.tests UntaggedNoTagSingleConstructors.tests- OmitNothingFields.tests- NoOmitNothingFields.allTests+ UntaggedTagSingleConstructors.tests UnwrapUnaryRecords.allTests
test/TaggedObjectNoTagSingleConstructors.hs view
@@ -1,15 +1,3 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE MonoLocalBinds #-}-{-# OPTIONS_GHC -fno-warn-orphans #-} module TaggedObjectNoTagSingleConstructors (main, tests) where
test/TaggedObjectTagSingleConstructors.hs view
@@ -1,15 +1,3 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE MonoLocalBinds #-}-{-# OPTIONS_GHC -fno-warn-orphans #-} module TaggedObjectTagSingleConstructors (main, tests) where
test/TestBoilerplate.hs view
@@ -1,16 +1,4 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-}-{-# OPTIONS_GHC -fno-warn-orphans #-} module TestBoilerplate where
test/TwoElemArrayNoTagSingleConstructors.hs view
@@ -1,15 +1,3 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE MonoLocalBinds #-}-{-# OPTIONS_GHC -fno-warn-orphans #-} module TwoElemArrayNoTagSingleConstructors (main, tests) where
test/TwoElemArrayTagSingleConstructors.hs view
@@ -1,15 +1,3 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE MonoLocalBinds #-}-{-# OPTIONS_GHC -fno-warn-orphans #-} module TwoElemArrayTagSingleConstructors (main, tests) where
test/UntaggedNoTagSingleConstructors.hs view
@@ -1,15 +1,4 @@ {-# LANGUAGE CPP #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE MonoLocalBinds #-}-{-# OPTIONS_GHC -fno-warn-orphans #-} module UntaggedNoTagSingleConstructors (main, tests) where
test/UntaggedTagSingleConstructors.hs view
@@ -1,15 +1,4 @@ {-# LANGUAGE CPP #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE MonoLocalBinds #-}-{-# OPTIONS_GHC -fno-warn-orphans #-} module UntaggedTagSingleConstructors (main, tests) where
test/UnwrapUnaryRecords.hs view
@@ -1,15 +1,4 @@ {-# LANGUAGE CPP #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE NamedFieldPuns #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE ConstraintKinds #-}-{-# LANGUAGE MonoLocalBinds #-}-{-# OPTIONS_GHC -fno-warn-orphans #-} module UnwrapUnaryRecords (allTests) where @@ -30,8 +19,8 @@ let decls = getTypeScriptDeclarations (Proxy :: Proxy OneField) decls `shouldBe` [- TSTypeAlternatives {typeName = "OneField", typeGenericVariables = [], alternativeTypes = ["IOneField"]}- ,TSTypeAlternatives {typeName = "IOneField", typeGenericVariables = [], alternativeTypes = ["string"]}+ TSTypeAlternatives "OneField" [] ["IOneField"] Nothing+ ,TSTypeAlternatives "IOneField" [] ["string"] Nothing ] tests@@ -42,5 +31,5 @@ allTests = tests #endif --- main :: IO ()--- main = hspec allTests+main :: IO ()+main = hspec allTests
test/Util.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE CPP, QuasiQuotes, OverloadedStrings, TemplateHaskell, RecordWildCards, ScopedTypeVariables, NamedFieldPuns, LambdaCase #-}+{-# LANGUAGE CPP #-} module Util where @@ -14,7 +14,8 @@ import System.Exit import System.FilePath import System.IO.Temp-import System.Process+import System.Process hiding (cwd)+ npmInstallScript, yarnInstallScript, localTSC :: String npmInstallScript = "test/assets/npm_install.sh"
test/Util/Aeson.hs view
@@ -3,8 +3,10 @@ module Util.Aeson where #if MIN_VERSION_aeson(2,0,0)+import qualified Data.Aeson.Key as K import qualified Data.Aeson.KeyMap as KM +aesonFromList :: [(K.Key, v)] -> KM.KeyMap v aesonFromList = KM.fromList #else import Data.HashMap.Strict as HM