From 431d8543ae997f155ee0a01768be4f78b605d5be Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Wed, 1 Mar 2023 00:27:38 -0800 Subject: [PATCH 01/76] Get docs on interface names --- src/Data/Aeson/TypeScript/Formatting.hs | 12 +++++++++--- src/Data/Aeson/TypeScript/Instances.hs | 4 ++-- src/Data/Aeson/TypeScript/TH.hs | 23 +++++++++++++++-------- src/Data/Aeson/TypeScript/Types.hs | 3 ++- 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/Data/Aeson/TypeScript/Formatting.hs b/src/Data/Aeson/TypeScript/Formatting.hs index eec3e7d..2869f2c 100644 --- a/src/Data/Aeson/TypeScript/Formatting.hs +++ b/src/Data/Aeson/TypeScript/Formatting.hs @@ -30,10 +30,15 @@ formatTSDeclaration (FormattingOptions {..}) (TSTypeAlternatives name genericVar 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 members maybeDoc) = + docPrefix <> [i|#{exportPrefix exportMode}interface #{modifiedInterfaceName}#{getGenericBrackets genericVariables} { #{ls} }|] where + docPrefix = case maybeDoc of + Nothing -> "" + Just doc | '\n' `L.elem` doc -> "/* " <> (deleteLeadingWhitespace doc) <> " */\n" + Just doc -> "// " <> (deleteLeadingWhitespace doc) <> "\n" + ls = T.intercalate "\n" $ [indentTo numIndentSpaces (T.pack (formatTSField member <> ";")) | member <- members] modifiedInterfaceName = (\(li, name) -> li <> interfaceNameModifier name) . splitAt 1 $ interfaceName @@ -73,7 +78,8 @@ formatTSField (TSField optional name typ maybeDoc) = docPrefix <> [i|#{name}#{if Just doc | '\n' `L.elem` doc -> "/* " <> (deleteLeadingWhitespace doc) <> " */\n" Just doc -> "// " <> (deleteLeadingWhitespace doc) <> "\n" - deleteLeadingWhitespace = L.dropWhile (== ' ') +deleteLeadingWhitespace :: String -> String +deleteLeadingWhitespace = L.dropWhile (== ' ') getGenericBrackets :: [String] -> String getGenericBrackets [] = "" diff --git a/src/Data/Aeson/TypeScript/Instances.hs b/src/Data/Aeson/TypeScript/Instances.hs index ee566be..6d50c5b 100644 --- a/src/Data/Aeson/TypeScript/Instances.hs +++ b/src/Data/Aeson/TypeScript/Instances.hs @@ -90,8 +90,8 @@ instance {-# OVERLAPPING #-} TypeScript [Char] where 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", "Right"] - , TSInterfaceDeclaration "Left" ["T"] [TSField False "Left" "T" Nothing] - , TSInterfaceDeclaration "Right" ["T"] [TSField False "Right" "T" 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)) diff --git a/src/Data/Aeson/TypeScript/TH.hs b/src/Data/Aeson/TypeScript/TH.hs index 73c764e..773e634 100644 --- a/src/Data/Aeson/TypeScript/TH.hs +++ b/src/Data/Aeson/TypeScript/TH.hs @@ -314,7 +314,20 @@ handleConstructor options (DatatypeInfo {..}) genericVariables ci = do assembleInterfaceDeclaration members = [|TSInterfaceDeclaration $(TH.stringE interfaceName) $(genericVariablesListExpr True genericVariables) - $(return members)|] + $(return members) + $(tryGetDoc (constructorName ci))|] + + tryGetDoc :: Name -> Q Exp + tryGetDoc n = do +#if MIN_VERSION_template_haskell(2,18,0) + maybeDoc <- nothingOnFail $ getDoc (DeclDoc n) +#else + let maybeDoc = Nothing +#endif + + case maybeDoc of + Just (Just doc) -> [|Just $(TH.stringE doc)|] + _ -> [|Nothing|] getTSFields :: WriterT [ExtraDeclOrGenericInfo] Q [Exp] getTSFields = forM (namesAndTypes options genericVariables ci) $ \(name, nameString, typ) -> do @@ -323,13 +336,7 @@ handleConstructor options (DatatypeInfo {..}) genericVariables ci = do ( , ) <$> [|$(getTypeAsStringExp t) <> " | null"|] <*> getOptionalAsBoolExp t _ -> ( , ) <$> getTypeAsStringExp typ <*> getOptionalAsBoolExp typ -#if MIN_VERSION_template_haskell(2,18,0) - maybeDoc <- lift $ nothingOnFail $ getDoc (DeclDoc name) -#else - let maybeDoc = Nothing -#endif - - lift [| TSField $(return optAsBool) $(TH.stringE nameString) $(return fieldTyp) $(case maybeDoc of Just (Just doc) -> [|Just $(TH.stringE doc)|]; _ -> [|Nothing|]) |] + lift [| TSField $(return optAsBool) $(TH.stringE nameString) $(return fieldTyp) $(tryGetDoc name) |] isSingleRecordConstructor (constructorVariant -> RecordConstructor [_]) = True isSingleRecordConstructor _ = False diff --git a/src/Data/Aeson/TypeScript/Types.hs b/src/Data/Aeson/TypeScript/Types.hs index c42af91..ec23d1c 100644 --- a/src/Data/Aeson/TypeScript/Types.hs +++ b/src/Data/Aeson/TypeScript/Types.hs @@ -86,7 +86,8 @@ instance Show TSType where data TSDeclaration = TSInterfaceDeclaration { interfaceName :: String , interfaceGenericVariables :: [String] - , interfaceMembers :: [TSField] } + , interfaceMembers :: [TSField] + , interfaceDoc :: Maybe String } | TSTypeAlternatives { typeName :: String , typeGenericVariables :: [String] , alternativeTypes :: [String]} From 856370007867e013d2499c5a6570ffa917f47a9c Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Wed, 1 Mar 2023 00:37:08 -0800 Subject: [PATCH 02/76] Update tests to use docs on interface names --- src/Data/Aeson/TypeScript/Lookup.hs | 2 +- test/ClosedTypeFamilies.hs | 8 ++++---- test/Generic.hs | 16 +++++----------- test/HigherKind.hs | 6 +++--- test/NoOmitNothingFields.hs | 1 + test/OmitNothingFields.hs | 1 + test/OpenTypeFamilies.hs | 8 ++++---- 7 files changed, 19 insertions(+), 23 deletions(-) diff --git a/src/Data/Aeson/TypeScript/Lookup.hs b/src/Data/Aeson/TypeScript/Lookup.hs index 8c245c8..ef0e9a8 100644 --- a/src/Data/Aeson/TypeScript/Lookup.hs +++ b/src/Data/Aeson/TypeScript/Lookup.hs @@ -55,7 +55,7 @@ getClosedTypeFamilyInterfaceDecl name eqns = do #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 diff --git a/test/ClosedTypeFamilies.hs b/test/ClosedTypeFamilies.hs index d8381db..606a0cf 100644 --- a/test/ClosedTypeFamilies.hs +++ b/test/ClosedTypeFamilies.hs @@ -43,7 +43,7 @@ tests = describe "Closed type families" $ do 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]"] , TSTypeAlternatives "Simple" ["T extends keyof DeployEnvironment2"] ["ISimple"] ]) @@ -56,7 +56,7 @@ tests = describe "Closed type families" $ do TSField False "_userUsername" "string" Nothing , TSField False "_userCreatedAt" "number" Nothing , TSField False "_userDeployEnvironment" "DeployEnvironment[T]" Nothing - ] + ] Nothing ]) it [i|get the declarations recursively|] $ do @@ -65,12 +65,12 @@ tests = describe "Closed type families" $ do 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" Nothing , TSField False "_userCreatedAt" "number" Nothing , TSField False "_userDeployEnvironment" "DeployEnvironment[T]" Nothing - ] + ] Nothing , TSTypeAlternatives "UserT" ["T extends keyof DeployEnvironment"] ["IUser"] ]) diff --git a/test/Generic.hs b/test/Generic.hs index 889ac8d..fa36a3e 100644 --- a/test/Generic.hs +++ b/test/Generic.hs @@ -29,8 +29,8 @@ tests :: SpecWith () 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 False "tag" "\"Product\"" Nothing, TSField False "contents" "[number, T]" Nothing]} - ,TSInterfaceDeclaration {interfaceName = "IUnary", interfaceGenericVariables = ["T"], interfaceMembers = [TSField False "tag" "\"Unary\"" Nothing, TSField False "contents" "number" Nothing]} + 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 {typeName = "Complex", typeGenericVariables = ["T"], alternativeTypes = ["IProduct","IUnary"]} ] @@ -42,24 +42,18 @@ tests = describe "Generic instances" $ do it [i|Complex3 makes the declaration and types correctly|] $ do (getTypeScriptDeclarationsRecursively (Proxy :: Proxy (Complex3 String))) `shouldBe` [ - TSInterfaceDeclaration {interfaceName = "IProduct3", interfaceGenericVariables = ["T"], interfaceMembers = [ - TSField False "record3" "T[]" Nothing - ]} + TSInterfaceDeclaration "IProduct3" ["T"] [TSField False "record3" "T[]" Nothing] Nothing ,TSTypeAlternatives {typeName = "Complex3", typeGenericVariables = ["T"], alternativeTypes = ["IProduct3"]} ] (getTypeScriptDeclarationsRecursively (Proxy :: Proxy (Complex3 Int))) `shouldBe` [ - TSInterfaceDeclaration {interfaceName = "IProduct3", interfaceGenericVariables = ["T"], interfaceMembers = [ - TSField False "record3" "T[]" Nothing - ]} + TSInterfaceDeclaration "IProduct3" ["T"] [TSField False "record3" "T[]" Nothing] Nothing ,TSTypeAlternatives {typeName = "Complex3", typeGenericVariables = ["T"], alternativeTypes = ["IProduct3"]} ] it [i|Complex4 makes the declaration and types correctly|] $ do (getTypeScriptDeclarationsRecursively (Proxy :: Proxy (Complex4 String))) `shouldBe` [ - TSInterfaceDeclaration {interfaceName = "IProduct4", interfaceGenericVariables = ["T"], interfaceMembers = [ - TSField False "record4" "{[k in string]?: T}" Nothing - ]} + TSInterfaceDeclaration "IProduct4" ["T"] [TSField False "record4" "{[k in string]?: T}" Nothing] Nothing ,TSTypeAlternatives {typeName = "Complex4", typeGenericVariables = ["T"], alternativeTypes = ["IProduct4"]} ] diff --git a/test/HigherKind.hs b/test/HigherKind.hs index b272ecc..00aeac5 100644 --- a/test/HigherKind.hs +++ b/test/HigherKind.hs @@ -37,7 +37,7 @@ tests = describe "Higher kinds" $ do it [i|makes the declaration and types correctly|] $ do (getTypeScriptDeclarations (Proxy :: Proxy (HigherKind T))) `shouldBe` ([ TSTypeAlternatives "HigherKind" ["T"] ["IHigherKind"], - TSInterfaceDeclaration "IHigherKind" ["T"] [TSField False "higherKindList" "T[]" Nothing] + TSInterfaceDeclaration "IHigherKind" ["T"] [TSField False "higherKindList" "T[]" Nothing] Nothing ]) (getTypeScriptType (Proxy :: Proxy (HigherKind Int))) `shouldBe` "HigherKind" @@ -47,7 +47,7 @@ tests = describe "Higher kinds" $ do (getTypeScriptDeclarations (Proxy :: Proxy Foo)) `shouldBe` ([ TSTypeAlternatives "Foo" [] ["IFoo"], TSInterfaceDeclaration "IFoo" [] [TSField False "fooString" "string" Nothing - , TSField False "fooHigherKindReference" "HigherKind" Nothing] + , TSField False "fooHigherKindReference" "HigherKind" Nothing] Nothing ]) it [i|works with an interface inside|] $ do @@ -61,7 +61,7 @@ tests = describe "Higher kinds" $ do (getTypeScriptDeclarations (Proxy :: Proxy (DoubleHigherKind T1 T2))) `shouldBe` ([ TSTypeAlternatives "DoubleHigherKind" ["T1","T2"] ["IDoubleHigherKind"], TSInterfaceDeclaration "IDoubleHigherKind" ["T1","T2"] [TSField False "someList" "T2[]" Nothing - , TSField False "higherKindThing" "HigherKind" Nothing] + , TSField False "higherKindThing" "HigherKind" Nothing] Nothing ]) (getTypeScriptType (Proxy :: Proxy (DoubleHigherKind Int String))) `shouldBe` "DoubleHigherKind" diff --git a/test/NoOmitNothingFields.hs b/test/NoOmitNothingFields.hs index 4f5da71..36c5d39 100644 --- a/test/NoOmitNothingFields.hs +++ b/test/NoOmitNothingFields.hs @@ -24,6 +24,7 @@ allTests = describe "NoOmitNothingFields" $ do interfaceName = "IOptional" , interfaceGenericVariables = [] , interfaceMembers = [TSField False "optionalInt" "number | null" Nothing] + , interfaceDoc = Nothing }] tests diff --git a/test/OmitNothingFields.hs b/test/OmitNothingFields.hs index 9993e3b..360f2a1 100644 --- a/test/OmitNothingFields.hs +++ b/test/OmitNothingFields.hs @@ -21,6 +21,7 @@ main = hspec $ describe "OmitNothingFields" $ do , interfaceMembers = [ TSField True "optionalInt" "number" Nothing ] + , interfaceDoc = Nothing }] tests diff --git a/test/OpenTypeFamilies.hs b/test/OpenTypeFamilies.hs index f668757..1b1aeaa 100644 --- a/test/OpenTypeFamilies.hs +++ b/test/OpenTypeFamilies.hs @@ -43,7 +43,7 @@ tests = describe "Open type families" $ do 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]"] , TSTypeAlternatives "Simple" ["T extends keyof DeployEnvironment2"] ["ISimple"] ]) @@ -56,7 +56,7 @@ tests = describe "Open type families" $ do TSField False "_userUsername" "string" Nothing , TSField False "_userCreatedAt" "number" Nothing , TSField False "_userDeployEnvironment" "DeployEnvironment[T]" Nothing - ] + ] Nothing ]) it [i|get the declarations recursively|] $ do @@ -65,12 +65,12 @@ tests = describe "Open type families" $ do 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" Nothing , TSField False "_userCreatedAt" "number" Nothing , TSField False "_userDeployEnvironment" "DeployEnvironment[T]" Nothing - ] + ] Nothing , TSTypeAlternatives "UserT" ["T extends keyof DeployEnvironment"] ["IUser"] ]) From 01ec42f268ff0c2e4a48fb55cac5e78324777aed Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Wed, 1 Mar 2023 00:37:16 -0800 Subject: [PATCH 03/76] Fix warning in test/Util.hs --- test/Util.hs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/Util.hs b/test/Util.hs index 180f657..88a088d 100644 --- a/test/Util.hs +++ b/test/Util.hs @@ -14,7 +14,8 @@ import System.Environment 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" From 8cba46725d7761ef7b061652b57290bf5b6317f7 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Wed, 1 Mar 2023 00:47:23 -0800 Subject: [PATCH 04/76] Add haddockModifier to ExtraTypeScriptOptions --- src/Data/Aeson/TypeScript/Formatting.hs | 21 +++++++-------------- src/Data/Aeson/TypeScript/TH.hs | 10 ++++++---- src/Data/Aeson/TypeScript/Types.hs | 11 ++++++++++- test/GetDoc.hs | 16 +++++++++------- 4 files changed, 32 insertions(+), 26 deletions(-) diff --git a/src/Data/Aeson/TypeScript/Formatting.hs b/src/Data/Aeson/TypeScript/Formatting.hs index 2869f2c..7990790 100644 --- a/src/Data/Aeson/TypeScript/Formatting.hs +++ b/src/Data/Aeson/TypeScript/Formatting.hs @@ -31,14 +31,9 @@ formatTSDeclaration (FormattingOptions {..}) (TSTypeAlternatives name genericVar toEnumName = T.replace "\"" "" formatTSDeclaration (FormattingOptions {..}) (TSInterfaceDeclaration interfaceName genericVariables members maybeDoc) = - docPrefix <> [i|#{exportPrefix exportMode}interface #{modifiedInterfaceName}#{getGenericBrackets genericVariables} { + makeDocPrefix maybeDoc <> [i|#{exportPrefix exportMode}interface #{modifiedInterfaceName}#{getGenericBrackets genericVariables} { #{ls} }|] where - docPrefix = case maybeDoc of - Nothing -> "" - Just doc | '\n' `L.elem` doc -> "/* " <> (deleteLeadingWhitespace doc) <> " */\n" - Just doc -> "// " <> (deleteLeadingWhitespace doc) <> "\n" - ls = T.intercalate "\n" $ [indentTo numIndentSpaces (T.pack (formatTSField member <> ";")) | member <- members] modifiedInterfaceName = (\(li, name) -> li <> interfaceNameModifier name) . splitAt 1 $ interfaceName @@ -71,15 +66,13 @@ validateFormattingOptions options@FormattingOptions{..} decls isPlainSumType ds = (not . any isInterface $ ds) && length ds == 1 formatTSField :: TSField -> String -formatTSField (TSField optional name typ maybeDoc) = docPrefix <> [i|#{name}#{if optional then ("?" :: String) else ""}: #{typ}|] - where - docPrefix = case maybeDoc of - Nothing -> "" - Just doc | '\n' `L.elem` doc -> "/* " <> (deleteLeadingWhitespace doc) <> " */\n" - Just doc -> "// " <> (deleteLeadingWhitespace doc) <> "\n" +formatTSField (TSField optional name typ maybeDoc) = makeDocPrefix maybeDoc <> [i|#{name}#{if optional then ("?" :: String) else ""}: #{typ}|] -deleteLeadingWhitespace :: String -> String -deleteLeadingWhitespace = L.dropWhile (== ' ') +makeDocPrefix :: Maybe String -> String +makeDocPrefix maybeDoc = case maybeDoc of + Nothing -> "" + Just doc | '\n' `L.elem` doc -> "/* " <> doc <> " */\n" + Just doc -> "// " <> doc <> "\n" getGenericBrackets :: [String] -> String getGenericBrackets [] = "" diff --git a/src/Data/Aeson/TypeScript/TH.hs b/src/Data/Aeson/TypeScript/TH.hs index 773e634..0207026 100644 --- a/src/Data/Aeson/TypeScript/TH.hs +++ b/src/Data/Aeson/TypeScript/TH.hs @@ -217,7 +217,7 @@ deriveTypeScript' options name extraOptions = do 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)|] @@ -244,8 +244,8 @@ deriveTypeScript' options name extraOptions = do 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 @@ -320,7 +320,9 @@ handleConstructor options (DatatypeInfo {..}) genericVariables ci = do tryGetDoc :: Name -> Q Exp tryGetDoc n = do #if MIN_VERSION_template_haskell(2,18,0) - maybeDoc <- nothingOnFail $ getDoc (DeclDoc n) + maybeDoc <- nothingOnFail (getDoc (DeclDoc n)) >>= \case + Just (Just doc) -> return $ Just $ Just $ haddockModifier doc + x -> return x #else let maybeDoc = Nothing #endif diff --git a/src/Data/Aeson/TypeScript/Types.hs b/src/Data/Aeson/TypeScript/Types.hs index ec23d1c..4b98999 100644 --- a/src/Data/Aeson/TypeScript/Types.hs +++ b/src/Data/Aeson/TypeScript/Types.hs @@ -11,6 +11,7 @@ module Data.Aeson.TypeScript.Types where import qualified Data.Aeson as A import Data.Aeson.TypeScript.LegalName +import qualified Data.List as L import qualified Data.List.NonEmpty as NonEmpty import Data.Proxy import Data.String @@ -203,11 +204,19 @@ allStarConstructors'' = ["T1", "T2", "T3", "T4", "T5", "T6", "T7", "T8", "T9", " data ExtraTypeScriptOptions = ExtraTypeScriptOptions { typeFamiliesToMapToTypeScript :: [Name] + , keyType :: Maybe String + + -- | Function which is applied to all Haddocks we read in. + -- By default, just drops leading whitespace. + , haddockModifier :: String -> String } defaultExtraTypeScriptOptions :: ExtraTypeScriptOptions -defaultExtraTypeScriptOptions = ExtraTypeScriptOptions [] Nothing +defaultExtraTypeScriptOptions = ExtraTypeScriptOptions [] Nothing deleteLeadingWhitespace + where + deleteLeadingWhitespace :: String -> String + deleteLeadingWhitespace = L.dropWhile (== ' ') data ExtraDeclOrGenericInfo = ExtraDecl Exp | ExtraGeneric GenericInfo diff --git a/test/GetDoc.hs b/test/GetDoc.hs index 0f91f82..8ee8f80 100644 --- a/test/GetDoc.hs +++ b/test/GetDoc.hs @@ -10,11 +10,13 @@ import Prelude hiding (Double) import Test.Hspec --- | OneField is a type with a single field -data OneField = OneField { - -- | This is a simple string - simpleString :: String - } +-- | OneField type doc +data OneField = + -- | OneField constructor doc + OneField { + -- | This is a simple string + simpleString :: String + } $(deriveTypeScript A.defaultOptions ''OneField) tests :: SpecWith () @@ -23,8 +25,8 @@ tests = describe "getDoc tests" $ do (getTypeScriptDeclarations (Proxy :: Proxy OneField)) `shouldBe` ([ TSTypeAlternatives "OneField" [] ["IOneField"] , TSInterfaceDeclaration "IOneField" [] [ - TSField False "simpleString" "string" (Just " This is a simple string") - ] + TSField False "simpleString" "string" (Just "This is a simple string") + ] (Just "OneField constructor doc") ]) main :: IO () From 68be59f818391d7b5f1259698b96bdeb819ccd4c Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Wed, 1 Mar 2023 00:56:52 -0800 Subject: [PATCH 05/76] Working on TSTypeAlternatives docs and cleaning up extensions --- aeson-typescript.cabal | 10 +++++++ package.yaml | 18 ++++++++--- src/Data/Aeson/TypeScript/Formatting.hs | 12 ++++---- src/Data/Aeson/TypeScript/Instances.hs | 6 +--- src/Data/Aeson/TypeScript/Lookup.hs | 9 ------ src/Data/Aeson/TypeScript/Recursive.hs | 8 ----- src/Data/Aeson/TypeScript/TH.hs | 30 +++---------------- src/Data/Aeson/TypeScript/Transform.hs | 9 ------ src/Data/Aeson/TypeScript/TypeManipulation.hs | 9 ------ src/Data/Aeson/TypeScript/Types.hs | 7 ++--- src/Data/Aeson/TypeScript/Util.hs | 21 ++++++++----- test/Basic.hs | 6 ++-- 12 files changed, 55 insertions(+), 90 deletions(-) diff --git a/aeson-typescript.cabal b/aeson-typescript.cabal index 2837766..93c2d8b 100644 --- a/aeson-typescript.cabal +++ b/aeson-typescript.cabal @@ -48,6 +48,16 @@ library Paths_aeson_typescript hs-source-dirs: src + default-extensions: + LambdaCase + RecordWildCards + NamedFieldPuns + MultiWayIf + TupleSections + QuasiQuotes + OverloadedStrings + ViewPatterns + ScopedTypeVariables build-depends: aeson , base >=4.7 && <5 diff --git a/package.yaml b/package.yaml index 4626235..07a1080 100644 --- a/package.yaml +++ b/package.yaml @@ -39,11 +39,21 @@ dependencies: library: source-dirs: src + default-extensions: + - LambdaCase + - RecordWildCards + - NamedFieldPuns + - MultiWayIf + - TupleSections + - QuasiQuotes + - OverloadedStrings + - ViewPatterns + - ScopedTypeVariables exposed-modules: - - Data.Aeson.TypeScript.TH - - Data.Aeson.TypeScript.Internal - - Data.Aeson.TypeScript.Recursive - - Data.Aeson.TypeScript.LegalName + - Data.Aeson.TypeScript.TH + - Data.Aeson.TypeScript.Internal + - Data.Aeson.TypeScript.Recursive + - Data.Aeson.TypeScript.LegalName tests: aeson-typescript-tests: diff --git a/src/Data/Aeson/TypeScript/Formatting.hs b/src/Data/Aeson/TypeScript/Formatting.hs index 7990790..c099c62 100644 --- a/src/Data/Aeson/TypeScript/Formatting.hs +++ b/src/Data/Aeson/TypeScript/Formatting.hs @@ -18,12 +18,14 @@ formatTSDeclarations = formatTSDeclarations' defaultFormattingOptions -- | 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] diff --git a/src/Data/Aeson/TypeScript/Instances.hs b/src/Data/Aeson/TypeScript/Instances.hs index 6d50c5b..3833dcc 100644 --- a/src/Data/Aeson/TypeScript/Instances.hs +++ b/src/Data/Aeson/TypeScript/Instances.hs @@ -1,8 +1,4 @@ -{-# LANGUAGE QuasiQuotes #-} -{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE OverlappingInstances #-} @@ -89,7 +85,7 @@ instance {-# OVERLAPPING #-} TypeScript [Char] where 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", "Right"] + getTypeScriptDeclarations _ = [TSTypeAlternatives "Either" ["T1", "T2"] ["Left", "Right"] Nothing , TSInterfaceDeclaration "Left" ["T"] [TSField False "Left" "T" Nothing] Nothing , TSInterfaceDeclaration "Right" ["T"] [TSField False "Right" "T" Nothing] Nothing ] diff --git a/src/Data/Aeson/TypeScript/Lookup.hs b/src/Data/Aeson/TypeScript/Lookup.hs index ef0e9a8..82544fe 100644 --- a/src/Data/Aeson/TypeScript/Lookup.hs +++ b/src/Data/Aeson/TypeScript/Lookup.hs @@ -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 diff --git a/src/Data/Aeson/TypeScript/Recursive.hs b/src/Data/Aeson/TypeScript/Recursive.hs index e525bf6..b0c7c12 100755 --- a/src/Data/Aeson/TypeScript/Recursive.hs +++ b/src/Data/Aeson/TypeScript/Recursive.hs @@ -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 ( diff --git a/src/Data/Aeson/TypeScript/TH.hs b/src/Data/Aeson/TypeScript/TH.hs index 0207026..c52c511 100644 --- a/src/Data/Aeson/TypeScript/TH.hs +++ b/src/Data/Aeson/TypeScript/TH.hs @@ -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 @@ -220,7 +211,8 @@ deriveTypeScript' options name extraOptions = do (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])) |] @@ -315,21 +307,7 @@ handleConstructor (ExtraTypeScriptOptions {..}) options (DatatypeInfo {..}) gene assembleInterfaceDeclaration members = [|TSInterfaceDeclaration $(TH.stringE interfaceName) $(genericVariablesListExpr True genericVariables) $(return members) - $(tryGetDoc (constructorName ci))|] - - tryGetDoc :: Name -> Q Exp - tryGetDoc 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|] + $(tryGetDoc haddockModifier (constructorName ci))|] getTSFields :: WriterT [ExtraDeclOrGenericInfo] Q [Exp] getTSFields = forM (namesAndTypes options genericVariables ci) $ \(name, nameString, typ) -> do @@ -338,7 +316,7 @@ handleConstructor (ExtraTypeScriptOptions {..}) options (DatatypeInfo {..}) gene ( , ) <$> [|$(getTypeAsStringExp t) <> " | null"|] <*> getOptionalAsBoolExp t _ -> ( , ) <$> getTypeAsStringExp typ <*> getOptionalAsBoolExp typ - lift [| TSField $(return optAsBool) $(TH.stringE nameString) $(return fieldTyp) $(tryGetDoc name) |] + lift [| TSField $(return optAsBool) $(TH.stringE nameString) $(return fieldTyp) $(tryGetDoc haddockModifier name) |] isSingleRecordConstructor (constructorVariant -> RecordConstructor [_]) = True isSingleRecordConstructor _ = False diff --git a/src/Data/Aeson/TypeScript/Transform.hs b/src/Data/Aeson/TypeScript/Transform.hs index 259267a..f5494e1 100644 --- a/src/Data/Aeson/TypeScript/Transform.hs +++ b/src/Data/Aeson/TypeScript/Transform.hs @@ -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 ( diff --git a/src/Data/Aeson/TypeScript/TypeManipulation.hs b/src/Data/Aeson/TypeScript/TypeManipulation.hs index dc36c11..9462d49 100644 --- a/src/Data/Aeson/TypeScript/TypeManipulation.hs +++ b/src/Data/Aeson/TypeScript/TypeManipulation.hs @@ -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 diff --git a/src/Data/Aeson/TypeScript/Types.hs b/src/Data/Aeson/TypeScript/Types.hs index 4b98999..58f5317 100644 --- a/src/Data/Aeson/TypeScript/Types.hs +++ b/src/Data/Aeson/TypeScript/Types.hs @@ -1,8 +1,4 @@ -{-# LANGUAGE QuasiQuotes #-} -{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TemplateHaskell #-} -{-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE StandaloneDeriving #-} @@ -91,7 +87,8 @@ data TSDeclaration = TSInterfaceDeclaration { interfaceName :: String , interfaceDoc :: Maybe String } | TSTypeAlternatives { typeName :: String , typeGenericVariables :: [String] - , alternativeTypes :: [String]} + , alternativeTypes :: [String] + , typeDoc :: Maybe String } | TSRawDeclaration { text :: String } deriving (Show, Eq, Ord) diff --git a/src/Data/Aeson/TypeScript/Util.hs b/src/Data/Aeson/TypeScript/Util.hs index 74b2c29..cedf0bf 100644 --- a/src/Data/Aeson/TypeScript/Util.hs +++ b/src/Data/Aeson/TypeScript/Util.hs @@ -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 @@ -227,3 +220,17 @@ 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|] diff --git a/test/Basic.hs b/test/Basic.hs index eec08ea..18c226d 100644 --- a/test/Basic.hs +++ b/test/Basic.hs @@ -22,13 +22,13 @@ tests = describe "Basic tests" $ do 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` ([ - TSTypeAlternatives "Unit2" [] ["\"foo\""] + TSTypeAlternatives "Unit2" [] ["\"foo\""] Nothing ]) From e75d17a220bc4e0fa54f6e00dbf9b9a0377d85fd Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Wed, 1 Mar 2023 01:10:37 -0800 Subject: [PATCH 06/76] Consolidate extensions and update TSTypeAlternatives in tests --- aeson-typescript.cabal | 21 +++++++++++++-------- package.yaml | 27 ++++++++++++--------------- src/Data/Aeson/TypeScript/TH.hs | 6 ++++-- test/ClosedTypeFamilies.hs | 8 ++++---- test/Generic.hs | 12 ++++++------ test/GetDoc.hs | 2 +- test/HigherKind.hs | 10 +++++----- test/NoOmitNothingFields.hs | 13 ++----------- test/OpenTypeFamilies.hs | 8 ++++---- test/UnwrapUnaryRecords.hs | 4 ++-- 10 files changed, 53 insertions(+), 58 deletions(-) diff --git a/aeson-typescript.cabal b/aeson-typescript.cabal index 93c2d8b..645ac1a 100644 --- a/aeson-typescript.cabal +++ b/aeson-typescript.cabal @@ -50,14 +50,14 @@ library src default-extensions: LambdaCase - RecordWildCards - NamedFieldPuns MultiWayIf - TupleSections - QuasiQuotes + NamedFieldPuns OverloadedStrings - ViewPatterns + QuasiQuotes + RecordWildCards ScopedTypeVariables + TupleSections + ViewPatterns build-depends: aeson , base >=4.7 && <5 @@ -113,14 +113,19 @@ test-suite aeson-typescript-tests test src default-extensions: + LambdaCase + MultiWayIf + NamedFieldPuns OverloadedStrings + QuasiQuotes + RecordWildCards ScopedTypeVariables - KindSignatures + TupleSections + ViewPatterns FlexibleContexts - QuasiQuotes + KindSignatures TemplateHaskell TypeFamilies - LambdaCase ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N -haddock -fno-warn-unused-top-binds -fno-warn-orphans build-depends: aeson diff --git a/package.yaml b/package.yaml index 07a1080..c8e44f4 100644 --- a/package.yaml +++ b/package.yaml @@ -37,18 +37,19 @@ dependencies: - transformers - unordered-containers +default-extensions: +- LambdaCase +- MultiWayIf +- NamedFieldPuns +- OverloadedStrings +- QuasiQuotes +- RecordWildCards +- ScopedTypeVariables +- TupleSections +- ViewPatterns + library: source-dirs: src - default-extensions: - - LambdaCase - - RecordWildCards - - NamedFieldPuns - - MultiWayIf - - TupleSections - - QuasiQuotes - - OverloadedStrings - - ViewPatterns - - ScopedTypeVariables exposed-modules: - Data.Aeson.TypeScript.TH - Data.Aeson.TypeScript.Internal @@ -70,14 +71,10 @@ tests: - -fno-warn-unused-top-binds - -fno-warn-orphans default-extensions: - - OverloadedStrings - - ScopedTypeVariables - - KindSignatures - FlexibleContexts - - QuasiQuotes + - KindSignatures - TemplateHaskell - TypeFamilies - - LambdaCase dependencies: - aeson-typescript - bytestring diff --git a/src/Data/Aeson/TypeScript/TH.hs b/src/Data/Aeson/TypeScript/TH.hs index c52c511..7cd0e49 100644 --- a/src/Data/Aeson/TypeScript/TH.hs +++ b/src/Data/Aeson/TypeScript/TH.hs @@ -287,7 +287,8 @@ handleConstructor (ExtraTypeScriptOptions {..}) options (DatatypeInfo {..}) gene _ -> getTypeAsStringExp typ alternatives <- lift [|TSTypeAlternatives $(TH.stringE interfaceName) $(genericVariablesListExpr True genericVariables) - [$(return stringExp)]|] + [$(return stringExp)] + $(tryGetDoc haddockModifier (constructorName ci))|] tell [ExtraDecl alternatives] #endif @@ -302,7 +303,8 @@ handleConstructor (ExtraTypeScriptOptions {..}) options (DatatypeInfo {..}) gene 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) diff --git a/test/ClosedTypeFamilies.hs b/test/ClosedTypeFamilies.hs index 606a0cf..0e75647 100644 --- a/test/ClosedTypeFamilies.hs +++ b/test/ClosedTypeFamilies.hs @@ -44,14 +44,14 @@ tests = describe "Closed type families" $ do , TSField False "\"single_node_env\"" "\"single\"" Nothing , TSField False "T" "void" Nothing ] Nothing - , TSTypeAlternatives "ISimple" ["T extends keyof DeployEnvironment2"] ["DeployEnvironment2[T]"] - , TSTypeAlternatives "Simple" ["T extends keyof DeployEnvironment2"] ["ISimple"] + , TSTypeAlternatives "ISimple" ["T extends keyof DeployEnvironment2"] ["DeployEnvironment2[T]"] Nothing + , TSTypeAlternatives "Simple" ["T extends keyof DeployEnvironment2"] ["ISimple"] 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"] + TSTypeAlternatives "UserT" ["T extends keyof DeployEnvironment"] ["IUser"] Nothing , TSInterfaceDeclaration "IUser" ["T extends keyof DeployEnvironment"] [ TSField False "_userUsername" "string" Nothing , TSField False "_userCreatedAt" "number" Nothing @@ -71,7 +71,7 @@ tests = describe "Closed type families" $ do , TSField False "_userCreatedAt" "number" Nothing , TSField False "_userDeployEnvironment" "DeployEnvironment[T]" Nothing ] Nothing - , TSTypeAlternatives "UserT" ["T extends keyof DeployEnvironment"] ["IUser"] + , TSTypeAlternatives "UserT" ["T extends keyof DeployEnvironment"] ["IUser"] Nothing ]) main :: IO () diff --git a/test/Generic.hs b/test/Generic.hs index fa36a3e..68f92fb 100644 --- a/test/Generic.hs +++ b/test/Generic.hs @@ -31,30 +31,30 @@ tests = describe "Generic instances" $ do (getTypeScriptDeclarationsRecursively (Proxy :: Proxy (Complex String))) `shouldBe` [ 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 {typeName = "Complex", typeGenericVariables = ["T"], alternativeTypes = ["IProduct","IUnary"]} + ,TSTypeAlternatives "Complex" ["T"] ["IProduct","IUnary"] Nothing ] it [i|Complex2 makes the declaration and types correctly|] $ do (getTypeScriptDeclarationsRecursively (Proxy :: Proxy (Complex2 String))) `shouldBe` [ - TSTypeAlternatives {typeName = "Complex2", typeGenericVariables = ["T"], alternativeTypes = ["IProduct2"]} - ,TSTypeAlternatives {typeName = "IProduct2", typeGenericVariables = ["T"], alternativeTypes = ["[number, T]"]} + TSTypeAlternatives "Complex2" ["T"] ["IProduct2"] Nothing + ,TSTypeAlternatives "IProduct2" ["T"] ["[number, T]"] Nothing ] it [i|Complex3 makes the declaration and types correctly|] $ do (getTypeScriptDeclarationsRecursively (Proxy :: Proxy (Complex3 String))) `shouldBe` [ TSInterfaceDeclaration "IProduct3" ["T"] [TSField False "record3" "T[]" Nothing] Nothing - ,TSTypeAlternatives {typeName = "Complex3", typeGenericVariables = ["T"], alternativeTypes = ["IProduct3"]} + ,TSTypeAlternatives "Complex3" ["T"] ["IProduct3"] Nothing ] (getTypeScriptDeclarationsRecursively (Proxy :: Proxy (Complex3 Int))) `shouldBe` [ TSInterfaceDeclaration "IProduct3" ["T"] [TSField False "record3" "T[]" Nothing] Nothing - ,TSTypeAlternatives {typeName = "Complex3", typeGenericVariables = ["T"], alternativeTypes = ["IProduct3"]} + ,TSTypeAlternatives "Complex3" ["T"] ["IProduct3"] Nothing ] it [i|Complex4 makes the declaration and types correctly|] $ do (getTypeScriptDeclarationsRecursively (Proxy :: Proxy (Complex4 String))) `shouldBe` [ TSInterfaceDeclaration "IProduct4" ["T"] [TSField False "record4" "{[k in string]?: T}" Nothing] Nothing - ,TSTypeAlternatives {typeName = "Complex4", typeGenericVariables = ["T"], alternativeTypes = ["IProduct4"]} + ,TSTypeAlternatives "Complex4" ["T"] ["IProduct4"] Nothing ] main :: IO () diff --git a/test/GetDoc.hs b/test/GetDoc.hs index 8ee8f80..73f25b7 100644 --- a/test/GetDoc.hs +++ b/test/GetDoc.hs @@ -23,7 +23,7 @@ tests :: SpecWith () tests = describe "getDoc tests" $ do it [i|Works with a simple record type|] $ do (getTypeScriptDeclarations (Proxy :: Proxy OneField)) `shouldBe` ([ - TSTypeAlternatives "OneField" [] ["IOneField"] + TSTypeAlternatives "OneField" [] ["IOneField"] (Just "OneField type doc") , TSInterfaceDeclaration "IOneField" [] [ TSField False "simpleString" "string" (Just "This is a simple string") ] (Just "OneField constructor doc") diff --git a/test/HigherKind.hs b/test/HigherKind.hs index 00aeac5..3587785 100644 --- a/test/HigherKind.hs +++ b/test/HigherKind.hs @@ -36,7 +36,7 @@ tests = describe "Higher kinds" $ do describe "Kind * -> *" $ do it [i|makes the declaration and types correctly|] $ do (getTypeScriptDeclarations (Proxy :: Proxy (HigherKind T))) `shouldBe` ([ - TSTypeAlternatives "HigherKind" ["T"] ["IHigherKind"], + TSTypeAlternatives "HigherKind" ["T"] ["IHigherKind"] Nothing, TSInterfaceDeclaration "IHigherKind" ["T"] [TSField False "higherKindList" "T[]" Nothing] Nothing ]) @@ -45,21 +45,21 @@ tests = describe "Higher kinds" $ do it [i|works when referenced in another type|] $ do (getTypeScriptDeclarations (Proxy :: Proxy Foo)) `shouldBe` ([ - TSTypeAlternatives "Foo" [] ["IFoo"], + TSTypeAlternatives "Foo" [] ["IFoo"] Nothing, TSInterfaceDeclaration "IFoo" [] [TSField False "fooString" "string" Nothing , TSField False "fooHigherKindReference" "HigherKind" Nothing] Nothing ]) it [i|works with an interface inside|] $ do (getTypeScriptDeclarations (Proxy :: Proxy (HigherKindWithUnary T))) `shouldBe` ([ - TSTypeAlternatives "HigherKindWithUnary" ["T"] ["IUnary"], - TSTypeAlternatives "IUnary" ["T"] ["number"] + TSTypeAlternatives "HigherKindWithUnary" ["T"] ["IUnary"] 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"], + TSTypeAlternatives "DoubleHigherKind" ["T1","T2"] ["IDoubleHigherKind"] Nothing, TSInterfaceDeclaration "IDoubleHigherKind" ["T1","T2"] [TSField False "someList" "T2[]" Nothing , TSField False "higherKindThing" "HigherKind" Nothing] Nothing ]) diff --git a/test/NoOmitNothingFields.hs b/test/NoOmitNothingFields.hs index 36c5d39..148e822 100644 --- a/test/NoOmitNothingFields.hs +++ b/test/NoOmitNothingFields.hs @@ -15,16 +15,7 @@ allTests = describe "NoOmitNothingFields" $ do 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 False "optionalInt" "number | null" Nothing] - , interfaceDoc = Nothing - }] + decls `shouldBe` [TSTypeAlternatives "Optional" [] ["IOptional"] Nothing + , TSInterfaceDeclaration "IOptional" [] [TSField False "optionalInt" "number | null" Nothing] Nothing] tests diff --git a/test/OpenTypeFamilies.hs b/test/OpenTypeFamilies.hs index 1b1aeaa..52a148e 100644 --- a/test/OpenTypeFamilies.hs +++ b/test/OpenTypeFamilies.hs @@ -44,14 +44,14 @@ tests = describe "Open type families" $ do , TSField False "\"k8s_env\"" "\"k8s\"" Nothing , TSField False "T" "void" Nothing ] Nothing - , TSTypeAlternatives "ISimple" ["T extends keyof DeployEnvironment2"] ["DeployEnvironment2[T]"] - , TSTypeAlternatives "Simple" ["T extends keyof DeployEnvironment2"] ["ISimple"] + , TSTypeAlternatives "ISimple" ["T extends keyof DeployEnvironment2"] ["DeployEnvironment2[T]"] Nothing + , TSTypeAlternatives "Simple" ["T extends keyof DeployEnvironment2"] ["ISimple"] 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"] + TSTypeAlternatives "UserT" ["T extends keyof DeployEnvironment"] ["IUser"] Nothing , TSInterfaceDeclaration "IUser" ["T extends keyof DeployEnvironment"] [ TSField False "_userUsername" "string" Nothing , TSField False "_userCreatedAt" "number" Nothing @@ -71,7 +71,7 @@ tests = describe "Open type families" $ do , TSField False "_userCreatedAt" "number" Nothing , TSField False "_userDeployEnvironment" "DeployEnvironment[T]" Nothing ] Nothing - , TSTypeAlternatives "UserT" ["T extends keyof DeployEnvironment"] ["IUser"] + , TSTypeAlternatives "UserT" ["T extends keyof DeployEnvironment"] ["IUser"] Nothing ]) main :: IO () diff --git a/test/UnwrapUnaryRecords.hs b/test/UnwrapUnaryRecords.hs index 99c702d..1a75fb2 100644 --- a/test/UnwrapUnaryRecords.hs +++ b/test/UnwrapUnaryRecords.hs @@ -19,8 +19,8 @@ allTests = describe "UnwrapUnaryRecords" $ do 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 From b8149881c317ef95ca702747fc74ef5affddff83 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Wed, 1 Mar 2023 01:17:33 -0800 Subject: [PATCH 07/76] Change default haddockModifier to stripStart on each line --- src/Data/Aeson/TypeScript/Types.hs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/Data/Aeson/TypeScript/Types.hs b/src/Data/Aeson/TypeScript/Types.hs index 58f5317..a96f635 100644 --- a/src/Data/Aeson/TypeScript/Types.hs +++ b/src/Data/Aeson/TypeScript/Types.hs @@ -7,10 +7,11 @@ module Data.Aeson.TypeScript.Types where import qualified Data.Aeson as A import Data.Aeson.TypeScript.LegalName -import qualified Data.List as L +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 @@ -205,15 +206,20 @@ data ExtraTypeScriptOptions = ExtraTypeScriptOptions { , keyType :: Maybe String -- | Function which is applied to all Haddocks we read in. - -- By default, just drops leading whitespace. + -- By default, just drops leading whitespace from each line. , haddockModifier :: String -> String } defaultExtraTypeScriptOptions :: ExtraTypeScriptOptions -defaultExtraTypeScriptOptions = ExtraTypeScriptOptions [] Nothing deleteLeadingWhitespace +defaultExtraTypeScriptOptions = ExtraTypeScriptOptions [] Nothing stripStartEachLine where - deleteLeadingWhitespace :: String -> String - deleteLeadingWhitespace = L.dropWhile (== ' ') + 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 From bab4047f5c551e4f4b48cccf46d6c9ccbf13421d Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Wed, 1 Mar 2023 01:17:52 -0800 Subject: [PATCH 08/76] Format haddocks with // comments always --- src/Data/Aeson/TypeScript/Formatting.hs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Data/Aeson/TypeScript/Formatting.hs b/src/Data/Aeson/TypeScript/Formatting.hs index c099c62..990971e 100644 --- a/src/Data/Aeson/TypeScript/Formatting.hs +++ b/src/Data/Aeson/TypeScript/Formatting.hs @@ -3,6 +3,7 @@ module Data.Aeson.TypeScript.Formatting where import Data.Aeson.TypeScript.Types +import Data.Function ((&)) import qualified Data.List as L import Data.String.Interpolate import qualified Data.Text as T @@ -73,8 +74,10 @@ formatTSField (TSField optional name typ maybeDoc) = makeDocPrefix maybeDoc <> [ makeDocPrefix :: Maybe String -> String makeDocPrefix maybeDoc = case maybeDoc of Nothing -> "" - Just doc | '\n' `L.elem` doc -> "/* " <> doc <> " */\n" - Just doc -> "// " <> doc <> "\n" + Just (T.pack -> text) -> ["// " <> line | line <- T.splitOn "\n" text] + & T.intercalate "\n" + & (<> "\n") + & T.unpack getGenericBrackets :: [String] -> String getGenericBrackets [] = "" From 4c587754358dad3463ae5e5dd46b4b334408348d Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Wed, 1 Mar 2023 03:03:43 -0800 Subject: [PATCH 09/76] Implement @no-emit-typescript annotation address #31 --- CHANGELOG.md | 1 + src/Data/Aeson/TypeScript/Formatting.hs | 39 +++++++++++- test/Formatting.hs | 80 +++++++++++++++++-------- 3 files changed, 91 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f0610c1..e817f8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * [#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. +* Add support for @no-emit-typescript in Haddocks for constructors and record fields (requires GHC >= 9.2) ## 0.4.2.0 diff --git a/src/Data/Aeson/TypeScript/Formatting.hs b/src/Data/Aeson/TypeScript/Formatting.hs index 990971e..b4e4c77 100644 --- a/src/Data/Aeson/TypeScript/Formatting.hs +++ b/src/Data/Aeson/TypeScript/Formatting.hs @@ -1,10 +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 @@ -33,7 +34,7 @@ formatTSDeclaration (FormattingOptions {..}) (TSTypeAlternatives name genericVar enumType = [i|\n\ntype #{name} = keyof typeof #{typeNameModifier name};|] :: T.Text toEnumName = T.replace "\"" "" -formatTSDeclaration (FormattingOptions {..}) (TSInterfaceDeclaration interfaceName genericVariables members maybeDoc) = +formatTSDeclaration (FormattingOptions {..}) (TSInterfaceDeclaration interfaceName genericVariables (filter (not . isNoEmitTypeScriptField) -> members) maybeDoc) = makeDocPrefix maybeDoc <> [i|#{exportPrefix exportMode}interface #{modifiedInterfaceName}#{getGenericBrackets genericVariables} { #{ls} }|] where @@ -52,7 +53,27 @@ 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 @@ -82,3 +103,15 @@ makeDocPrefix maybeDoc = case maybeDoc of 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 diff --git a/test/Formatting.hs b/test/Formatting.hs index c4fec32..f9a4906 100644 --- a/test/Formatting.hs +++ b/test/Formatting.hs @@ -19,30 +19,58 @@ $(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" $ 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 +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 + + 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}|] + +main :: IO () +main = hspec tests From d6a3addf220d51dcc1199744869beda2b8bb2aa1 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Wed, 1 Mar 2023 03:17:19 -0800 Subject: [PATCH 10/76] Check for compatible template-haskell when testing @no-emit-typescript --- test/Formatting.hs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/Formatting.hs b/test/Formatting.hs index f9a4906..d035c4e 100644 --- a/test/Formatting.hs +++ b/test/Formatting.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE CPP #-} {-# LANGUAGE TypeApplications #-} module Formatting (tests) where @@ -65,12 +66,14 @@ tests = describe "Formatting" $ 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 From 6c4cbc9dd5127c6f36faab5ec73df52531a68644 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Wed, 22 Mar 2023 21:33:09 -0700 Subject: [PATCH 11/76] GHC 9.2.6 -> 9.2.7 in CI --- .github/workflows/aeson-typescript.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/aeson-typescript.yml b/.github/workflows/aeson-typescript.yml index 669806a..5d5b9ee 100644 --- a/.github/workflows/aeson-typescript.yml +++ b/.github/workflows/aeson-typescript.yml @@ -70,7 +70,7 @@ jobs: - "8.8.4" - "8.10.7" - "9.0.2" - - "9.2.6" + - "9.2.7" - "9.4.4" steps: From 6f5803aaa179e11410b4a714b5479d2f84a15b87 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Wed, 22 Mar 2023 21:33:24 -0700 Subject: [PATCH 12/76] See if we can test GHC 9.6.1 Cabal in CI --- .github/workflows/aeson-typescript.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/aeson-typescript.yml b/.github/workflows/aeson-typescript.yml index 5d5b9ee..3246c6a 100644 --- a/.github/workflows/aeson-typescript.yml +++ b/.github/workflows/aeson-typescript.yml @@ -19,6 +19,7 @@ jobs: - "9.0.2" - "9.2.6" - "9.4.4" + - "9.6.1" # exclude: # - os: macOS-latest # ghc: 8.8.3 From 5ae6687ba09c609c6698ef06ad6b3dac490395d1 Mon Sep 17 00:00:00 2001 From: Rebecca Turner Date: Wed, 22 Mar 2023 11:31:00 -0700 Subject: [PATCH 13/76] Enable building with mtl-2.3 --- src/Data/Aeson/TypeScript/Recursive.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Data/Aeson/TypeScript/Recursive.hs b/src/Data/Aeson/TypeScript/Recursive.hs index b0c7c12..8eb673c 100755 --- a/src/Data/Aeson/TypeScript/Recursive.hs +++ b/src/Data/Aeson/TypeScript/Recursive.hs @@ -16,6 +16,7 @@ module Data.Aeson.TypeScript.Recursive ( , getAllParentTypes ) where +import Control.Monad import Control.Monad.State import Control.Monad.Trans.Maybe import Control.Monad.Writer From 1ddb9d529436d804957c52f89a7f6cfbdf5e1a5c Mon Sep 17 00:00:00 2001 From: Langston Barrett Date: Wed, 3 Aug 2022 10:14:40 -0400 Subject: [PATCH 14/76] Add instances for more types from base Specifically: * `Data.Functor.Compose.Compose` * `Data.Functor.Const.Const` * `Data.Functor.Identity.Identity` * `Data.Functor.Product.Product` * `Data.List.NonEmpty.NonEmpty` * `Data.Word.Word` * `Data.Word.Word16` * `Data.Word.Word32` * `Data.Word.Word64` * `Numeric.Natural.Natural` --- src/Data/Aeson/TypeScript/Instances.hs | 43 ++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/Data/Aeson/TypeScript/Instances.hs b/src/Data/Aeson/TypeScript/Instances.hs index 3833dcc..8759207 100644 --- a/src/Data/Aeson/TypeScript/Instances.hs +++ b/src/Data/Aeson/TypeScript/Instances.hs @@ -13,9 +13,14 @@ module Data.Aeson.TypeScript.Instances where import qualified Data.Aeson as A import Data.Aeson.TypeScript.Types import Data.Data +import Data.Functor.Compose (Compose) +import Data.Functor.Const (Const) +import Data.Functor.Identity (Identity) +import Data.Functor.Product (Product) import Data.HashMap.Strict import Data.HashSet import qualified Data.List as L +import Data.List.NonEmpty (NonEmpty) import Data.Map.Strict import Data.Set import Data.String.Interpolate @@ -23,6 +28,7 @@ import qualified Data.Text as T import qualified Data.Text.Lazy as TL import Data.Void import Data.Word +import Numeric.Natural (Natural) import GHC.Int #if !MIN_VERSION_base(4,11,0) @@ -49,6 +55,9 @@ instance TypeScript TL.Text where instance TypeScript Integer where getTypeScriptType _ = "number" +instance TypeScript Natural where + getTypeScriptType _ = "number" + instance TypeScript Float where getTypeScriptType _ = "number" @@ -73,13 +82,29 @@ instance TypeScript Int64 where instance TypeScript Char where getTypeScriptType _ = "string" +instance TypeScript Word where + getTypeScriptType _ = "number" + instance TypeScript Word8 where getTypeScriptType _ = "number" +instance TypeScript Word16 where + getTypeScriptType _ = "number" + +instance TypeScript Word32 where + getTypeScriptType _ = "number" + +instance TypeScript Word64 where + getTypeScriptType _ = "number" + instance {-# OVERLAPPABLE #-} (TypeScript a) => TypeScript [a] where getTypeScriptType _ = (getTypeScriptType (Proxy :: Proxy a)) ++ "[]" getParentTypes _ = [TSType (Proxy :: Proxy a)] +instance (TypeScript a) => TypeScript (NonEmpty a) where + getTypeScriptType _ = getTypeScriptType (Proxy :: Proxy [a]) + getParentTypes _ = [TSType (Proxy :: Proxy a)] + instance {-# OVERLAPPING #-} TypeScript [Char] where getTypeScriptType _ = "string" @@ -114,6 +139,24 @@ instance (TypeScript a, TypeScript b, TypeScript c, TypeScript d) => TypeScript , (TSType (Proxy :: Proxy d)) ] +instance (TypeScript a) => TypeScript (Const a) where + getTypeScriptType _ = getTypeScriptType (Proxy :: Proxy a) + getParentTypes _ = [TSType (Proxy :: Proxy a)] + +instance (TypeScript a) => TypeScript (Identity a) where + getTypeScriptType _ = getTypeScriptType (Proxy :: Proxy a) + getParentTypes _ = [TSType (Proxy :: Proxy a)] + +instance (Typeable f, Typeable g, Typeable a, TypeScript (f (g a)), TypeScript a) => TypeScript (Compose f g a) where + getTypeScriptType _ = getTypeScriptType (Proxy :: Proxy (f (g a))) + getParentTypes _ = getParentTypes (Proxy :: Proxy (f (g a))) + +instance (Typeable f, Typeable g, Typeable a, TypeScript (f a), TypeScript (g a)) => TypeScript (Product f g a) where + getTypeScriptType _ = getTypeScriptType (Proxy :: Proxy (f a, g a)) + getParentTypes _ = L.nub [ (TSType (Proxy :: Proxy (f a))) + , (TSType (Proxy :: Proxy (g a))) + ] + instance (TypeScript a) => TypeScript (Maybe a) where getTypeScriptType _ = getTypeScriptType (Proxy :: Proxy a) getTypeScriptOptional _ = True From 0043bb7fd9cfad055fa085be46dfc872485ce3cd Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Wed, 22 Mar 2023 23:06:14 -0700 Subject: [PATCH 15/76] Bump dev stack resolver --- stack.yaml | 2 +- stack.yaml.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/stack.yaml b/stack.yaml index 812491d..677d2f3 100644 --- a/stack.yaml +++ b/stack.yaml @@ -1,5 +1,5 @@ -resolver: lts-20.12 +resolver: lts-20.15 packages: - . diff --git a/stack.yaml.lock b/stack.yaml.lock index b1d5d3a..79b93cf 100644 --- a/stack.yaml.lock +++ b/stack.yaml.lock @@ -6,7 +6,7 @@ packages: [] snapshots: - completed: - sha256: af5d667f6096e535b9c725a72cffe0f6c060e0568d9f9eeda04caee70d0d9d2d - size: 649133 - url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/20/12.yaml - original: lts-20.12 + sha256: 5d1df60a0aaf19ab42eb79d5ca01ab812318a96be3925559e902e1bfd8cac569 + size: 649582 + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/20/15.yaml + original: lts-20.15 From 5ef8e5507cbef37eb89a8e4d2c0c667dec931d16 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Wed, 22 Mar 2023 23:07:07 -0700 Subject: [PATCH 16/76] Release 0.5.0.0 --- CHANGELOG.md | 6 +++++- aeson-typescript.cabal | 2 +- package.yaml | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e817f8a..0b614a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,10 +3,14 @@ ## (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. -* Add support for @no-emit-typescript in Haddocks for constructors and record fields (requires GHC >= 9.2) +* 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 diff --git a/aeson-typescript.cabal b/aeson-typescript.cabal index 645ac1a..6416159 100644 --- a/aeson-typescript.cabal +++ b/aeson-typescript.cabal @@ -5,7 +5,7 @@ cabal-version: 1.12 -- 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 category: Text, Web, JSON diff --git a/package.yaml b/package.yaml index c8e44f4..a029bb2 100644 --- a/package.yaml +++ b/package.yaml @@ -1,5 +1,5 @@ name: aeson-typescript -version: 0.4.2.0 +version: 0.5.0.0 github: "codedownio/aeson-typescript" license: BSD3 category: Text, Web, JSON From c8c94fd49b052eb8ac09680cd3dd6efc7661b0a4 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Thu, 23 Mar 2023 00:29:31 -0700 Subject: [PATCH 17/76] Try fixing up new instances and add test of the new number ones --- src/Data/Aeson/TypeScript/Instances.hs | 14 ++++++++++---- test/TestBoilerplate.hs | 12 ++++++++++++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/Data/Aeson/TypeScript/Instances.hs b/src/Data/Aeson/TypeScript/Instances.hs index 8759207..97de51c 100644 --- a/src/Data/Aeson/TypeScript/Instances.hs +++ b/src/Data/Aeson/TypeScript/Instances.hs @@ -3,6 +3,7 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE OverlappingInstances #-} {-# LANGUAGE CPP #-} +{-# LANGUAGE PolyKinds #-} {-# OPTIONS_GHC -fno-warn-orphans #-} -- Note: the OverlappingInstances pragma is only here so the overlapping instances in this file @@ -19,6 +20,7 @@ import Data.Functor.Identity (Identity) import Data.Functor.Product (Product) import Data.HashMap.Strict import Data.HashSet +import Data.Kind (Type) import qualified Data.List as L import Data.List.NonEmpty (NonEmpty) import Data.Map.Strict @@ -28,8 +30,8 @@ import qualified Data.Text as T import qualified Data.Text.Lazy as TL import Data.Void import Data.Word -import Numeric.Natural (Natural) import GHC.Int +import Numeric.Natural (Natural) #if !MIN_VERSION_base(4,11,0) import Data.Monoid @@ -139,7 +141,7 @@ instance (TypeScript a, TypeScript b, TypeScript c, TypeScript d) => TypeScript , (TSType (Proxy :: Proxy d)) ] -instance (TypeScript a) => TypeScript (Const a) where +instance forall a k (b :: k). (Typeable k, Typeable b, TypeScript a) => TypeScript (Const a b) where getTypeScriptType _ = getTypeScriptType (Proxy :: Proxy a) getParentTypes _ = [TSType (Proxy :: Proxy a)] @@ -147,11 +149,15 @@ instance (TypeScript a) => TypeScript (Identity a) where getTypeScriptType _ = getTypeScriptType (Proxy :: Proxy a) getParentTypes _ = [TSType (Proxy :: Proxy a)] -instance (Typeable f, Typeable g, Typeable a, TypeScript (f (g a)), TypeScript a) => TypeScript (Compose f g a) where +instance forall k k1 (f :: k -> Type) (g :: k1 -> k) a. ( + Typeable k, Typeable k1, Typeable f, Typeable g, Typeable a, TypeScript (f (g a)), TypeScript a + ) => TypeScript (Compose f g a) where getTypeScriptType _ = getTypeScriptType (Proxy :: Proxy (f (g a))) getParentTypes _ = getParentTypes (Proxy :: Proxy (f (g a))) -instance (Typeable f, Typeable g, Typeable a, TypeScript (f a), TypeScript (g a)) => TypeScript (Product f g a) where +instance forall k (f :: k -> Type) (g :: k -> Type) a. ( + Typeable k, Typeable f, Typeable g, Typeable a, TypeScript (f a), TypeScript (g a) + ) => TypeScript (Product f g a) where getTypeScriptType _ = getTypeScriptType (Proxy :: Proxy (f a, g a)) getParentTypes _ = L.nub [ (TSType (Proxy :: Proxy (f a))) , (TSType (Proxy :: Proxy (g a))) diff --git a/test/TestBoilerplate.hs b/test/TestBoilerplate.hs index ac4afd0..a642548 100644 --- a/test/TestBoilerplate.hs +++ b/test/TestBoilerplate.hs @@ -10,7 +10,9 @@ import Data.Functor.Identity import Data.Kind import Data.Proxy import Data.String.Interpolate +import Data.Word import Language.Haskell.TH hiding (Type) +import Numeric.Natural (Natural) import Test.Hspec import Util import Util.Aeson @@ -25,6 +27,13 @@ data TwoConstructor = Con1 { con1String :: String } | Con2 { con2String :: Strin data Complex a = Nullary | Unary Int | Product String Char a | Record { testOne :: Int, testTwo :: Bool, testThree :: Complex a} deriving Eq data Optional = Optional {optionalInt :: Maybe Int} data AesonTypes = AesonTypes { aesonValue :: A.Value, aesonObject :: A.Object } +data Numbers = Numbers { + natural :: Natural + , word :: Word + , word16 :: Word16 + , word32 :: Word32 + , word64 :: Word64 + } -- * For testing type families @@ -65,6 +74,7 @@ testDeclarations testName aesonOptions = do deriveInstances ''Complex deriveInstances ''Optional deriveInstances ''AesonTypes + deriveInstances ''Numbers typesAndValues :: Exp <- [e|[(getTypeScriptType (Proxy :: Proxy Unit), A.encode Unit) @@ -94,6 +104,8 @@ testDeclarations testName aesonOptions = do aesonValue = A.object [("foo" :: A.Key, A.Number 42)] , aesonObject = aesonFromList [("foo", A.Number 42)] })) + + , (getTypeScriptType (Proxy :: Proxy Optional), A.encode (Numbers 42 42 42 42 42)) ]|] declarations :: Exp <- [e|getTypeScriptDeclarations (Proxy :: Proxy Unit) From 7a7fd49bf99ad3462b43468d698b5ceb0a7babed Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Thu, 23 Mar 2023 00:31:54 -0700 Subject: [PATCH 18/76] Fix numbers boilerplate --- test/TestBoilerplate.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/TestBoilerplate.hs b/test/TestBoilerplate.hs index a642548..2dbfbb0 100644 --- a/test/TestBoilerplate.hs +++ b/test/TestBoilerplate.hs @@ -105,7 +105,7 @@ testDeclarations testName aesonOptions = do , aesonObject = aesonFromList [("foo", A.Number 42)] })) - , (getTypeScriptType (Proxy :: Proxy Optional), A.encode (Numbers 42 42 42 42 42)) + , (getTypeScriptType (Proxy :: Proxy Numbers), A.encode (Numbers 42 42 42 42 42)) ]|] declarations :: Exp <- [e|getTypeScriptDeclarations (Proxy :: Proxy Unit) From ba24350b7117ec57f829a95b28ed41d6b8817c7a Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Thu, 23 Mar 2023 00:39:32 -0700 Subject: [PATCH 19/76] One more boilerplate fix --- test/TestBoilerplate.hs | 1 + 1 file changed, 1 insertion(+) diff --git a/test/TestBoilerplate.hs b/test/TestBoilerplate.hs index 2dbfbb0..f19112d 100644 --- a/test/TestBoilerplate.hs +++ b/test/TestBoilerplate.hs @@ -118,6 +118,7 @@ testDeclarations testName aesonOptions = do <> getTypeScriptDeclarations (Proxy :: Proxy (Complex T)) <> getTypeScriptDeclarations (Proxy :: Proxy Optional) <> getTypeScriptDeclarations (Proxy :: Proxy AesonTypes) + <> getTypeScriptDeclarations (Proxy :: Proxy Numbers) |] tests <- [d|tests :: SpecWith () From aed83abcfee2aecd3399b33c67a308cbd2e340db Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Thu, 23 Mar 2023 00:39:39 -0700 Subject: [PATCH 20/76] Fix up package.yaml tested-with --- .github/workflows/aeson-typescript.yml | 2 +- aeson-typescript.cabal | 8 +++++++- package.yaml | 9 ++++++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/.github/workflows/aeson-typescript.yml b/.github/workflows/aeson-typescript.yml index 3246c6a..2f60f89 100644 --- a/.github/workflows/aeson-typescript.yml +++ b/.github/workflows/aeson-typescript.yml @@ -17,7 +17,7 @@ jobs: - "8.8.4" - "8.10.7" - "9.0.2" - - "9.2.6" + - "9.2.7" - "9.4.4" - "9.6.1" # exclude: diff --git a/aeson-typescript.cabal b/aeson-typescript.cabal index 6416159..34423cd 100644 --- a/aeson-typescript.cabal +++ b/aeson-typescript.cabal @@ -18,7 +18,13 @@ license: BSD3 license-file: LICENSE build-type: Simple tested-with: - GHC == 9.0.1, GHC == 8.10.4, GHC == 8.10.3, GHC == 8.8.4, GHC == 8.8.3 + GHC == 9.6.1 + , GHC == 9.4.4 + , GHC == 9.2.7 + , GHC == 9.0.2 + , GHC == 8.10.7 + , GHC == 8.8.4 + , GHC == 8.6.5 extra-source-files: README.md CHANGELOG.md diff --git a/package.yaml b/package.yaml index a029bb2..87ad92c 100644 --- a/package.yaml +++ b/package.yaml @@ -23,7 +23,14 @@ synopsis: Generate TypeScript definition files from your ADTs # common to point users to the README.md file. description: Please see the README on Github at -tested-with: GHC == 9.0.1, GHC == 8.10.4, GHC == 8.10.3, GHC == 8.8.4, GHC == 8.8.3 +tested-with: +- GHC == 9.6.1 +- GHC == 9.4.4 +- GHC == 9.2.7 +- GHC == 9.0.2 +- GHC == 8.10.7 +- GHC == 8.8.4 +- GHC == 8.6.5 dependencies: - aeson From afbf9210ea53f29f70631603f73b51403fa49584 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Thu, 23 Mar 2023 00:43:22 -0700 Subject: [PATCH 21/76] Bump CI setup-node version (v2 -> v3) and node (v12 -> v16) --- .github/workflows/aeson-typescript.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/aeson-typescript.yml b/.github/workflows/aeson-typescript.yml index 2f60f89..6577565 100644 --- a/.github/workflows/aeson-typescript.yml +++ b/.github/workflows/aeson-typescript.yml @@ -89,10 +89,9 @@ jobs: path: ~/.stack key: ${{ runner.os }}-${{ matrix.ghc }}-stack - # Install TSC - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v3 with: - node-version: '12' + node-version: '16' - name: Install TSC run: | npm install -g typescript From 55ed89b0eec31fc01afc81ced236905476781e2f Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Thu, 23 Mar 2023 01:54:30 -0700 Subject: [PATCH 22/76] More FancyFunctors fields --- test/TestBoilerplate.hs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/TestBoilerplate.hs b/test/TestBoilerplate.hs index f19112d..5b4ad98 100644 --- a/test/TestBoilerplate.hs +++ b/test/TestBoilerplate.hs @@ -6,8 +6,12 @@ import Control.Monad.Writer.Lazy hiding (Product) import qualified Data.Aeson as A import Data.Aeson.TH as A import Data.Aeson.TypeScript.TH +import Data.Functor.Compose +import Data.Functor.Const import Data.Functor.Identity +import Data.Functor.Product import Data.Kind +import Data.List.NonEmpty import Data.Proxy import Data.String.Interpolate import Data.Word @@ -34,6 +38,17 @@ data Numbers = Numbers { , word32 :: Word32 , word64 :: Word64 } +data FancyFunctors = FancyFunctors { + nonEmpty :: NonEmpty Int + , const :: Const Int Int + , product :: Product Identity Identity Int + , compose :: Compose Identity Identity Int + } + +-- * Values + +fancyFunctorsValue :: FancyFunctors +fancyFunctorsValue = FancyFunctors (42 :| []) (Const 42) (Pair 42 42) (Compose 42) -- * For testing type families @@ -75,6 +90,7 @@ testDeclarations testName aesonOptions = do deriveInstances ''Optional deriveInstances ''AesonTypes deriveInstances ''Numbers + deriveInstances ''FancyFunctors typesAndValues :: Exp <- [e|[(getTypeScriptType (Proxy :: Proxy Unit), A.encode Unit) @@ -106,6 +122,7 @@ testDeclarations testName aesonOptions = do })) , (getTypeScriptType (Proxy :: Proxy Numbers), A.encode (Numbers 42 42 42 42 42)) + , (getTypeScriptType (Proxy :: Proxy FancyFunctors), A.encode fancyFunctorsValue) ]|] declarations :: Exp <- [e|getTypeScriptDeclarations (Proxy :: Proxy Unit) @@ -119,6 +136,7 @@ testDeclarations testName aesonOptions = do <> getTypeScriptDeclarations (Proxy :: Proxy Optional) <> getTypeScriptDeclarations (Proxy :: Proxy AesonTypes) <> getTypeScriptDeclarations (Proxy :: Proxy Numbers) + <> getTypeScriptDeclarations (Proxy :: Proxy FancyFunctors) |] tests <- [d|tests :: SpecWith () From 671347e3739b63bf04d5412330dc9a4748c7832e Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Thu, 27 Apr 2023 17:15:06 -0700 Subject: [PATCH 23/76] Release 0.6.0.0 --- CHANGELOG.md | 5 ++++- aeson-typescript.cabal | 2 +- package.yaml | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b614a8..0d7aba8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,10 @@ # Change log -## (unreleased) +## 0.6.0.0 + +* New word instances: Word, Word16, Word32, Word64 +* New instances from Data.Functor: Compose, Const, Identity, Product ## 0.5.0.0 diff --git a/aeson-typescript.cabal b/aeson-typescript.cabal index 34423cd..aead56b 100644 --- a/aeson-typescript.cabal +++ b/aeson-typescript.cabal @@ -5,7 +5,7 @@ cabal-version: 1.12 -- see: https://github.com/sol/hpack name: aeson-typescript -version: 0.5.0.0 +version: 0.6.0.0 synopsis: Generate TypeScript definition files from your ADTs description: Please see the README on Github at category: Text, Web, JSON diff --git a/package.yaml b/package.yaml index 87ad92c..3821c55 100644 --- a/package.yaml +++ b/package.yaml @@ -1,5 +1,5 @@ name: aeson-typescript -version: 0.5.0.0 +version: 0.6.0.0 github: "codedownio/aeson-typescript" license: BSD3 category: Text, Web, JSON From 903774c23902adb714662758bfc8b836f26a057e Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Thu, 22 Jun 2023 21:05:35 -0700 Subject: [PATCH 24/76] ci: try specifying stack resolver properly --- .github/workflows/aeson-typescript.yml | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/.github/workflows/aeson-typescript.yml b/.github/workflows/aeson-typescript.yml index 6577565..9290bd6 100644 --- a/.github/workflows/aeson-typescript.yml +++ b/.github/workflows/aeson-typescript.yml @@ -67,27 +67,33 @@ jobs: strategy: fail-fast: false matrix: - ghc: - - "8.8.4" - - "8.10.7" - - "9.0.2" - - "9.2.7" - - "9.4.4" + include: + - ghc: "8.8.4" + resolver: "lts-16.31" + - ghc: "8.10.7" + resolver: "lts-18.28" + - ghc: "9.0.2" + resolver: "lts-19.33" + - ghc: "9.2.8" + resolver: "lts-20.26" + - ghc: "9.4.5" + resolver: "lts-21.0" steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: haskell/actions/setup@v2 name: Setup Haskell Stack with: ghc-version: ${{ matrix.ghc }} + enable-stack: true stack-version: "latest" - uses: actions/cache@v1 name: Cache ~/.stack with: path: ~/.stack - key: ${{ runner.os }}-${{ matrix.ghc }}-stack + key: ${{ runner.os }}-${{ matrix.ghc }}-${{ matrix.resolver }}-stack - uses: actions/setup-node@v3 with: @@ -98,8 +104,8 @@ jobs: - name: Build run: | - stack build --system-ghc --test --bench --no-run-tests --no-run-benchmarks + stack build --resolver ${{matrix.resolver}} --system-ghc --test --bench --no-run-tests --no-run-benchmarks - name: Test run: | - stack test --system-ghc + stack test --resolver ${{matrix.resolver}} --system-ghc From 0f4b0d3f22c95601a99859e712ee2279bd38b948 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Wed, 28 Jun 2023 04:43:42 -0700 Subject: [PATCH 25/76] Modernize CI by using explicit stack.yaml files --- .github/workflows/aeson-typescript.yml | 29 +++++++++++--------------- stack-8.10.7.yaml | 5 +++++ stack-8.10.7.yaml.lock | 12 +++++++++++ stack-9.0.2.yaml | 5 +++++ stack-9.0.2.yaml.lock | 12 +++++++++++ stack-9.2.8.yaml | 5 +++++ stack-9.2.8.yaml.lock | 12 +++++++++++ stack-9.4.5.yaml | 5 +++++ stack-9.4.5.yaml.lock | 12 +++++++++++ stack.yaml | 5 +---- stack.yaml.lock | 8 +++---- 11 files changed, 85 insertions(+), 25 deletions(-) create mode 100644 stack-8.10.7.yaml create mode 100644 stack-8.10.7.yaml.lock create mode 100644 stack-9.0.2.yaml create mode 100644 stack-9.0.2.yaml.lock create mode 100644 stack-9.2.8.yaml create mode 100644 stack-9.2.8.yaml.lock create mode 100644 stack-9.4.5.yaml create mode 100644 stack-9.4.5.yaml.lock diff --git a/.github/workflows/aeson-typescript.yml b/.github/workflows/aeson-typescript.yml index 9290bd6..f660f16 100644 --- a/.github/workflows/aeson-typescript.yml +++ b/.github/workflows/aeson-typescript.yml @@ -13,16 +13,11 @@ jobs: matrix: os: [ubuntu-latest, macOS-latest] ghc: - - "8.6.5" - - "8.8.4" - "8.10.7" - "9.0.2" - - "9.2.7" - - "9.4.4" - - "9.6.1" - # exclude: - # - os: macOS-latest - # ghc: 8.8.3 + - "9.2.8" + - "9.4.5" + - "9.6.2" steps: - uses: actions/checkout@v2 @@ -68,16 +63,16 @@ jobs: fail-fast: false matrix: include: - - ghc: "8.8.4" - resolver: "lts-16.31" - ghc: "8.10.7" - resolver: "lts-18.28" + yaml: "stack-8.10.7" - ghc: "9.0.2" - resolver: "lts-19.33" + yaml: "stack-9.0.2.yaml" - ghc: "9.2.8" - resolver: "lts-20.26" + yaml: "stack-9.2.8.yaml" - ghc: "9.4.5" - resolver: "lts-21.0" + yaml: "stack-9.4.5.yaml" + - ghc: "9.6.2" + yaml: "stack.yaml" steps: - uses: actions/checkout@v3 @@ -93,7 +88,7 @@ jobs: name: Cache ~/.stack with: path: ~/.stack - key: ${{ runner.os }}-${{ matrix.ghc }}-${{ matrix.resolver }}-stack + key: ${{ runner.os }}-${{ matrix.ghc }}-${{ matrix.yaml }} - uses: actions/setup-node@v3 with: @@ -104,8 +99,8 @@ jobs: - name: Build run: | - stack build --resolver ${{matrix.resolver}} --system-ghc --test --bench --no-run-tests --no-run-benchmarks + stack build --stack-yaml ${{matrix.yaml}} --system-ghc --test --bench --no-run-tests --no-run-benchmarks - name: Test run: | - stack test --resolver ${{matrix.resolver}} --system-ghc + stack test --stack-yaml ${{matrix.yaml}} --system-ghc diff --git a/stack-8.10.7.yaml b/stack-8.10.7.yaml new file mode 100644 index 0000000..2b383ea --- /dev/null +++ b/stack-8.10.7.yaml @@ -0,0 +1,5 @@ + +resolver: lts-18.28 + +packages: +- . diff --git a/stack-8.10.7.yaml.lock b/stack-8.10.7.yaml.lock new file mode 100644 index 0000000..da10c3e --- /dev/null +++ b/stack-8.10.7.yaml.lock @@ -0,0 +1,12 @@ +# This file was autogenerated by Stack. +# You should not edit this file by hand. +# For more information, please see the documentation at: +# https://docs.haskellstack.org/en/stable/lock_files + +packages: [] +snapshots: +- completed: + sha256: 428ec8d5ce932190d3cbe266b9eb3c175cd81e984babf876b64019e2cbe4ea68 + size: 590100 + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/18/28.yaml + original: lts-18.28 diff --git a/stack-9.0.2.yaml b/stack-9.0.2.yaml new file mode 100644 index 0000000..fe2c91a --- /dev/null +++ b/stack-9.0.2.yaml @@ -0,0 +1,5 @@ + +resolver: lts-19.33 + +packages: +- . diff --git a/stack-9.0.2.yaml.lock b/stack-9.0.2.yaml.lock new file mode 100644 index 0000000..d79c369 --- /dev/null +++ b/stack-9.0.2.yaml.lock @@ -0,0 +1,12 @@ +# This file was autogenerated by Stack. +# You should not edit this file by hand. +# For more information, please see the documentation at: +# https://docs.haskellstack.org/en/stable/lock_files + +packages: [] +snapshots: +- completed: + sha256: 6d1532d40621957a25bad5195bfca7938e8a06d923c91bc52aa0f3c41181f2d4 + size: 619204 + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/19/33.yaml + original: lts-19.33 diff --git a/stack-9.2.8.yaml b/stack-9.2.8.yaml new file mode 100644 index 0000000..028d2f7 --- /dev/null +++ b/stack-9.2.8.yaml @@ -0,0 +1,5 @@ + +resolver: lts-20.26 + +packages: +- . diff --git a/stack-9.2.8.yaml.lock b/stack-9.2.8.yaml.lock new file mode 100644 index 0000000..ea5a850 --- /dev/null +++ b/stack-9.2.8.yaml.lock @@ -0,0 +1,12 @@ +# This file was autogenerated by Stack. +# You should not edit this file by hand. +# For more information, please see the documentation at: +# https://docs.haskellstack.org/en/stable/lock_files + +packages: [] +snapshots: +- completed: + sha256: 5a59b2a405b3aba3c00188453be172b85893cab8ebc352b1ef58b0eae5d248a2 + size: 650475 + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/20/26.yaml + original: lts-20.26 diff --git a/stack-9.4.5.yaml b/stack-9.4.5.yaml new file mode 100644 index 0000000..a05c602 --- /dev/null +++ b/stack-9.4.5.yaml @@ -0,0 +1,5 @@ + +resolver: lts-21.0 + +packages: +- . diff --git a/stack-9.4.5.yaml.lock b/stack-9.4.5.yaml.lock new file mode 100644 index 0000000..ad1be6c --- /dev/null +++ b/stack-9.4.5.yaml.lock @@ -0,0 +1,12 @@ +# This file was autogenerated by Stack. +# You should not edit this file by hand. +# For more information, please see the documentation at: +# https://docs.haskellstack.org/en/stable/lock_files + +packages: [] +snapshots: +- completed: + sha256: 1867d84255dff8c87373f5dd03e5a5cb1c10a99587e26c8793e750c54e83ffdc + size: 639139 + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/21/0.yaml + original: lts-21.0 diff --git a/stack.yaml b/stack.yaml index 677d2f3..4d5471e 100644 --- a/stack.yaml +++ b/stack.yaml @@ -1,8 +1,5 @@ -resolver: lts-20.15 +resolver: nightly-2023-06-27 packages: - . - -# ghc-options: -# "$locals": -fwrite-ide-info diff --git a/stack.yaml.lock b/stack.yaml.lock index 79b93cf..204a9e1 100644 --- a/stack.yaml.lock +++ b/stack.yaml.lock @@ -6,7 +6,7 @@ packages: [] snapshots: - completed: - sha256: 5d1df60a0aaf19ab42eb79d5ca01ab812318a96be3925559e902e1bfd8cac569 - size: 649582 - url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/20/15.yaml - original: lts-20.15 + sha256: 7cb8c85885c204500c43790ea0e7802a6f8bdaf1a27309de33cbd8898f2c1c00 + size: 531943 + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/nightly/2023/6/27.yaml + original: nightly-2023-06-27 From 968a95bc695129209586b5c70ab07cc60003fdd9 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Wed, 28 Jun 2023 04:43:57 -0700 Subject: [PATCH 26/76] Fix Aeson CPP --- test/TestBoilerplate.hs | 2 +- test/Util/Aeson.hs | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/test/TestBoilerplate.hs b/test/TestBoilerplate.hs index 5b4ad98..3b45997 100644 --- a/test/TestBoilerplate.hs +++ b/test/TestBoilerplate.hs @@ -117,7 +117,7 @@ testDeclarations testName aesonOptions = do , (getTypeScriptType (Proxy :: Proxy Optional), A.encode (Optional { optionalInt = Just 1 })) , (getTypeScriptType (Proxy :: Proxy AesonTypes), A.encode (AesonTypes { - aesonValue = A.object [("foo" :: A.Key, A.Number 42)] + aesonValue = A.object [("foo" :: AesonKey, A.Number 42)] , aesonObject = aesonFromList [("foo", A.Number 42)] })) diff --git a/test/Util/Aeson.hs b/test/Util/Aeson.hs index b38b900..3954546 100644 --- a/test/Util/Aeson.hs +++ b/test/Util/Aeson.hs @@ -8,8 +8,15 @@ import qualified Data.Aeson.KeyMap as KM aesonFromList :: [(K.Key, v)] -> KM.KeyMap v aesonFromList = KM.fromList + +type AesonKey = A.Key #else +import Data.Aeson as A import Data.HashMap.Strict as HM +import Data.Text as T +aesonFromList :: [(T.Text, Value)] -> HM.HashMap Text A.Value aesonFromList = HM.fromList + +type AesonKey = Text #endif From 870982a53f939f29754138ff29da45b395019cc7 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Wed, 28 Jun 2023 04:54:10 -0700 Subject: [PATCH 27/76] Fix a yaml path --- .github/workflows/aeson-typescript.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/aeson-typescript.yml b/.github/workflows/aeson-typescript.yml index f660f16..343791a 100644 --- a/.github/workflows/aeson-typescript.yml +++ b/.github/workflows/aeson-typescript.yml @@ -64,7 +64,7 @@ jobs: matrix: include: - ghc: "8.10.7" - yaml: "stack-8.10.7" + yaml: "stack-8.10.7.yaml" - ghc: "9.0.2" yaml: "stack-9.0.2.yaml" - ghc: "9.2.8" From a80b62c1906a82cb9853d0f647b4d6ec6ef19195 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Wed, 28 Jun 2023 04:54:35 -0700 Subject: [PATCH 28/76] Another Util/Aeson.hs fix --- test/Util/Aeson.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Util/Aeson.hs b/test/Util/Aeson.hs index 3954546..38aded1 100644 --- a/test/Util/Aeson.hs +++ b/test/Util/Aeson.hs @@ -9,7 +9,7 @@ import qualified Data.Aeson.KeyMap as KM aesonFromList :: [(K.Key, v)] -> KM.KeyMap v aesonFromList = KM.fromList -type AesonKey = A.Key +type AesonKey = K.Key #else import Data.Aeson as A import Data.HashMap.Strict as HM From c8e64b65aec4247d5942d5fe0006ac6d525f4efe Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Wed, 28 Jun 2023 05:05:58 -0700 Subject: [PATCH 29/76] Improve output when TSC check fails --- test/Util.hs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/test/Util.hs b/test/Util.hs index 88a088d..8436f05 100644 --- a/test/Util.hs +++ b/test/Util.hs @@ -70,12 +70,19 @@ testTypeCheckDeclarations tsDeclarations typesAndVals = withSystemTempDirectory writeFile tsFile contents tsc <- getTSC - (code, output, _err) <- readProcessWithExitCode tsc ["--strict", "--noEmit", "--skipLibCheck", "--traceResolution", "--noResolve", tsFile] "" + (code, sout, serr) <- readProcessWithExitCode tsc ["--strict", "--noEmit", "--skipLibCheck", "--traceResolution", "--noResolve", tsFile] "" - when (code /= ExitSuccess) $ do - error [i|TSC check failed: #{output}. File contents were\n\n#{contents}|] + when (code /= ExitSuccess) $ + error [__i|TSC check failed. + File contents: + #{contents} - return () + Stdout: + #{sout} + + Stderr: + #{serr} + |] ensureTSCExists :: IO () From d7deffad3d9f6652ef820be7eca71b8f77b0dee9 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Wed, 28 Jun 2023 05:07:56 -0700 Subject: [PATCH 30/76] Try fixing cabal tests in CI --- .github/workflows/aeson-typescript.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/aeson-typescript.yml b/.github/workflows/aeson-typescript.yml index 343791a..9d31265 100644 --- a/.github/workflows/aeson-typescript.yml +++ b/.github/workflows/aeson-typescript.yml @@ -33,16 +33,15 @@ jobs: run: | cabal freeze - - uses: actions/cache@v1 + - uses: actions/cache@v3 name: Cache ~/.cabal/store with: path: ${{ steps.setup-haskell-cabal.outputs.cabal-store }} key: ${{ runner.os }}-${{ matrix.ghc }}-${{ hashFiles('cabal.project.freeze') }} - # Install TSC - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v3 with: - node-version: '12' + node-version: '16' - name: Install TSC run: | npm install -g typescript @@ -84,7 +83,7 @@ jobs: enable-stack: true stack-version: "latest" - - uses: actions/cache@v1 + - uses: actions/cache@v3 name: Cache ~/.stack with: path: ~/.stack From 40674f9628732eb8afd5918373debb4a764bf3d8 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Thu, 12 Oct 2023 21:24:27 -0700 Subject: [PATCH 31/76] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4cdf469..249e3b5 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,6 @@ Now you can generate the types by running `stack runhaskell tsdef/Main.hs > type # See also -If you want a much more opinionated web framework for generating APIs, check out [servant](http://haskell-servant.readthedocs.io/en/stable/). (Although it doesn't seem to support TypeScript client generation at the moment.) +If you want a more opinionated web framework for generating APIs, check out [servant](http://haskell-servant.readthedocs.io/en/stable/). If you use Servant, you may enjoy [servant-typescript](https://github.com/codedownio/servant-typescript), which is based on `aeson-typescript`! It also has the advantage of magically collecting all the types used in your API, so you don't have to list them out manually. For another very powerful framework that can generate TypeScript client code based on an API specification, see [Swagger/OpenAPI](https://github.com/swagger-api/swagger-codegen). From 0d0f4b2d54f0efa16e0af1e47ef5e6353a6b8250 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Thu, 12 Oct 2023 21:25:20 -0700 Subject: [PATCH 32/76] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 249e3b5..227be17 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,6 @@ Now you can generate the types by running `stack runhaskell tsdef/Main.hs > type # See also -If you want a more opinionated web framework for generating APIs, check out [servant](http://haskell-servant.readthedocs.io/en/stable/). If you use Servant, you may enjoy [servant-typescript](https://github.com/codedownio/servant-typescript), which is based on `aeson-typescript`! It also has the advantage of magically collecting all the types used in your API, so you don't have to list them out manually. +If you want a more opinionated web framework for generating APIs, check out [servant](http://haskell-servant.readthedocs.io/en/stable/). If you use Servant, you may enjoy [servant-typescript](https://github.com/codedownio/servant-typescript), which is based on `aeson-typescript`! This companion package also has the advantage of magically collecting all the types used in your API, so you don't have to list them out manually. For another very powerful framework that can generate TypeScript client code based on an API specification, see [Swagger/OpenAPI](https://github.com/swagger-api/swagger-codegen). From 0c62a9291dd5e69e40d0682900a759b5498a9029 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Mon, 13 Nov 2023 17:25:32 -0800 Subject: [PATCH 33/76] Apply typeNameModifier to fields within interfaces --- CHANGELOG.md | 3 +++ src/Data/Aeson/TypeScript/Formatting.hs | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d7aba8..720c2c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Change log +## Unreleased + +* Apply `typeNameModifier` to type names emitted on the RHS of fields within interfaces, for consistency. ## 0.6.0.0 diff --git a/src/Data/Aeson/TypeScript/Formatting.hs b/src/Data/Aeson/TypeScript/Formatting.hs index b4e4c77..c6051fc 100644 --- a/src/Data/Aeson/TypeScript/Formatting.hs +++ b/src/Data/Aeson/TypeScript/Formatting.hs @@ -41,6 +41,9 @@ formatTSDeclaration (FormattingOptions {..}) (TSInterfaceDeclaration interfaceNa ls = T.intercalate "\n" $ [indentTo numIndentSpaces (T.pack (formatTSField member <> ";")) | member <- members] modifiedInterfaceName = (\(li, name) -> li <> interfaceNameModifier name) . splitAt 1 $ interfaceName + formatTSField :: TSField -> String + formatTSField (TSField optional name typ maybeDoc) = makeDocPrefix maybeDoc <> [i|#{name}#{if optional then ("?" :: String) else ""}: #{typeNameModifier typ}|] + formatTSDeclaration _ (TSRawDeclaration text) = text indentTo :: Int -> T.Text -> T.Text @@ -89,9 +92,6 @@ validateFormattingOptions options@FormattingOptions{..} decls -- Units (data U = U) contain two declarations, and thus are invalid isPlainSumType ds = (not . any isInterface $ ds) && length ds == 1 -formatTSField :: TSField -> String -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 -> "" From 9465d8dea3488450a69220dc919c094fff8a3e07 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Mon, 13 Nov 2023 17:33:39 -0800 Subject: [PATCH 34/76] Update stack.yaml files/GHC versions --- .github/workflows/aeson-typescript.yml | 10 +++++----- stack-9.4.5.yaml | 5 ----- stack-9.4.7.yaml | 5 +++++ stack-9.4.5.yaml.lock => stack-9.4.7.yaml.lock | 8 ++++---- stack.yaml | 2 +- stack.yaml.lock | 8 ++++---- 6 files changed, 19 insertions(+), 19 deletions(-) delete mode 100644 stack-9.4.5.yaml create mode 100644 stack-9.4.7.yaml rename stack-9.4.5.yaml.lock => stack-9.4.7.yaml.lock (65%) diff --git a/.github/workflows/aeson-typescript.yml b/.github/workflows/aeson-typescript.yml index 9d31265..9c63d79 100644 --- a/.github/workflows/aeson-typescript.yml +++ b/.github/workflows/aeson-typescript.yml @@ -16,8 +16,8 @@ jobs: - "8.10.7" - "9.0.2" - "9.2.8" - - "9.4.5" - - "9.6.2" + - "9.4.7" + - "9.6.3" steps: - uses: actions/checkout@v2 @@ -68,9 +68,9 @@ jobs: yaml: "stack-9.0.2.yaml" - ghc: "9.2.8" yaml: "stack-9.2.8.yaml" - - ghc: "9.4.5" - yaml: "stack-9.4.5.yaml" - - ghc: "9.6.2" + - ghc: "9.4.7" + yaml: "stack-9.4.7.yaml" + - ghc: "9.6.3" yaml: "stack.yaml" steps: diff --git a/stack-9.4.5.yaml b/stack-9.4.5.yaml deleted file mode 100644 index a05c602..0000000 --- a/stack-9.4.5.yaml +++ /dev/null @@ -1,5 +0,0 @@ - -resolver: lts-21.0 - -packages: -- . diff --git a/stack-9.4.7.yaml b/stack-9.4.7.yaml new file mode 100644 index 0000000..13994e4 --- /dev/null +++ b/stack-9.4.7.yaml @@ -0,0 +1,5 @@ + +resolver: lts-21.20 + +packages: +- . diff --git a/stack-9.4.5.yaml.lock b/stack-9.4.7.yaml.lock similarity index 65% rename from stack-9.4.5.yaml.lock rename to stack-9.4.7.yaml.lock index ad1be6c..1b8f599 100644 --- a/stack-9.4.5.yaml.lock +++ b/stack-9.4.7.yaml.lock @@ -6,7 +6,7 @@ packages: [] snapshots: - completed: - sha256: 1867d84255dff8c87373f5dd03e5a5cb1c10a99587e26c8793e750c54e83ffdc - size: 639139 - url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/21/0.yaml - original: lts-21.0 + sha256: 5921ddc75f5dd3f197fbc32e1e5676895a8e7b971d4f82ef6b556657801dd18a + size: 640054 + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/21/20.yaml + original: lts-21.20 diff --git a/stack.yaml b/stack.yaml index 4d5471e..bfc9a75 100644 --- a/stack.yaml +++ b/stack.yaml @@ -1,5 +1,5 @@ -resolver: nightly-2023-06-27 +resolver: nightly-2023-11-14 packages: - . diff --git a/stack.yaml.lock b/stack.yaml.lock index 204a9e1..dd4da80 100644 --- a/stack.yaml.lock +++ b/stack.yaml.lock @@ -6,7 +6,7 @@ packages: [] snapshots: - completed: - sha256: 7cb8c85885c204500c43790ea0e7802a6f8bdaf1a27309de33cbd8898f2c1c00 - size: 531943 - url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/nightly/2023/6/27.yaml - original: nightly-2023-06-27 + sha256: 0eaacfc9de6b0ab46ab6026166d2ba7718ab06a8612086b3ee21d7667e682df0 + size: 698974 + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/nightly/2023/11/14.yaml + original: nightly-2023-11-14 From 7cd51838d0c69fe299f52b8ce496d94795898a57 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Mon, 13 Nov 2023 17:45:44 -0800 Subject: [PATCH 35/76] Undo 0c62a92 --- src/Data/Aeson/TypeScript/Formatting.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Data/Aeson/TypeScript/Formatting.hs b/src/Data/Aeson/TypeScript/Formatting.hs index c6051fc..fdaad6e 100644 --- a/src/Data/Aeson/TypeScript/Formatting.hs +++ b/src/Data/Aeson/TypeScript/Formatting.hs @@ -42,7 +42,7 @@ formatTSDeclaration (FormattingOptions {..}) (TSInterfaceDeclaration interfaceNa modifiedInterfaceName = (\(li, name) -> li <> interfaceNameModifier name) . splitAt 1 $ interfaceName formatTSField :: TSField -> String - formatTSField (TSField optional name typ maybeDoc) = makeDocPrefix maybeDoc <> [i|#{name}#{if optional then ("?" :: String) else ""}: #{typeNameModifier typ}|] + formatTSField (TSField optional name typ maybeDoc) = makeDocPrefix maybeDoc <> [i|#{name}#{if optional then ("?" :: String) else ""}: #{typ}|] formatTSDeclaration _ (TSRawDeclaration text) = text From 70af53a251b854c3767e7407226e197716a7f43f Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Mon, 13 Nov 2023 17:54:42 -0800 Subject: [PATCH 36/76] Remove changelog entry until we fix this for real --- CHANGELOG.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 720c2c8..79f651a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,8 +2,6 @@ ## Unreleased -* Apply `typeNameModifier` to type names emitted on the RHS of fields within interfaces, for consistency. - ## 0.6.0.0 * New word instances: Word, Word16, Word32, Word64 From 1afccfe6318bea005f6fe319bcda52ee8d09b7a2 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Thu, 30 Nov 2023 20:35:50 -0700 Subject: [PATCH 37/76] Add more enum formatting tests --- test/Formatting.hs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/test/Formatting.hs b/test/Formatting.hs index d035c4e..b4953e2 100644 --- a/test/Formatting.hs +++ b/test/Formatting.hs @@ -14,6 +14,12 @@ import Test.Hspec data D = S | F deriving (Eq, Show) $(deriveTypeScript defaultOptions ''D) +data D2 = S2 | F2 deriving (Eq, Show) +$(deriveTypeScript defaultOptions ''D2) + +data Unit = U deriving (Eq, Show) +$(deriveTypeScript defaultOptions ''Unit) + data PrimeInType' = PrimeInType $(deriveTypeScript defaultOptions ''PrimeInType') @@ -47,11 +53,21 @@ tests = describe "Formatting" $ do formatTSDeclarations' defaultFormattingOptions (getTypeScriptDeclarations @D Proxy) `shouldBe` [i|type D = "S" | "F";|] - describe "and the Enum format option is set" $ + describe "and the Enum format option is set" $ do it "should generate a TS Enum" $ formatTSDeclarations' (defaultFormattingOptions { typeAlternativesFormat = Enum }) (getTypeScriptDeclarations @D Proxy) `shouldBe` [i|enum D { S, F }|] + it "should generate a TS Enum with multiple" $ + formatTSDeclarations' (defaultFormattingOptions { typeAlternativesFormat = Enum }) (getTypeScriptDeclarations @D Proxy <> getTypeScriptDeclarations @D2 Proxy) `shouldBe` + [__i|enum D { S, F } + + enum D2 { S2, F2 }|] + + it "should generate a TS Enum from unit" $ + formatTSDeclarations' (defaultFormattingOptions { typeAlternativesFormat = Enum }) (getTypeScriptDeclarations @Unit Proxy) `shouldBe` + [__i|enum Unit { U }|] + 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` From a7d273e80bf6b5aeeb827deab54d1d1f7d4f3213 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Thu, 30 Nov 2023 20:36:16 -0700 Subject: [PATCH 38/76] Get rid of validateFormattingOptions --- src/Data/Aeson/TypeScript/Formatting.hs | 34 +++++++------------------ 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/src/Data/Aeson/TypeScript/Formatting.hs b/src/Data/Aeson/TypeScript/Formatting.hs index fdaad6e..f2464e4 100644 --- a/src/Data/Aeson/TypeScript/Formatting.hs +++ b/src/Data/Aeson/TypeScript/Formatting.hs @@ -25,13 +25,13 @@ formatTSDeclaration (FormattingOptions {..}) (TSTypeAlternatives name genericVar where mainDeclaration = case typeAlternativesFormat of Enum -> [i|#{exportPrefix exportMode}enum #{typeNameModifier name} { #{alternativesEnum} }|] - EnumWithType -> [i|#{exportPrefix exportMode}enum #{typeNameModifier name} { #{alternativesEnumWithType} }#{enumType}|] + EnumWithType -> [i|#{exportPrefix exportMode}enum #{typeNameModifier name}Enum { #{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 + enumType = [i|\n\ntype #{name} = keyof typeof #{typeNameModifier name}Enum;|] :: T.Text toEnumName = T.replace "\"" "" formatTSDeclaration (FormattingOptions {..}) (TSInterfaceDeclaration interfaceName genericVariables (filter (not . isNoEmitTypeScriptField) -> members) maybeDoc) = @@ -57,18 +57,16 @@ 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 allDeclarations = - declarations & fmap (T.pack . formatTSDeclaration (validateFormattingOptions options declarations)) + declarations & fmap (T.pack . formatTSDeclaration options) & 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 + removedDeclarationNames = mapMaybe getDeclarationName (filter isNoEmitTypeScriptDeclaration allDeclarations) + where + getDeclarationName :: TSDeclaration -> Maybe String + getDeclarationName (TSInterfaceDeclaration {..}) = Just interfaceName + getDeclarationName (TSTypeAlternatives {..}) = Just typeName + _ = Nothing removeReferencesToRemovedNames :: [String] -> TSDeclaration -> TSDeclaration removeReferencesToRemovedNames removedNames decl@(TSTypeAlternatives {..}) = decl { alternativeTypes = [x | x <- alternativeTypes, not (x `L.elem` removedNames)] } @@ -78,20 +76,6 @@ formatTSDeclarations' options allDeclarations = & filter (not . isNoEmitTypeScriptDeclaration) & fmap (removeReferencesToRemovedNames removedDeclarationNames) -validateFormattingOptions :: FormattingOptions -> [TSDeclaration] -> FormattingOptions -validateFormattingOptions options@FormattingOptions{..} decls - | typeAlternativesFormat == Enum && isPlainSumType decls = options - | typeAlternativesFormat == EnumWithType && isPlainSumType decls = options { typeNameModifier = flip (<>) "Enum" } - | otherwise = options { typeAlternativesFormat = TypeAlias } - where - isInterface :: TSDeclaration -> Bool - isInterface TSInterfaceDeclaration{} = True - isInterface _ = False - - -- Plain sum types have only one declaration with multiple alternatives - -- Units (data U = U) contain two declarations, and thus are invalid - isPlainSumType ds = (not . any isInterface $ ds) && length ds == 1 - makeDocPrefix :: Maybe String -> String makeDocPrefix maybeDoc = case maybeDoc of Nothing -> "" From 07bc4923850d0b12b14496f132ee8ffdc4d215f3 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Thu, 30 Nov 2023 20:39:22 -0700 Subject: [PATCH 39/76] Comment Unit test for now --- test/Formatting.hs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/test/Formatting.hs b/test/Formatting.hs index b4953e2..35ab299 100644 --- a/test/Formatting.hs +++ b/test/Formatting.hs @@ -5,6 +5,7 @@ module Formatting (tests) where import Control.Exception import Data.Aeson (defaultOptions) +import Data.Aeson.TH import Data.Aeson.TypeScript.TH import Data.Proxy import Data.String.Interpolate @@ -19,6 +20,7 @@ $(deriveTypeScript defaultOptions ''D2) data Unit = U deriving (Eq, Show) $(deriveTypeScript defaultOptions ''Unit) +$(deriveJSON defaultOptions ''Unit) data PrimeInType' = PrimeInType $(deriveTypeScript defaultOptions ''PrimeInType') @@ -64,9 +66,9 @@ tests = describe "Formatting" $ do enum D2 { S2, F2 }|] - it "should generate a TS Enum from unit" $ - formatTSDeclarations' (defaultFormattingOptions { typeAlternativesFormat = Enum }) (getTypeScriptDeclarations @Unit Proxy) `shouldBe` - [__i|enum Unit { U }|] + -- it "should generate a TS Enum from unit" $ + -- formatTSDeclarations' (defaultFormattingOptions { typeAlternativesFormat = Enum }) (getTypeScriptDeclarations @Unit Proxy) `shouldBe` + -- [__i|enum Unit { U }|] describe "and the EnumWithType format option is set" $ it "should generate a TS Enum with a type declaration" $ From 5afd1649ac1dcfed2a1a92312c3c182a20b0cf83 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Thu, 30 Nov 2023 21:58:59 -0700 Subject: [PATCH 40/76] Fix bug in getDeclarationName --- src/Data/Aeson/TypeScript/Formatting.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Data/Aeson/TypeScript/Formatting.hs b/src/Data/Aeson/TypeScript/Formatting.hs index f2464e4..50a9544 100644 --- a/src/Data/Aeson/TypeScript/Formatting.hs +++ b/src/Data/Aeson/TypeScript/Formatting.hs @@ -66,7 +66,7 @@ formatTSDeclarations' options allDeclarations = getDeclarationName :: TSDeclaration -> Maybe String getDeclarationName (TSInterfaceDeclaration {..}) = Just interfaceName getDeclarationName (TSTypeAlternatives {..}) = Just typeName - _ = Nothing + getDeclarationName _ = Nothing removeReferencesToRemovedNames :: [String] -> TSDeclaration -> TSDeclaration removeReferencesToRemovedNames removedNames decl@(TSTypeAlternatives {..}) = decl { alternativeTypes = [x | x <- alternativeTypes, not (x `L.elem` removedNames)] } From 7933c644a485c07b7f0fc90daddd2ee59f6039f1 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Thu, 30 Nov 2023 21:59:31 -0700 Subject: [PATCH 41/76] Fix a couple warnings --- src/Data/Aeson/TypeScript/Formatting.hs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Data/Aeson/TypeScript/Formatting.hs b/src/Data/Aeson/TypeScript/Formatting.hs index 50a9544..5590433 100644 --- a/src/Data/Aeson/TypeScript/Formatting.hs +++ b/src/Data/Aeson/TypeScript/Formatting.hs @@ -42,7 +42,7 @@ formatTSDeclaration (FormattingOptions {..}) (TSInterfaceDeclaration interfaceNa modifiedInterfaceName = (\(li, name) -> li <> interfaceNameModifier name) . splitAt 1 $ interfaceName formatTSField :: TSField -> String - formatTSField (TSField optional name typ maybeDoc) = makeDocPrefix maybeDoc <> [i|#{name}#{if optional then ("?" :: String) else ""}: #{typ}|] + formatTSField (TSField optional name typ maybeDoc') = makeDocPrefix maybeDoc' <> [i|#{name}#{if optional then ("?" :: String) else ""}: #{typ}|] formatTSDeclaration _ (TSRawDeclaration text) = text @@ -93,9 +93,11 @@ getGenericBrackets xs = [i|<#{T.intercalate ", " (fmap T.pack xs)}>|] noEmitTypeScriptAnnotation :: String noEmitTypeScriptAnnotation = "@no-emit-typescript" +isNoEmitTypeScriptField :: TSField -> Bool isNoEmitTypeScriptField (TSField {fieldDoc=(Just doc)}) = noEmitTypeScriptAnnotation `L.isInfixOf` doc isNoEmitTypeScriptField _ = False +isNoEmitTypeScriptDeclaration :: TSDeclaration -> Bool isNoEmitTypeScriptDeclaration (TSInterfaceDeclaration {interfaceDoc=(Just doc)}) = noEmitTypeScriptAnnotation `L.isInfixOf` doc isNoEmitTypeScriptDeclaration (TSTypeAlternatives {typeDoc=(Just doc)}) = noEmitTypeScriptAnnotation `L.isInfixOf` doc isNoEmitTypeScriptDeclaration _ = False From 2e5c1234e770877ce62a18e23a8dc811ade25079 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Thu, 30 Nov 2023 21:59:53 -0700 Subject: [PATCH 42/76] Add a better check for enum mode --- aeson-typescript.cabal | 3 ++- package.yaml | 1 + src/Data/Aeson/TypeScript/Formatting.hs | 28 ++++++++++++++++++++----- test/Formatting.hs | 10 ++++----- 4 files changed, 31 insertions(+), 11 deletions(-) diff --git a/aeson-typescript.cabal b/aeson-typescript.cabal index aead56b..139cbd6 100644 --- a/aeson-typescript.cabal +++ b/aeson-typescript.cabal @@ -1,6 +1,6 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.35.1. +-- This file has been generated from package.yaml by hpack version 0.36.0. -- -- see: https://github.com/sol/hpack @@ -67,6 +67,7 @@ library build-depends: aeson , base >=4.7 && <5 + , bytestring , containers , mtl , string-interpolate diff --git a/package.yaml b/package.yaml index 3821c55..a1e476d 100644 --- a/package.yaml +++ b/package.yaml @@ -35,6 +35,7 @@ tested-with: dependencies: - aeson - base >= 4.7 && < 5 +- bytestring - containers - mtl - string-interpolate diff --git a/src/Data/Aeson/TypeScript/Formatting.hs b/src/Data/Aeson/TypeScript/Formatting.hs index 5590433..fea6941 100644 --- a/src/Data/Aeson/TypeScript/Formatting.hs +++ b/src/Data/Aeson/TypeScript/Formatting.hs @@ -2,7 +2,9 @@ module Data.Aeson.TypeScript.Formatting where +import Data.Aeson as A import Data.Aeson.TypeScript.Types +import qualified Data.ByteString.Lazy.Char8 as BL8 import Data.Function ((&)) import qualified Data.List as L import Data.Maybe @@ -23,15 +25,31 @@ formatTSDeclaration :: FormattingOptions -> TSDeclaration -> String formatTSDeclaration (FormattingOptions {..}) (TSTypeAlternatives name genericVariables names maybeDoc) = makeDocPrefix maybeDoc <> mainDeclaration where - mainDeclaration = case typeAlternativesFormat of + mainDeclaration = case chooseTypeAlternativesFormat typeAlternativesFormat of Enum -> [i|#{exportPrefix exportMode}enum #{typeNameModifier name} { #{alternativesEnum} }|] + where + alternativesEnum = T.intercalate ", " $ [toEnumName entry | entry <- T.pack <$> names] EnumWithType -> [i|#{exportPrefix exportMode}enum #{typeNameModifier name}Enum { #{alternativesEnumWithType} }#{enumType}|] + where + alternativesEnumWithType = T.intercalate ", " $ [toEnumName entry <> "=" <> entry | entry <- T.pack <$> names] + enumType = [i|\n\ntype #{name} = keyof typeof #{typeNameModifier name}Enum;|] :: T.Text TypeAlias -> [i|#{exportPrefix exportMode}type #{typeNameModifier name}#{getGenericBrackets genericVariables} = #{alternatives};|] + where + alternatives = T.intercalate " | " (fmap T.pack names) + + -- Only allow certain formats if some checks pass + chooseTypeAlternativesFormat Enum + | all isDoubleQuotedString names = Enum + | otherwise = TypeAlias + chooseTypeAlternativesFormat EnumWithType + | all isDoubleQuotedString names = EnumWithType + | otherwise = TypeAlias + chooseTypeAlternativesFormat x = x + + isDoubleQuotedString s = case A.eitherDecode (BL8.pack s) of + Right (A.String _) -> True + _ -> False - 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}Enum;|] :: T.Text toEnumName = T.replace "\"" "" formatTSDeclaration (FormattingOptions {..}) (TSInterfaceDeclaration interfaceName genericVariables (filter (not . isNoEmitTypeScriptField) -> members) maybeDoc) = diff --git a/test/Formatting.hs b/test/Formatting.hs index 35ab299..ab3c770 100644 --- a/test/Formatting.hs +++ b/test/Formatting.hs @@ -5,7 +5,6 @@ module Formatting (tests) where import Control.Exception import Data.Aeson (defaultOptions) -import Data.Aeson.TH import Data.Aeson.TypeScript.TH import Data.Proxy import Data.String.Interpolate @@ -20,7 +19,6 @@ $(deriveTypeScript defaultOptions ''D2) data Unit = U deriving (Eq, Show) $(deriveTypeScript defaultOptions ''Unit) -$(deriveJSON defaultOptions ''Unit) data PrimeInType' = PrimeInType $(deriveTypeScript defaultOptions ''PrimeInType') @@ -66,9 +64,11 @@ tests = describe "Formatting" $ do enum D2 { S2, F2 }|] - -- it "should generate a TS Enum from unit" $ - -- formatTSDeclarations' (defaultFormattingOptions { typeAlternativesFormat = Enum }) (getTypeScriptDeclarations @Unit Proxy) `shouldBe` - -- [__i|enum Unit { U }|] + it "should generate a TS Enum from unit" $ + formatTSDeclarations' (defaultFormattingOptions { typeAlternativesFormat = Enum }) (getTypeScriptDeclarations @Unit Proxy) `shouldBe` + [__i|type Unit = IU; + + type IU = void[];|] describe "and the EnumWithType format option is set" $ it "should generate a TS Enum with a type declaration" $ From e39ae7c19e0a661fac351ec79f00795e45079cde Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Thu, 30 Nov 2023 22:08:45 -0700 Subject: [PATCH 43/76] Add CHANGELOG entry --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 79f651a..eaf6f71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +* Fix a bug which caused enum formatting mode to turn off when multiple declarations were provided (#41) + ## 0.6.0.0 * New word instances: Word, Word16, Word32, Word64 From 007e161fb59191010d175479bb8e4e216072db16 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Tue, 5 Dec 2023 19:13:45 -0800 Subject: [PATCH 44/76] Always include string in enums to match aeson --- src/Data/Aeson/TypeScript/Formatting.hs | 2 +- test/Formatting.hs | 25 +++++++++++++++++++------ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/Data/Aeson/TypeScript/Formatting.hs b/src/Data/Aeson/TypeScript/Formatting.hs index fea6941..9412b53 100644 --- a/src/Data/Aeson/TypeScript/Formatting.hs +++ b/src/Data/Aeson/TypeScript/Formatting.hs @@ -28,7 +28,7 @@ formatTSDeclaration (FormattingOptions {..}) (TSTypeAlternatives name genericVar mainDeclaration = case chooseTypeAlternativesFormat typeAlternativesFormat of Enum -> [i|#{exportPrefix exportMode}enum #{typeNameModifier name} { #{alternativesEnum} }|] where - alternativesEnum = T.intercalate ", " $ [toEnumName entry | entry <- T.pack <$> names] + alternativesEnum = T.intercalate ", " $ [toEnumName entry <> "=" <> entry | entry <- T.pack <$> names] EnumWithType -> [i|#{exportPrefix exportMode}enum #{typeNameModifier name}Enum { #{alternativesEnumWithType} }#{enumType}|] where alternativesEnumWithType = T.intercalate ", " $ [toEnumName entry <> "=" <> entry | entry <- T.pack <$> names] diff --git a/test/Formatting.hs b/test/Formatting.hs index ab3c770..a86f948 100644 --- a/test/Formatting.hs +++ b/test/Formatting.hs @@ -4,7 +4,7 @@ module Formatting (tests) where import Control.Exception -import Data.Aeson (defaultOptions) +import Data.Aeson (SumEncoding(UntaggedValue), defaultOptions, sumEncoding, tagSingleConstructors) import Data.Aeson.TypeScript.TH import Data.Proxy import Data.String.Interpolate @@ -17,9 +17,14 @@ $(deriveTypeScript defaultOptions ''D) data D2 = S2 | F2 deriving (Eq, Show) $(deriveTypeScript defaultOptions ''D2) +-- A.encode U --> "[]" data Unit = U deriving (Eq, Show) $(deriveTypeScript defaultOptions ''Unit) +-- A.encode UTagSingle --> "\"UTagSingle\"" +data UnitTagSingle = UTagSingle deriving (Eq, Show) +$(deriveTypeScript (defaultOptions { tagSingleConstructors = True, sumEncoding = UntaggedValue }) ''UnitTagSingle) + data PrimeInType' = PrimeInType $(deriveTypeScript defaultOptions ''PrimeInType') @@ -56,25 +61,33 @@ tests = describe "Formatting" $ do describe "and the Enum format option is set" $ do it "should generate a TS Enum" $ formatTSDeclarations' (defaultFormattingOptions { typeAlternativesFormat = Enum }) (getTypeScriptDeclarations @D Proxy) `shouldBe` - [i|enum D { S, F }|] + [i|enum D { S="S", F="F" }|] it "should generate a TS Enum with multiple" $ formatTSDeclarations' (defaultFormattingOptions { typeAlternativesFormat = Enum }) (getTypeScriptDeclarations @D Proxy <> getTypeScriptDeclarations @D2 Proxy) `shouldBe` - [__i|enum D { S, F } + [__i|enum D { S="S", F="F" } - enum D2 { S2, F2 }|] + enum D2 { S2="S2", F2="F2" }|] - it "should generate a TS Enum from unit" $ + it "should generate a normal type from Unit, singe tagSingleConstructors=False by default" $ formatTSDeclarations' (defaultFormattingOptions { typeAlternativesFormat = Enum }) (getTypeScriptDeclarations @Unit Proxy) `shouldBe` [__i|type Unit = IU; type IU = void[];|] - describe "and the EnumWithType format option is set" $ + it "should generate a suitable enum from UnitTagSingle" $ + formatTSDeclarations' (defaultFormattingOptions { typeAlternativesFormat = Enum }) (getTypeScriptDeclarations @UnitTagSingle Proxy) `shouldBe` + [__i|enum UnitTagSingle { UTagSingle="UTagSingle" }|] + + describe "and the EnumWithType format option is set" $ do 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;|] + it "should also work for UnitTagSingle" $ + formatTSDeclarations' (defaultFormattingOptions { typeAlternativesFormat = EnumWithType }) (getTypeScriptDeclarations @UnitTagSingle Proxy) `shouldBe` + [i|enum UnitTagSingleEnum { UTagSingle="UTagSingle" }\n\ntype UnitTagSingle = keyof typeof UnitTagSingleEnum;|] + describe "when the name has an apostrophe" $ do describe "in the type" $ do it "throws an error" $ do From 78bbf423ef445c9b76df4f41dc6a970596a19284 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Wed, 6 Dec 2023 15:56:51 -0800 Subject: [PATCH 45/76] Release 0.6.1.0 --- CHANGELOG.md | 3 +++ aeson-typescript.cabal | 2 +- package.yaml | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eaf6f71..a5020c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,10 @@ ## Unreleased +## 0.6.1.0 + * Fix a bug which caused enum formatting mode to turn off when multiple declarations were provided (#41) +* Fix some mismatch issues where an enum value doesn't match the desired string. ## 0.6.0.0 diff --git a/aeson-typescript.cabal b/aeson-typescript.cabal index 139cbd6..1caf1f6 100644 --- a/aeson-typescript.cabal +++ b/aeson-typescript.cabal @@ -5,7 +5,7 @@ cabal-version: 1.12 -- see: https://github.com/sol/hpack name: aeson-typescript -version: 0.6.0.0 +version: 0.6.1.0 synopsis: Generate TypeScript definition files from your ADTs description: Please see the README on Github at category: Text, Web, JSON diff --git a/package.yaml b/package.yaml index a1e476d..9de924e 100644 --- a/package.yaml +++ b/package.yaml @@ -1,5 +1,5 @@ name: aeson-typescript -version: 0.6.0.0 +version: 0.6.1.0 github: "codedownio/aeson-typescript" license: BSD3 category: Text, Web, JSON From 5802281709c959a6de339a7883dfd8082c673475 Mon Sep 17 00:00:00 2001 From: jjkv Date: Tue, 9 Jan 2024 15:26:38 -0500 Subject: [PATCH 46/76] export type variables 4 through 10 --- src/Data/Aeson/TypeScript/TH.hs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Data/Aeson/TypeScript/TH.hs b/src/Data/Aeson/TypeScript/TH.hs index 7cd0e49..4663a8f 100644 --- a/src/Data/Aeson/TypeScript/TH.hs +++ b/src/Data/Aeson/TypeScript/TH.hs @@ -137,6 +137,13 @@ module Data.Aeson.TypeScript.TH ( , T1(..) , T2(..) , T3(..) + , T4(..) + , T5(..) + , T6(..) + , T7(..) + , T8(..) + , T9(..) + , T10(..) , module Data.Aeson.TypeScript.Instances ) where From 02b279563d5780b3d07008a2690bf275c48d7185 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Wed, 10 Jan 2024 13:30:51 -0800 Subject: [PATCH 47/76] Update CHANGELOG --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a5020c4..729808f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 0.6.2.0 + +* Expose generic type constructors `T4` through `T10`. (We only exposed `T`, `T1`, `T2`, and `T3` before.) + ## 0.6.1.0 * Fix a bug which caused enum formatting mode to turn off when multiple declarations were provided (#41) From b834e60c91295afba6d7f92e87e57de19dc7cc49 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Wed, 10 Jan 2024 14:02:32 -0800 Subject: [PATCH 48/76] Bump version to 0.6.2.0 --- aeson-typescript.cabal | 2 +- package.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aeson-typescript.cabal b/aeson-typescript.cabal index 1caf1f6..6ae61ba 100644 --- a/aeson-typescript.cabal +++ b/aeson-typescript.cabal @@ -5,7 +5,7 @@ cabal-version: 1.12 -- see: https://github.com/sol/hpack name: aeson-typescript -version: 0.6.1.0 +version: 0.6.2.0 synopsis: Generate TypeScript definition files from your ADTs description: Please see the README on Github at category: Text, Web, JSON diff --git a/package.yaml b/package.yaml index 9de924e..8b52337 100644 --- a/package.yaml +++ b/package.yaml @@ -1,5 +1,5 @@ name: aeson-typescript -version: 0.6.1.0 +version: 0.6.2.0 github: "codedownio/aeson-typescript" license: BSD3 category: Text, Web, JSON From 517f14bde9544dbed826f1b7d6470aeb0b1e833e Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Fri, 26 Jan 2024 01:57:52 -0800 Subject: [PATCH 49/76] Add GHC 9.8 support and stack.yaml files for 9.8.1, 9.6.3 --- .github/workflows/aeson-typescript.yml | 5 ++++- CHANGELOG.md | 2 ++ src/Data/Aeson/TypeScript/Transform.hs | 4 +++- stack-9.6.3.yaml | 5 +++++ stack-9.6.3.yaml.lock | 12 ++++++++++++ stack-9.8.1.yaml | 5 +++++ stack-9.8.1.yaml.lock | 12 ++++++++++++ stack.yaml | 2 +- stack.yaml.lock | 8 ++++---- 9 files changed, 48 insertions(+), 7 deletions(-) create mode 100644 stack-9.6.3.yaml create mode 100644 stack-9.6.3.yaml.lock create mode 100644 stack-9.8.1.yaml create mode 100644 stack-9.8.1.yaml.lock diff --git a/.github/workflows/aeson-typescript.yml b/.github/workflows/aeson-typescript.yml index 9c63d79..e719130 100644 --- a/.github/workflows/aeson-typescript.yml +++ b/.github/workflows/aeson-typescript.yml @@ -18,6 +18,7 @@ jobs: - "9.2.8" - "9.4.7" - "9.6.3" + - "9.8.1" steps: - uses: actions/checkout@v2 @@ -71,7 +72,9 @@ jobs: - ghc: "9.4.7" yaml: "stack-9.4.7.yaml" - ghc: "9.6.3" - yaml: "stack.yaml" + yaml: "stack-9.6.3.yaml" + - ghc: "9.8.1" + yaml: "stack-9.8.1.yaml" steps: - uses: actions/checkout@v3 diff --git a/CHANGELOG.md b/CHANGELOG.md index 729808f..5cecaec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +* GHC 9.8 support + ## 0.6.2.0 * Expose generic type constructors `T4` through `T10`. (We only exposed `T`, `T1`, `T2`, and `T3` before.) diff --git a/src/Data/Aeson/TypeScript/Transform.hs b/src/Data/Aeson/TypeScript/Transform.hs index f5494e1..7e02879 100644 --- a/src/Data/Aeson/TypeScript/Transform.hs +++ b/src/Data/Aeson/TypeScript/Transform.hs @@ -45,7 +45,9 @@ transformTypeFamilies eo@(ExtraTypeScriptOptions {..}) (AppT (ConT name) typ) name' <- lift $ newName (nameBase typeFamilyName <> "'") f <- lift $ newName "f" -#if MIN_VERSION_template_haskell(2,17,0) +#if MIN_VERSION_template_haskell(2,21,0) + let inst1 = DataD [] name' [PlainTV f BndrReq] Nothing [] [] +#elif MIN_VERSION_template_haskell(2,17,0) let inst1 = DataD [] name' [PlainTV f ()] Nothing [] [] #else let inst1 = DataD [] name' [PlainTV f] Nothing [] [] diff --git a/stack-9.6.3.yaml b/stack-9.6.3.yaml new file mode 100644 index 0000000..fa1a123 --- /dev/null +++ b/stack-9.6.3.yaml @@ -0,0 +1,5 @@ + +resolver: lts-22.6 + +packages: +- . diff --git a/stack-9.6.3.yaml.lock b/stack-9.6.3.yaml.lock new file mode 100644 index 0000000..1b74b0a --- /dev/null +++ b/stack-9.6.3.yaml.lock @@ -0,0 +1,12 @@ +# This file was autogenerated by Stack. +# You should not edit this file by hand. +# For more information, please see the documentation at: +# https://docs.haskellstack.org/en/stable/lock_files + +packages: [] +snapshots: +- completed: + sha256: 1b4c2669e26fa828451830ed4725e4d406acc25a1fa24fcc039465dd13d7a575 + size: 714100 + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/22/6.yaml + original: lts-22.6 diff --git a/stack-9.8.1.yaml b/stack-9.8.1.yaml new file mode 100644 index 0000000..2f1a36f --- /dev/null +++ b/stack-9.8.1.yaml @@ -0,0 +1,5 @@ + +resolver: nightly-2024-01-26 + +packages: +- . diff --git a/stack-9.8.1.yaml.lock b/stack-9.8.1.yaml.lock new file mode 100644 index 0000000..3f8e18f --- /dev/null +++ b/stack-9.8.1.yaml.lock @@ -0,0 +1,12 @@ +# This file was autogenerated by Stack. +# You should not edit this file by hand. +# For more information, please see the documentation at: +# https://docs.haskellstack.org/en/stable/lock_files + +packages: [] +snapshots: +- completed: + sha256: 876a5c75d90718add42e1ad36d66000bf35050ce1c66748119897a32df613186 + size: 563963 + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/nightly/2024/1/26.yaml + original: nightly-2024-01-26 diff --git a/stack.yaml b/stack.yaml index bfc9a75..fa1a123 100644 --- a/stack.yaml +++ b/stack.yaml @@ -1,5 +1,5 @@ -resolver: nightly-2023-11-14 +resolver: lts-22.6 packages: - . diff --git a/stack.yaml.lock b/stack.yaml.lock index dd4da80..1b74b0a 100644 --- a/stack.yaml.lock +++ b/stack.yaml.lock @@ -6,7 +6,7 @@ packages: [] snapshots: - completed: - sha256: 0eaacfc9de6b0ab46ab6026166d2ba7718ab06a8612086b3ee21d7667e682df0 - size: 698974 - url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/nightly/2023/11/14.yaml - original: nightly-2023-11-14 + sha256: 1b4c2669e26fa828451830ed4725e4d406acc25a1fa24fcc039465dd13d7a575 + size: 714100 + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/22/6.yaml + original: lts-22.6 From 1ea2172d9c903d616ed53309a38f136f058dce22 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Mon, 29 Jan 2024 14:19:16 -0800 Subject: [PATCH 50/76] Release 0.6.3.0 (GHC 9.8 support) --- CHANGELOG.md | 2 ++ aeson-typescript.cabal | 2 +- package.yaml | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5cecaec..14b81d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 0.6.3.0 + * GHC 9.8 support ## 0.6.2.0 diff --git a/aeson-typescript.cabal b/aeson-typescript.cabal index 6ae61ba..1c8b635 100644 --- a/aeson-typescript.cabal +++ b/aeson-typescript.cabal @@ -5,7 +5,7 @@ cabal-version: 1.12 -- see: https://github.com/sol/hpack name: aeson-typescript -version: 0.6.2.0 +version: 0.6.3.0 synopsis: Generate TypeScript definition files from your ADTs description: Please see the README on Github at category: Text, Web, JSON diff --git a/package.yaml b/package.yaml index 8b52337..cf445d8 100644 --- a/package.yaml +++ b/package.yaml @@ -1,5 +1,5 @@ name: aeson-typescript -version: 0.6.2.0 +version: 0.6.3.0 github: "codedownio/aeson-typescript" license: BSD3 category: Text, Web, JSON From ac758f277f70e05e8696b34562b9f941e73ec953 Mon Sep 17 00:00:00 2001 From: Taylor Fausak Date: Tue, 29 Oct 2024 11:03:37 -0500 Subject: [PATCH 51/76] Fix type for maps with non-string keys --- src/Data/Aeson/TypeScript/Instances.hs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/Data/Aeson/TypeScript/Instances.hs b/src/Data/Aeson/TypeScript/Instances.hs index 97de51c..a3cd144 100644 --- a/src/Data/Aeson/TypeScript/Instances.hs +++ b/src/Data/Aeson/TypeScript/Instances.hs @@ -4,6 +4,7 @@ {-# LANGUAGE OverlappingInstances #-} {-# LANGUAGE CPP #-} {-# LANGUAGE PolyKinds #-} +{-# LANGUAGE TypeApplications #-} {-# OPTIONS_GHC -fno-warn-orphans #-} -- Note: the OverlappingInstances pragma is only here so the overlapping instances in this file @@ -171,13 +172,18 @@ instance (TypeScript a) => TypeScript (Maybe a) where instance TypeScript A.Value where getTypeScriptType _ = "any"; -instance (TypeScript a, TypeScript b) => TypeScript (Map a b) where - getTypeScriptType _ = "{[k in " ++ getTypeScriptKeyType (Proxy :: Proxy a) ++ "]?: " ++ getTypeScriptType (Proxy :: Proxy b) ++ "}" - getParentTypes _ = [TSType (Proxy :: Proxy a), TSType (Proxy :: Proxy b)] - -instance (TypeScript a, TypeScript b) => TypeScript (HashMap a b) where - getTypeScriptType _ = [i|{[k in #{getTypeScriptKeyType (Proxy :: Proxy a)}]?: #{getTypeScriptType (Proxy :: Proxy b)}}|] - getParentTypes _ = L.nub [TSType (Proxy :: Proxy a), TSType (Proxy :: Proxy b)] +instance (TypeScript a, TypeScript b, A.ToJSONKey a) => TypeScript (Map a b) where + getTypeScriptType = + let k = getTypeScriptKeyType @a Proxy + v = getTypeScriptType @b Proxy + in const $ case A.toJSONKey @a of + A.ToJSONKeyText{} -> "{[k in " <> k <> "]?: " <> v <> "}" + A.ToJSONKeyValue{} -> getTypeScriptType @[(a, b)] Proxy + getParentTypes = const $ L.nub [TSType @a Proxy, TSType @b Proxy] + +instance (TypeScript a, TypeScript b, A.ToJSONKey a) => TypeScript (HashMap a b) where + getTypeScriptType = const $ getTypeScriptType @(Map a b) Proxy + getParentTypes = const $ getParentTypes @(Map a b) Proxy #if MIN_VERSION_aeson(2,0,0) instance (TypeScript a) => TypeScript (A.KeyMap a) where From 5d6175061c2d6086290f6affb9aa95bcfb1b6ad1 Mon Sep 17 00:00:00 2001 From: thomasjm Date: Tue, 29 Oct 2024 19:08:28 -0700 Subject: [PATCH 52/76] Improve a few error messages --- src/Data/Aeson/TypeScript/Lookup.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Data/Aeson/TypeScript/Lookup.hs b/src/Data/Aeson/TypeScript/Lookup.hs index 82544fe..f51b2fd 100644 --- a/src/Data/Aeson/TypeScript/Lookup.hs +++ b/src/Data/Aeson/TypeScript/Lookup.hs @@ -30,7 +30,7 @@ deriveTypeScriptLookupType name declNameStr = do interfaceDecl <- getClosedTypeFamilyInterfaceDecl name eqns return [FunD (mkName declNameStr) [Clause [] (NormalB (ListE [interfaceDecl])) []]] - _ -> fail [i|Expected a close type family; got #{info}|] + _ -> fail [i|Expected a closed type family; got #{info}|] getClosedTypeFamilyInterfaceDecl :: Name -> [TySynEqn] -> Q Exp getClosedTypeFamilyInterfaceDecl name eqns = do @@ -44,7 +44,7 @@ getClosedTypeFamilyInterfaceDecl name eqns = do TySynEqn [ConT arg] result -> do [| 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}'|] + x -> fail [i|aeson-typescript doesn't know yet how to handle this type family equation when generating interface declaration: '#{x}'|] [| TSInterfaceDeclaration $(TH.stringE $ nameBase name) [] (L.sortBy (compare `on` fieldName) $(listE $ fmap return fields)) Nothing |] @@ -56,4 +56,4 @@ getClosedTypeFamilyImage eqns = do #else TySynEqn [ConT _] result -> return result #endif - x -> fail [i|aeson-typescript doesn't know yet how to handle this type family equation: '#{x}'|] + x -> fail [i|aeson-typescript doesn't know yet how to handle this type family equation when calculating closed type family image: '#{x}'|] From 10d8056282084b54d53ba638906efbbc9f3796ab Mon Sep 17 00:00:00 2001 From: thomasjm Date: Tue, 29 Oct 2024 19:09:41 -0700 Subject: [PATCH 53/76] Update CHANGELOG.md --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14b81d1..32aa218 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +## 0.6.4.0 + +* Fix type for maps with non-string keys (#46, fixes #28, thanks @tfausak!) + ## 0.6.3.0 * GHC 9.8 support From 35a6414c3d7e136d556e355fc86b6a6764171ddd Mon Sep 17 00:00:00 2001 From: thomasjm Date: Fri, 1 Nov 2024 00:11:22 -0700 Subject: [PATCH 54/76] Release 0.6.4.0 --- aeson-typescript.cabal | 4 ++-- package.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/aeson-typescript.cabal b/aeson-typescript.cabal index 1c8b635..a448269 100644 --- a/aeson-typescript.cabal +++ b/aeson-typescript.cabal @@ -1,11 +1,11 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.36.0. +-- This file has been generated from package.yaml by hpack version 0.37.0. -- -- see: https://github.com/sol/hpack name: aeson-typescript -version: 0.6.3.0 +version: 0.6.4.0 synopsis: Generate TypeScript definition files from your ADTs description: Please see the README on Github at category: Text, Web, JSON diff --git a/package.yaml b/package.yaml index cf445d8..0f0fde4 100644 --- a/package.yaml +++ b/package.yaml @@ -1,5 +1,5 @@ name: aeson-typescript -version: 0.6.3.0 +version: 0.6.4.0 github: "codedownio/aeson-typescript" license: BSD3 category: Text, Web, JSON From 0cf43e7006ad85b5f034226a31c732115efa3fa3 Mon Sep 17 00:00:00 2001 From: thomasjm Date: Fri, 6 Dec 2024 15:35:00 -0800 Subject: [PATCH 55/76] Remove question mark in Data.Map instance --- src/Data/Aeson/TypeScript/Instances.hs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Data/Aeson/TypeScript/Instances.hs b/src/Data/Aeson/TypeScript/Instances.hs index a3cd144..988aec0 100644 --- a/src/Data/Aeson/TypeScript/Instances.hs +++ b/src/Data/Aeson/TypeScript/Instances.hs @@ -177,8 +177,8 @@ instance (TypeScript a, TypeScript b, A.ToJSONKey a) => TypeScript (Map a b) whe let k = getTypeScriptKeyType @a Proxy v = getTypeScriptType @b Proxy in const $ case A.toJSONKey @a of - A.ToJSONKeyText{} -> "{[k in " <> k <> "]?: " <> v <> "}" - A.ToJSONKeyValue{} -> getTypeScriptType @[(a, b)] Proxy + A.ToJSONKeyText {} -> "{[k in " <> k <> "]: " <> v <> "}" + A.ToJSONKeyValue {} -> getTypeScriptType @[(a, b)] Proxy getParentTypes = const $ L.nub [TSType @a Proxy, TSType @b Proxy] instance (TypeScript a, TypeScript b, A.ToJSONKey a) => TypeScript (HashMap a b) where From 217af9cd361e961d4ba7fdb0edce90db390de0df Mon Sep 17 00:00:00 2001 From: thomasjm Date: Fri, 6 Dec 2024 16:04:28 -0800 Subject: [PATCH 56/76] GHC 9.6.3 -> 9.6.6 --- .github/workflows/aeson-typescript.yml | 6 +++--- stack-9.6.3.yaml | 5 ----- stack-9.6.6.yaml | 5 +++++ stack.yaml | 2 +- stack.yaml.lock | 8 ++++---- 5 files changed, 13 insertions(+), 13 deletions(-) delete mode 100644 stack-9.6.3.yaml create mode 100644 stack-9.6.6.yaml diff --git a/.github/workflows/aeson-typescript.yml b/.github/workflows/aeson-typescript.yml index e719130..948d0b7 100644 --- a/.github/workflows/aeson-typescript.yml +++ b/.github/workflows/aeson-typescript.yml @@ -17,7 +17,7 @@ jobs: - "9.0.2" - "9.2.8" - "9.4.7" - - "9.6.3" + - "9.6.6" - "9.8.1" steps: @@ -71,8 +71,8 @@ jobs: yaml: "stack-9.2.8.yaml" - ghc: "9.4.7" yaml: "stack-9.4.7.yaml" - - ghc: "9.6.3" - yaml: "stack-9.6.3.yaml" + - ghc: "9.6.6" + yaml: "stack-9.6.6.yaml" - ghc: "9.8.1" yaml: "stack-9.8.1.yaml" diff --git a/stack-9.6.3.yaml b/stack-9.6.3.yaml deleted file mode 100644 index fa1a123..0000000 --- a/stack-9.6.3.yaml +++ /dev/null @@ -1,5 +0,0 @@ - -resolver: lts-22.6 - -packages: -- . diff --git a/stack-9.6.6.yaml b/stack-9.6.6.yaml new file mode 100644 index 0000000..da3643b --- /dev/null +++ b/stack-9.6.6.yaml @@ -0,0 +1,5 @@ + +resolver: lts-22.43 + +packages: +- . diff --git a/stack.yaml b/stack.yaml index fa1a123..da3643b 100644 --- a/stack.yaml +++ b/stack.yaml @@ -1,5 +1,5 @@ -resolver: lts-22.6 +resolver: lts-22.43 packages: - . diff --git a/stack.yaml.lock b/stack.yaml.lock index 1b74b0a..f9829eb 100644 --- a/stack.yaml.lock +++ b/stack.yaml.lock @@ -6,7 +6,7 @@ packages: [] snapshots: - completed: - sha256: 1b4c2669e26fa828451830ed4725e4d406acc25a1fa24fcc039465dd13d7a575 - size: 714100 - url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/22/6.yaml - original: lts-22.6 + sha256: 08bd13ce621b41a8f5e51456b38d5b46d7783ce114a50ab604d6bbab0d002146 + size: 720271 + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/22/43.yaml + original: lts-22.43 From c659b5b3f85e5b1e08d5b303221ecb53cb85ffff Mon Sep 17 00:00:00 2001 From: thomasjm Date: Fri, 6 Dec 2024 16:04:45 -0800 Subject: [PATCH 57/76] Add flake.nix, .envrc --- .envrc | 6 ++++++ .gitignore | 2 ++ flake.nix | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+) create mode 100644 .envrc create mode 100644 flake.nix diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..ac5cf17 --- /dev/null +++ b/.envrc @@ -0,0 +1,6 @@ + +if ! has nix_direnv_version || ! nix_direnv_version 2.2.0; then + source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/2.2.0/direnvrc" "sha256-5EwyKnkJNQeXrRkYbwwRBcXbibosCJqyIUuz9Xq+LRc=" +fi + +use_flake diff --git a/.gitignore b/.gitignore index 938bf2c..b2918f1 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,5 @@ dist-newstyle *.hie dev/ + +.direnv diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..f0f08c1 --- /dev/null +++ b/flake.nix @@ -0,0 +1,32 @@ +{ + description = "aeson-typescript"; + + inputs.nixpkgs.url = "github:NixOS/nixpkgs/release-24.05"; + inputs.nixpkgsMaster.url = "github:NixOS/nixpkgs/master"; + inputs.flake-utils.url = "github:numtide/flake-utils"; + + outputs = { self, nixpkgs, nixpkgsMaster, flake-utils }: + flake-utils.lib.eachSystem [ "x86_64-linux" ] (system: + let + pkgs = import nixpkgs { inherit system; }; + pkgsMaster = import nixpkgsMaster { inherit system; }; + in + { + packages = { + inherit (pkgsMaster.haskell.packages.ghc966) weeder; + + test = pkgs.writeShellScriptBin "stack-test" '' + export NIX_PATH=nixpkgs=${pkgs.path} + ${pkgs.stack}/bin/stack test + ''; + + nixpkgsPath = pkgs.writeShellScriptBin "nixpkgsPath.sh" "echo -n ${pkgs.path}"; + }; + + devShells.default = pkgs.mkShell { + buildInputs = with pkgs; [ + nodejs + ]; + }; + }); +} From 300d44cf2389aa137b95f362805cef50b232e5c3 Mon Sep 17 00:00:00 2001 From: thomasjm Date: Fri, 6 Dec 2024 16:33:41 -0800 Subject: [PATCH 58/76] Update flake.nix and tests to pass with question mark change --- flake.lock | 78 +++++++++++++++++++++++++++++++++++++++++++++++++ flake.nix | 2 +- stack.yaml | 3 ++ test/Generic.hs | 2 +- test/Util.hs | 40 ++++++++++++++----------- 5 files changed, 106 insertions(+), 19 deletions(-) create mode 100644 flake.lock diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..649c591 --- /dev/null +++ b/flake.lock @@ -0,0 +1,78 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1733506555, + "narHash": "sha256-2LC74TJ4jh0oGkNRaiLfKvTttjBtBIT7lr9/OJBeb1g=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "f11c13edc4ad2bd863c7275a4aa792230bc668f6", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "release-24.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgsMaster": { + "locked": { + "lastModified": 1733527277, + "narHash": "sha256-f6a4Zql19fawMRbvAsJ21T4rvBxbsJFhHxHpu9jASLo=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "a01ee2f7f3e0f33f6738b6f49d24d3653a415682", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "master", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs", + "nixpkgsMaster": "nixpkgsMaster" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix index f0f08c1..1ac4a28 100644 --- a/flake.nix +++ b/flake.nix @@ -25,7 +25,7 @@ devShells.default = pkgs.mkShell { buildInputs = with pkgs; [ - nodejs + nodePackages.typescript ]; }; }); diff --git a/stack.yaml b/stack.yaml index da3643b..e6ad164 100644 --- a/stack.yaml +++ b/stack.yaml @@ -1,5 +1,8 @@ resolver: lts-22.43 +nix: + pure: false + packages: - . diff --git a/test/Generic.hs b/test/Generic.hs index 68f92fb..ea6d05b 100644 --- a/test/Generic.hs +++ b/test/Generic.hs @@ -53,7 +53,7 @@ tests = describe "Generic instances" $ do it [i|Complex4 makes the declaration and types correctly|] $ do (getTypeScriptDeclarationsRecursively (Proxy :: Proxy (Complex4 String))) `shouldBe` [ - TSInterfaceDeclaration "IProduct4" ["T"] [TSField False "record4" "{[k in string]?: T}" Nothing] Nothing + TSInterfaceDeclaration "IProduct4" ["T"] [TSField False "record4" "{[k in string]: T}" Nothing] Nothing ,TSTypeAlternatives "Complex4" ["T"] ["IProduct4"] Nothing ] diff --git a/test/Util.hs b/test/Util.hs index 8436f05..045672f 100644 --- a/test/Util.hs +++ b/test/Util.hs @@ -1,6 +1,11 @@ {-# LANGUAGE CPP #-} -module Util where +module Util ( + testTypeCheck + , testTypeCheckDeclarations + + , setTagSingleConstructors + ) where import Control.Monad import Data.Aeson as A @@ -17,10 +22,9 @@ import System.IO.Temp import System.Process hiding (cwd) -npmInstallScript, yarnInstallScript, localTSC :: String +npmInstallScript, yarnInstallScript :: String npmInstallScript = "test/assets/npm_install.sh" yarnInstallScript = "test/assets/yarn_install.sh" -localTSC = "test/assets/node_modules/.bin/tsc" isCI :: IO Bool isCI = lookupEnv "CI" >>= (return . (== (Just "true"))) @@ -30,8 +34,22 @@ getTSC = isCI >>= \case True -> do return "tsc" -- Assume it's set up on the path False -> do - ensureTSCExists - return localTSC + -- Check for a global tsc + findExecutable "tsc" >>= \case + Just tsc -> return tsc + Nothing -> do + let localTSC = "test/assets/node_modules/.bin/tsc" + + doesFileExist localTSC >>= \exists -> unless exists $ void $ do + cwd <- getCurrentDirectory + + installScript <- chooseInstallScript + + putStrLn [i|Invoking yarn to install tsc compiler (make sure yarn is installed). CWD is #{cwd}|] + (exitCode, stdout, stderr) <- readProcessWithExitCode installScript [] "" + when (exitCode /= ExitSuccess) $ putStrLn [i|Error installing yarn: '#{stderr}', '#{stdout}'|] + + return localTSC testTypeCheck :: forall a. (TypeScript a, ToJSON a) => a -> IO () testTypeCheck obj = withSystemTempDirectory "typescript_test" $ \folder -> do @@ -84,18 +102,6 @@ testTypeCheckDeclarations tsDeclarations typesAndVals = withSystemTempDirectory #{serr} |] - -ensureTSCExists :: IO () -ensureTSCExists = doesFileExist localTSC >>= \exists -> unless exists $ void $ do - cwd <- getCurrentDirectory - - installScript <- chooseInstallScript - - putStrLn [i|Invoking yarn to install tsc compiler (make sure yarn is installed). CWD is #{cwd}|] - (exitCode, stdout, stderr) <- readProcessWithExitCode installScript [] "" - when (exitCode /= ExitSuccess) $ putStrLn [i|Error installing yarn: '#{stderr}', '#{stdout}'|] - - -- Between Aeson 1.1.2.0 and 1.2.0.0, tagSingleConstructors was added setTagSingleConstructors :: Options -> Options #if MIN_VERSION_aeson(1,2,0) From e1fe0538fe47fb436ba8255485843f0d8bc83c2c Mon Sep 17 00:00:00 2001 From: thomasjm Date: Fri, 6 Dec 2024 16:38:35 -0800 Subject: [PATCH 59/76] GHC 9.4.7 -> 9.4.8, 9.8.1 -> 9.8.2 --- .github/workflows/aeson-typescript.yml | 12 ++++++------ stack-9.4.7.yaml | 5 ----- stack-9.4.8.yaml | 5 +++++ stack-9.4.7.yaml.lock => stack-9.4.8.yaml.lock | 8 ++++---- stack-9.8.1.yaml | 5 ----- stack-9.8.4.yaml | 5 +++++ stack-9.8.1.yaml.lock => stack-9.8.4.yaml.lock | 8 ++++---- 7 files changed, 24 insertions(+), 24 deletions(-) delete mode 100644 stack-9.4.7.yaml create mode 100644 stack-9.4.8.yaml rename stack-9.4.7.yaml.lock => stack-9.4.8.yaml.lock (65%) delete mode 100644 stack-9.8.1.yaml create mode 100644 stack-9.8.4.yaml rename stack-9.8.1.yaml.lock => stack-9.8.4.yaml.lock (63%) diff --git a/.github/workflows/aeson-typescript.yml b/.github/workflows/aeson-typescript.yml index 948d0b7..425c384 100644 --- a/.github/workflows/aeson-typescript.yml +++ b/.github/workflows/aeson-typescript.yml @@ -16,9 +16,9 @@ jobs: - "8.10.7" - "9.0.2" - "9.2.8" - - "9.4.7" + - "9.4.8" - "9.6.6" - - "9.8.1" + - "9.8.2" steps: - uses: actions/checkout@v2 @@ -69,12 +69,12 @@ jobs: yaml: "stack-9.0.2.yaml" - ghc: "9.2.8" yaml: "stack-9.2.8.yaml" - - ghc: "9.4.7" - yaml: "stack-9.4.7.yaml" + - ghc: "9.4.8" + yaml: "stack-9.4.8.yaml" - ghc: "9.6.6" yaml: "stack-9.6.6.yaml" - - ghc: "9.8.1" - yaml: "stack-9.8.1.yaml" + - ghc: "9.8.2" + yaml: "stack-9.8.2.yaml" steps: - uses: actions/checkout@v3 diff --git a/stack-9.4.7.yaml b/stack-9.4.7.yaml deleted file mode 100644 index 13994e4..0000000 --- a/stack-9.4.7.yaml +++ /dev/null @@ -1,5 +0,0 @@ - -resolver: lts-21.20 - -packages: -- . diff --git a/stack-9.4.8.yaml b/stack-9.4.8.yaml new file mode 100644 index 0000000..8ff6e94 --- /dev/null +++ b/stack-9.4.8.yaml @@ -0,0 +1,5 @@ + +resolver: lts-21.25 + +packages: +- . diff --git a/stack-9.4.7.yaml.lock b/stack-9.4.8.yaml.lock similarity index 65% rename from stack-9.4.7.yaml.lock rename to stack-9.4.8.yaml.lock index 1b8f599..f823d29 100644 --- a/stack-9.4.7.yaml.lock +++ b/stack-9.4.8.yaml.lock @@ -6,7 +6,7 @@ packages: [] snapshots: - completed: - sha256: 5921ddc75f5dd3f197fbc32e1e5676895a8e7b971d4f82ef6b556657801dd18a - size: 640054 - url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/21/20.yaml - original: lts-21.20 + sha256: a81fb3877c4f9031e1325eb3935122e608d80715dc16b586eb11ddbff8671ecd + size: 640086 + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/21/25.yaml + original: lts-21.25 diff --git a/stack-9.8.1.yaml b/stack-9.8.1.yaml deleted file mode 100644 index 2f1a36f..0000000 --- a/stack-9.8.1.yaml +++ /dev/null @@ -1,5 +0,0 @@ - -resolver: nightly-2024-01-26 - -packages: -- . diff --git a/stack-9.8.4.yaml b/stack-9.8.4.yaml new file mode 100644 index 0000000..995854f --- /dev/null +++ b/stack-9.8.4.yaml @@ -0,0 +1,5 @@ + +resolver: nightly-2024-10-21 + +packages: +- . diff --git a/stack-9.8.1.yaml.lock b/stack-9.8.4.yaml.lock similarity index 63% rename from stack-9.8.1.yaml.lock rename to stack-9.8.4.yaml.lock index 3f8e18f..691f9ca 100644 --- a/stack-9.8.1.yaml.lock +++ b/stack-9.8.4.yaml.lock @@ -6,7 +6,7 @@ packages: [] snapshots: - completed: - sha256: 876a5c75d90718add42e1ad36d66000bf35050ce1c66748119897a32df613186 - size: 563963 - url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/nightly/2024/1/26.yaml - original: nightly-2024-01-26 + sha256: 867086a789eaf6da9f48a56bb5e8bfd6df27b120023c144cc7bbec5c95717915 + size: 669588 + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/nightly/2024/10/21.yaml + original: nightly-2024-10-21 From de38e594bfa15843da60f2a93ef7ecbe5590f493 Mon Sep 17 00:00:00 2001 From: thomasjm Date: Sat, 7 Dec 2024 00:07:31 -0800 Subject: [PATCH 60/76] Fix stack-9.8.2. file name --- stack-9.8.4.yaml => stack-9.8.2.yaml | 0 stack-9.8.4.yaml.lock => stack-9.8.2.yaml.lock | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename stack-9.8.4.yaml => stack-9.8.2.yaml (100%) rename stack-9.8.4.yaml.lock => stack-9.8.2.yaml.lock (100%) diff --git a/stack-9.8.4.yaml b/stack-9.8.2.yaml similarity index 100% rename from stack-9.8.4.yaml rename to stack-9.8.2.yaml diff --git a/stack-9.8.4.yaml.lock b/stack-9.8.2.yaml.lock similarity index 100% rename from stack-9.8.4.yaml.lock rename to stack-9.8.2.yaml.lock From 4d6c0b414f41a28544e7a5f28fcfe70261fae79d Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Mon, 3 Feb 2025 19:53:45 -0800 Subject: [PATCH 61/76] Update stack.yaml files --- .github/workflows/aeson-typescript.yml | 6 +++--- stack-9.8.2.yaml | 5 ----- stack-9.8.4.yaml | 5 +++++ stack-9.8.2.yaml.lock => stack-9.8.4.yaml.lock | 8 ++++---- stack.yaml | 2 +- stack.yaml.lock | 8 ++++---- 6 files changed, 17 insertions(+), 17 deletions(-) delete mode 100644 stack-9.8.2.yaml create mode 100644 stack-9.8.4.yaml rename stack-9.8.2.yaml.lock => stack-9.8.4.yaml.lock (63%) diff --git a/.github/workflows/aeson-typescript.yml b/.github/workflows/aeson-typescript.yml index 425c384..fcffabb 100644 --- a/.github/workflows/aeson-typescript.yml +++ b/.github/workflows/aeson-typescript.yml @@ -18,7 +18,7 @@ jobs: - "9.2.8" - "9.4.8" - "9.6.6" - - "9.8.2" + - "9.8.4" steps: - uses: actions/checkout@v2 @@ -73,8 +73,8 @@ jobs: yaml: "stack-9.4.8.yaml" - ghc: "9.6.6" yaml: "stack-9.6.6.yaml" - - ghc: "9.8.2" - yaml: "stack-9.8.2.yaml" + - ghc: "9.8.4" + yaml: "stack-9.8.4.yaml" steps: - uses: actions/checkout@v3 diff --git a/stack-9.8.2.yaml b/stack-9.8.2.yaml deleted file mode 100644 index 995854f..0000000 --- a/stack-9.8.2.yaml +++ /dev/null @@ -1,5 +0,0 @@ - -resolver: nightly-2024-10-21 - -packages: -- . diff --git a/stack-9.8.4.yaml b/stack-9.8.4.yaml new file mode 100644 index 0000000..8587184 --- /dev/null +++ b/stack-9.8.4.yaml @@ -0,0 +1,5 @@ + +resolver: lts-23.7 + +packages: +- . diff --git a/stack-9.8.2.yaml.lock b/stack-9.8.4.yaml.lock similarity index 63% rename from stack-9.8.2.yaml.lock rename to stack-9.8.4.yaml.lock index 691f9ca..0e99322 100644 --- a/stack-9.8.2.yaml.lock +++ b/stack-9.8.4.yaml.lock @@ -6,7 +6,7 @@ packages: [] snapshots: - completed: - sha256: 867086a789eaf6da9f48a56bb5e8bfd6df27b120023c144cc7bbec5c95717915 - size: 669588 - url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/nightly/2024/10/21.yaml - original: nightly-2024-10-21 + sha256: 4ef79c30b9efcf07335cb3de532983a7ac4c5a4180bc17f6212a86b09ce2ff75 + size: 680777 + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/23/7.yaml + original: lts-23.7 diff --git a/stack.yaml b/stack.yaml index e6ad164..dfcce6a 100644 --- a/stack.yaml +++ b/stack.yaml @@ -1,5 +1,5 @@ -resolver: lts-22.43 +resolver: lts-23.7 nix: pure: false diff --git a/stack.yaml.lock b/stack.yaml.lock index f9829eb..0e99322 100644 --- a/stack.yaml.lock +++ b/stack.yaml.lock @@ -6,7 +6,7 @@ packages: [] snapshots: - completed: - sha256: 08bd13ce621b41a8f5e51456b38d5b46d7783ce114a50ab604d6bbab0d002146 - size: 720271 - url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/22/43.yaml - original: lts-22.43 + sha256: 4ef79c30b9efcf07335cb3de532983a7ac4c5a4180bc17f6212a86b09ce2ff75 + size: 680777 + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/23/7.yaml + original: lts-23.7 From 48f5d0dbc5d39ac2cc7ced80b112690b8238deda Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Mon, 3 Feb 2025 19:55:04 -0800 Subject: [PATCH 62/76] flake.nix: trying to do windows cross-compile --- flake.lock | 609 ++++++++++++++++++++++++++++++++++++++++++++++++++++- flake.nix | 43 +++- 2 files changed, 635 insertions(+), 17 deletions(-) diff --git a/flake.lock b/flake.lock index 649c591..577cda8 100644 --- a/flake.lock +++ b/flake.lock @@ -1,5 +1,105 @@ { "nodes": { + "HTTP": { + "flake": false, + "locked": { + "lastModified": 1451647621, + "narHash": "sha256-oHIyw3x0iKBexEo49YeUDV1k74ZtyYKGR2gNJXXRxts=", + "owner": "phadej", + "repo": "HTTP", + "rev": "9bc0996d412fef1787449d841277ef663ad9a915", + "type": "github" + }, + "original": { + "owner": "phadej", + "repo": "HTTP", + "type": "github" + } + }, + "cabal-32": { + "flake": false, + "locked": { + "lastModified": 1603716527, + "narHash": "sha256-X0TFfdD4KZpwl0Zr6x+PLxUt/VyKQfX7ylXHdmZIL+w=", + "owner": "haskell", + "repo": "cabal", + "rev": "48bf10787e27364730dd37a42b603cee8d6af7ee", + "type": "github" + }, + "original": { + "owner": "haskell", + "ref": "3.2", + "repo": "cabal", + "type": "github" + } + }, + "cabal-34": { + "flake": false, + "locked": { + "lastModified": 1645834128, + "narHash": "sha256-wG3d+dOt14z8+ydz4SL7pwGfe7SiimxcD/LOuPCV6xM=", + "owner": "haskell", + "repo": "cabal", + "rev": "5ff598c67f53f7c4f48e31d722ba37172230c462", + "type": "github" + }, + "original": { + "owner": "haskell", + "ref": "3.4", + "repo": "cabal", + "type": "github" + } + }, + "cabal-36": { + "flake": false, + "locked": { + "lastModified": 1669081697, + "narHash": "sha256-I5or+V7LZvMxfbYgZATU4awzkicBwwok4mVoje+sGmU=", + "owner": "haskell", + "repo": "cabal", + "rev": "8fd619e33d34924a94e691c5fea2c42f0fc7f144", + "type": "github" + }, + "original": { + "owner": "haskell", + "ref": "3.6", + "repo": "cabal", + "type": "github" + } + }, + "cardano-shell": { + "flake": false, + "locked": { + "lastModified": 1608537748, + "narHash": "sha256-PulY1GfiMgKVnBci3ex4ptk2UNYMXqGjJOxcPy2KYT4=", + "owner": "input-output-hk", + "repo": "cardano-shell", + "rev": "9392c75087cb9a3d453998f4230930dea3a95725", + "type": "github" + }, + "original": { + "owner": "input-output-hk", + "repo": "cardano-shell", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1672831974, + "narHash": "sha256-z9k3MfslLjWQfnjBtEtJZdq3H7kyi2kQtUThfTgdRk0=", + "owner": "input-output-hk", + "repo": "flake-compat", + "rev": "45f2638735f8cdc40fe302742b79f248d23eb368", + "type": "github" + }, + "original": { + "owner": "input-output-hk", + "ref": "hkm/gitlab-fix", + "repo": "flake-compat", + "type": "github" + } + }, "flake-utils": { "inputs": { "systems": "systems" @@ -18,43 +118,530 @@ "type": "github" } }, + "ghc-8.6.5-iohk": { + "flake": false, + "locked": { + "lastModified": 1600920045, + "narHash": "sha256-DO6kxJz248djebZLpSzTGD6s8WRpNI9BTwUeOf5RwY8=", + "owner": "input-output-hk", + "repo": "ghc", + "rev": "95713a6ecce4551240da7c96b6176f980af75cae", + "type": "github" + }, + "original": { + "owner": "input-output-hk", + "ref": "release/8.6.5-iohk", + "repo": "ghc", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "hackage": { + "flake": false, + "locked": { + "lastModified": 1738628879, + "narHash": "sha256-fQNlSl5f6MPKLI7RmqLKHdix3YtxVkAyZ0b7XzNn1YQ=", + "owner": "input-output-hk", + "repo": "hackage.nix", + "rev": "901791fe0870fc8816fb52665774fb7b4d591ed9", + "type": "github" + }, + "original": { + "owner": "input-output-hk", + "repo": "hackage.nix", + "type": "github" + } + }, + "haskellNix": { + "inputs": { + "HTTP": "HTTP", + "cabal-32": "cabal-32", + "cabal-34": "cabal-34", + "cabal-36": "cabal-36", + "cardano-shell": "cardano-shell", + "flake-compat": "flake-compat", + "ghc-8.6.5-iohk": "ghc-8.6.5-iohk", + "hackage": "hackage", + "hls-1.10": "hls-1.10", + "hls-2.0": "hls-2.0", + "hls-2.2": "hls-2.2", + "hls-2.3": "hls-2.3", + "hls-2.4": "hls-2.4", + "hls-2.5": "hls-2.5", + "hls-2.6": "hls-2.6", + "hls-2.7": "hls-2.7", + "hls-2.8": "hls-2.8", + "hls-2.9": "hls-2.9", + "hpc-coveralls": "hpc-coveralls", + "iserv-proxy": "iserv-proxy", + "nixpkgs": [ + "haskellNix", + "nixpkgs-unstable" + ], + "nixpkgs-2003": "nixpkgs-2003", + "nixpkgs-2105": "nixpkgs-2105", + "nixpkgs-2111": "nixpkgs-2111", + "nixpkgs-2205": "nixpkgs-2205", + "nixpkgs-2211": "nixpkgs-2211", + "nixpkgs-2305": "nixpkgs-2305", + "nixpkgs-2311": "nixpkgs-2311", + "nixpkgs-2405": "nixpkgs-2405", + "nixpkgs-2411": "nixpkgs-2411", + "nixpkgs-unstable": "nixpkgs-unstable", + "old-ghc-nix": "old-ghc-nix", + "stackage": "stackage" + }, + "locked": { + "lastModified": 1738630291, + "narHash": "sha256-sT8M2+hNzQl2flJZY0lAD9Ygpr5f4deKecc/OuNRVP0=", + "owner": "input-output-hk", + "repo": "haskell.nix", + "rev": "2cb66646461d4388b950621190af3840169fe883", + "type": "github" + }, + "original": { + "owner": "input-output-hk", + "repo": "haskell.nix", + "type": "github" + } + }, + "hls-1.10": { + "flake": false, + "locked": { + "lastModified": 1680000865, + "narHash": "sha256-rc7iiUAcrHxwRM/s0ErEsSPxOR3u8t7DvFeWlMycWgo=", + "owner": "haskell", + "repo": "haskell-language-server", + "rev": "b08691db779f7a35ff322b71e72a12f6e3376fd9", + "type": "github" + }, + "original": { + "owner": "haskell", + "ref": "1.10.0.0", + "repo": "haskell-language-server", + "type": "github" + } + }, + "hls-2.0": { + "flake": false, + "locked": { + "lastModified": 1687698105, + "narHash": "sha256-OHXlgRzs/kuJH8q7Sxh507H+0Rb8b7VOiPAjcY9sM1k=", + "owner": "haskell", + "repo": "haskell-language-server", + "rev": "783905f211ac63edf982dd1889c671653327e441", + "type": "github" + }, + "original": { + "owner": "haskell", + "ref": "2.0.0.1", + "repo": "haskell-language-server", + "type": "github" + } + }, + "hls-2.2": { + "flake": false, + "locked": { + "lastModified": 1693064058, + "narHash": "sha256-8DGIyz5GjuCFmohY6Fa79hHA/p1iIqubfJUTGQElbNk=", + "owner": "haskell", + "repo": "haskell-language-server", + "rev": "b30f4b6cf5822f3112c35d14a0cba51f3fe23b85", + "type": "github" + }, + "original": { + "owner": "haskell", + "ref": "2.2.0.0", + "repo": "haskell-language-server", + "type": "github" + } + }, + "hls-2.3": { + "flake": false, + "locked": { + "lastModified": 1695910642, + "narHash": "sha256-tR58doOs3DncFehHwCLczJgntyG/zlsSd7DgDgMPOkI=", + "owner": "haskell", + "repo": "haskell-language-server", + "rev": "458ccdb55c9ea22cd5d13ec3051aaefb295321be", + "type": "github" + }, + "original": { + "owner": "haskell", + "ref": "2.3.0.0", + "repo": "haskell-language-server", + "type": "github" + } + }, + "hls-2.4": { + "flake": false, + "locked": { + "lastModified": 1699862708, + "narHash": "sha256-YHXSkdz53zd0fYGIYOgLt6HrA0eaRJi9mXVqDgmvrjk=", + "owner": "haskell", + "repo": "haskell-language-server", + "rev": "54507ef7e85fa8e9d0eb9a669832a3287ffccd57", + "type": "github" + }, + "original": { + "owner": "haskell", + "ref": "2.4.0.1", + "repo": "haskell-language-server", + "type": "github" + } + }, + "hls-2.5": { + "flake": false, + "locked": { + "lastModified": 1701080174, + "narHash": "sha256-fyiR9TaHGJIIR0UmcCb73Xv9TJq3ht2ioxQ2mT7kVdc=", + "owner": "haskell", + "repo": "haskell-language-server", + "rev": "27f8c3d3892e38edaef5bea3870161815c4d014c", + "type": "github" + }, + "original": { + "owner": "haskell", + "ref": "2.5.0.0", + "repo": "haskell-language-server", + "type": "github" + } + }, + "hls-2.6": { + "flake": false, + "locked": { + "lastModified": 1705325287, + "narHash": "sha256-+P87oLdlPyMw8Mgoul7HMWdEvWP/fNlo8jyNtwME8E8=", + "owner": "haskell", + "repo": "haskell-language-server", + "rev": "6e0b342fa0327e628610f2711f8c3e4eaaa08b1e", + "type": "github" + }, + "original": { + "owner": "haskell", + "ref": "2.6.0.0", + "repo": "haskell-language-server", + "type": "github" + } + }, + "hls-2.7": { + "flake": false, + "locked": { + "lastModified": 1708965829, + "narHash": "sha256-LfJ+TBcBFq/XKoiNI7pc4VoHg4WmuzsFxYJ3Fu+Jf+M=", + "owner": "haskell", + "repo": "haskell-language-server", + "rev": "50322b0a4aefb27adc5ec42f5055aaa8f8e38001", + "type": "github" + }, + "original": { + "owner": "haskell", + "ref": "2.7.0.0", + "repo": "haskell-language-server", + "type": "github" + } + }, + "hls-2.8": { + "flake": false, + "locked": { + "lastModified": 1715153580, + "narHash": "sha256-Vi/iUt2pWyUJlo9VrYgTcbRviWE0cFO6rmGi9rmALw0=", + "owner": "haskell", + "repo": "haskell-language-server", + "rev": "dd1be1beb16700de59e0d6801957290bcf956a0a", + "type": "github" + }, + "original": { + "owner": "haskell", + "ref": "2.8.0.0", + "repo": "haskell-language-server", + "type": "github" + } + }, + "hls-2.9": { + "flake": false, + "locked": { + "lastModified": 1720003792, + "narHash": "sha256-qnDx8Pk0UxtoPr7BimEsAZh9g2WuTuMB/kGqnmdryKs=", + "owner": "haskell", + "repo": "haskell-language-server", + "rev": "0c1817cb2babef0765e4e72dd297c013e8e3d12b", + "type": "github" + }, + "original": { + "owner": "haskell", + "ref": "2.9.0.1", + "repo": "haskell-language-server", + "type": "github" + } + }, + "hpc-coveralls": { + "flake": false, + "locked": { + "lastModified": 1607498076, + "narHash": "sha256-8uqsEtivphgZWYeUo5RDUhp6bO9j2vaaProQxHBltQk=", + "owner": "sevanspowell", + "repo": "hpc-coveralls", + "rev": "14df0f7d229f4cd2e79f8eabb1a740097fdfa430", + "type": "github" + }, + "original": { + "owner": "sevanspowell", + "repo": "hpc-coveralls", + "type": "github" + } + }, + "iserv-proxy": { + "flake": false, + "locked": { + "lastModified": 1717479972, + "narHash": "sha256-7vE3RQycHI1YT9LHJ1/fUaeln2vIpYm6Mmn8FTpYeVo=", + "owner": "stable-haskell", + "repo": "iserv-proxy", + "rev": "2ed34002247213fc435d0062350b91bab920626e", + "type": "github" + }, + "original": { + "owner": "stable-haskell", + "ref": "iserv-syms", + "repo": "iserv-proxy", + "type": "github" + } + }, "nixpkgs": { "locked": { - "lastModified": 1733506555, - "narHash": "sha256-2LC74TJ4jh0oGkNRaiLfKvTttjBtBIT7lr9/OJBeb1g=", + "lastModified": 1738633836, + "narHash": "sha256-WqzHCqLdENH6Y44G997EKc8sIO7DrLQf2NMh1Pm0qn4=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "f11c13edc4ad2bd863c7275a4aa792230bc668f6", + "rev": "c55e1940d4dffcfa2b8d4ea15e864c837e514a77", "type": "github" }, "original": { "owner": "NixOS", - "ref": "release-24.05", + "ref": "release-24.11", "repo": "nixpkgs", "type": "github" } }, - "nixpkgsMaster": { + "nixpkgs-2003": { "locked": { - "lastModified": 1733527277, - "narHash": "sha256-f6a4Zql19fawMRbvAsJ21T4rvBxbsJFhHxHpu9jASLo=", + "lastModified": 1620055814, + "narHash": "sha256-8LEHoYSJiL901bTMVatq+rf8y7QtWuZhwwpKE2fyaRY=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "a01ee2f7f3e0f33f6738b6f49d24d3653a415682", + "rev": "1db42b7fe3878f3f5f7a4f2dc210772fd080e205", "type": "github" }, "original": { "owner": "NixOS", - "ref": "master", + "ref": "nixpkgs-20.03-darwin", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-2105": { + "locked": { + "lastModified": 1659914493, + "narHash": "sha256-lkA5X3VNMKirvA+SUzvEhfA7XquWLci+CGi505YFAIs=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "022caabb5f2265ad4006c1fa5b1ebe69fb0c3faf", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-21.05-darwin", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-2111": { + "locked": { + "lastModified": 1659446231, + "narHash": "sha256-hekabNdTdgR/iLsgce5TGWmfIDZ86qjPhxDg/8TlzhE=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "eabc38219184cc3e04a974fe31857d8e0eac098d", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-21.11-darwin", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-2205": { + "locked": { + "lastModified": 1685573264, + "narHash": "sha256-Zffu01pONhs/pqH07cjlF10NnMDLok8ix5Uk4rhOnZQ=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "380be19fbd2d9079f677978361792cb25e8a3635", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-22.05-darwin", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-2211": { + "locked": { + "lastModified": 1688392541, + "narHash": "sha256-lHrKvEkCPTUO+7tPfjIcb7Trk6k31rz18vkyqmkeJfY=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "ea4c80b39be4c09702b0cb3b42eab59e2ba4f24b", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-22.11-darwin", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-2305": { + "locked": { + "lastModified": 1705033721, + "narHash": "sha256-K5eJHmL1/kev6WuqyqqbS1cdNnSidIZ3jeqJ7GbrYnQ=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "a1982c92d8980a0114372973cbdfe0a307f1bdea", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-23.05-darwin", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-2311": { + "locked": { + "lastModified": 1719957072, + "narHash": "sha256-gvFhEf5nszouwLAkT9nWsDzocUTqLWHuL++dvNjMp9I=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "7144d6241f02d171d25fba3edeaf15e0f2592105", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-23.11-darwin", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-2405": { + "locked": { + "lastModified": 1735564410, + "narHash": "sha256-HB/FA0+1gpSs8+/boEavrGJH+Eq08/R2wWNph1sM1Dg=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "1e7a8f391f1a490460760065fa0630b5520f9cf8", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-24.05-darwin", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-2411": { + "locked": { + "lastModified": 1737255904, + "narHash": "sha256-r3fxHvh+M/mBgCZXOACzRFPsJdix2QSsKazb7VCXXo0=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "eacdab35066b0bb1c9413c96898e326b76398a81", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-24.11-darwin", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-unstable": { + "locked": { + "lastModified": 1737110817, + "narHash": "sha256-DSenga8XjPaUV5KUFW/i3rNkN7jm9XmguW+qQ1ZJTR4=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "041c867bad68dfe34b78b2813028a2e2ea70a23c", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", "repo": "nixpkgs", "type": "github" } }, + "old-ghc-nix": { + "flake": false, + "locked": { + "lastModified": 1631092763, + "narHash": "sha256-sIKgO+z7tj4lw3u6oBZxqIhDrzSkvpHtv0Kki+lh9Fg=", + "owner": "angerman", + "repo": "old-ghc-nix", + "rev": "af48a7a7353e418119b6dfe3cd1463a657f342b8", + "type": "github" + }, + "original": { + "owner": "angerman", + "ref": "master", + "repo": "old-ghc-nix", + "type": "github" + } + }, "root": { "inputs": { "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs", - "nixpkgsMaster": "nixpkgsMaster" + "gitignore": "gitignore", + "haskellNix": "haskellNix", + "nixpkgs": "nixpkgs" + } + }, + "stackage": { + "flake": false, + "locked": { + "lastModified": 1738627879, + "narHash": "sha256-NqNxhRroKBitD8BxoDTSXJbw9R3pPlsaVkoYqiPbDT0=", + "owner": "input-output-hk", + "repo": "stackage.nix", + "rev": "42916147b7e9e8f751cac1881a60bcbb8839ec3d", + "type": "github" + }, + "original": { + "owner": "input-output-hk", + "repo": "stackage.nix", + "type": "github" } }, "systems": { diff --git a/flake.nix b/flake.nix index 1ac4a28..4727cfc 100644 --- a/flake.nix +++ b/flake.nix @@ -1,19 +1,50 @@ { description = "aeson-typescript"; - inputs.nixpkgs.url = "github:NixOS/nixpkgs/release-24.05"; - inputs.nixpkgsMaster.url = "github:NixOS/nixpkgs/master"; inputs.flake-utils.url = "github:numtide/flake-utils"; + inputs.gitignore = { + url = "github:hercules-ci/gitignore.nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + inputs.haskellNix.url = "github:input-output-hk/haskell.nix"; + inputs.nixpkgs.url = "github:NixOS/nixpkgs/release-24.11"; - outputs = { self, nixpkgs, nixpkgsMaster, flake-utils }: + outputs = { self, flake-utils, gitignore, haskellNix, nixpkgs }: flake-utils.lib.eachSystem [ "x86_64-linux" ] (system: let - pkgs = import nixpkgs { inherit system; }; - pkgsMaster = import nixpkgsMaster { inherit system; }; + compiler-nix-name = "ghc984"; + + pkgs = import nixpkgs { + inherit system; + overlays = [haskellNix.overlay]; + inherit (haskellNix) config; + }; + + src = gitignore.lib.gitignoreSource ./.; + + flake = (pkgs.haskell-nix.hix.project { + inherit src compiler-nix-name; + evalSystem = system; + projectFileName = "stack.yaml"; + modules = []; + }).flake {}; + + flakeWindows = (pkgs.pkgsCross.mingwW64.haskell-nix.hix.project { + inherit src compiler-nix-name; + evalSystem = system; + projectFileName = "stack.yaml"; + modules = []; + }).flake {}; + in { packages = { - inherit (pkgsMaster.haskell.packages.ghc966) weeder; + inherit (pkgs.haskell.packages.${compiler-nix-name}) weeder; + + inherit flake; + + normal = flake.packages."aeson-typescript:lib:aeson-typescript"; + windows = flakeWindows.packages."aeson-typescript:lib:aeson-typescript"; test = pkgs.writeShellScriptBin "stack-test" '' export NIX_PATH=nixpkgs=${pkgs.path} From e2c05c937a8e62436e9ca02475e3524cf82e1916 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Mon, 3 Feb 2025 19:55:17 -0800 Subject: [PATCH 63/76] .gitignore result --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index b2918f1..346524a 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ dist-newstyle dev/ .direnv + +result From 77d515608b8619001691fb7707445a6a7c169db3 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Tue, 4 Feb 2025 05:20:27 -0800 Subject: [PATCH 64/76] More on cross-compiling --- flake.lock | 21 ++++----------------- flake.nix | 9 ++++++--- 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/flake.lock b/flake.lock index 577cda8..bf6c88e 100644 --- a/flake.lock +++ b/flake.lock @@ -427,22 +427,6 @@ "type": "github" } }, - "nixpkgs": { - "locked": { - "lastModified": 1738633836, - "narHash": "sha256-WqzHCqLdENH6Y44G997EKc8sIO7DrLQf2NMh1Pm0qn4=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "c55e1940d4dffcfa2b8d4ea15e864c837e514a77", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "release-24.11", - "repo": "nixpkgs", - "type": "github" - } - }, "nixpkgs-2003": { "locked": { "lastModified": 1620055814, @@ -625,7 +609,10 @@ "flake-utils": "flake-utils", "gitignore": "gitignore", "haskellNix": "haskellNix", - "nixpkgs": "nixpkgs" + "nixpkgs": [ + "haskellNix", + "nixpkgs" + ] } }, "stackage": { diff --git a/flake.nix b/flake.nix index 4727cfc..b48a9ff 100644 --- a/flake.nix +++ b/flake.nix @@ -7,11 +7,12 @@ inputs.nixpkgs.follows = "nixpkgs"; }; inputs.haskellNix.url = "github:input-output-hk/haskell.nix"; - inputs.nixpkgs.url = "github:NixOS/nixpkgs/release-24.11"; + inputs.nixpkgs.follows = "haskellNix/nixpkgs"; outputs = { self, flake-utils, gitignore, haskellNix, nixpkgs }: flake-utils.lib.eachSystem [ "x86_64-linux" ] (system: let + # compiler-nix-name = "ghc966"; compiler-nix-name = "ghc984"; pkgs = import nixpkgs { @@ -32,8 +33,10 @@ flakeWindows = (pkgs.pkgsCross.mingwW64.haskell-nix.hix.project { inherit src compiler-nix-name; evalSystem = system; - projectFileName = "stack.yaml"; - modules = []; + projectFileName = "stack-9.8.4.yaml"; + modules = [{ + reinstallableLibGhc = false; + }]; }).flake {}; in From 03e486680c5de3d0d5edef3b3654f39802166724 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Thu, 6 Feb 2025 19:00:33 -0800 Subject: [PATCH 65/76] ci: run latest stack files --- .github/workflows/aeson-typescript.yml | 3 +++ stack-9.10.1.yaml | 5 +++++ stack-9.10.1.yaml.lock | 12 ++++++++++++ stack-9.6.6.yaml.lock | 12 ++++++++++++ 4 files changed, 32 insertions(+) create mode 100644 stack-9.10.1.yaml create mode 100644 stack-9.10.1.yaml.lock create mode 100644 stack-9.6.6.yaml.lock diff --git a/.github/workflows/aeson-typescript.yml b/.github/workflows/aeson-typescript.yml index fcffabb..0a45431 100644 --- a/.github/workflows/aeson-typescript.yml +++ b/.github/workflows/aeson-typescript.yml @@ -19,6 +19,7 @@ jobs: - "9.4.8" - "9.6.6" - "9.8.4" + - "9.10.1" steps: - uses: actions/checkout@v2 @@ -75,6 +76,8 @@ jobs: yaml: "stack-9.6.6.yaml" - ghc: "9.8.4" yaml: "stack-9.8.4.yaml" + - ghc: "9.10.1" + yaml: "stack-9.10.1.yaml" steps: - uses: actions/checkout@v3 diff --git a/stack-9.10.1.yaml b/stack-9.10.1.yaml new file mode 100644 index 0000000..db6fede --- /dev/null +++ b/stack-9.10.1.yaml @@ -0,0 +1,5 @@ + +resolver: nightly-2025-02-04 + +packages: +- . diff --git a/stack-9.10.1.yaml.lock b/stack-9.10.1.yaml.lock new file mode 100644 index 0000000..d12fe41 --- /dev/null +++ b/stack-9.10.1.yaml.lock @@ -0,0 +1,12 @@ +# This file was autogenerated by Stack. +# You should not edit this file by hand. +# For more information, please see the documentation at: +# https://docs.haskellstack.org/en/stable/lock_files + +packages: [] +snapshots: +- completed: + sha256: a1b6c372b9194401b72c7c707b257215a4bed0649b8114c778d9fa17db15a4cb + size: 650398 + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/nightly/2025/2/4.yaml + original: nightly-2025-02-04 diff --git a/stack-9.6.6.yaml.lock b/stack-9.6.6.yaml.lock new file mode 100644 index 0000000..f9829eb --- /dev/null +++ b/stack-9.6.6.yaml.lock @@ -0,0 +1,12 @@ +# This file was autogenerated by Stack. +# You should not edit this file by hand. +# For more information, please see the documentation at: +# https://docs.haskellstack.org/en/stable/lock_files + +packages: [] +snapshots: +- completed: + sha256: 08bd13ce621b41a8f5e51456b38d5b46d7783ce114a50ab604d6bbab0d002146 + size: 720271 + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/22/43.yaml + original: lts-22.43 From 7d22ebbbb8cc61e86cd9295d6af5659c1845c405 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Thu, 6 Feb 2025 19:00:48 -0800 Subject: [PATCH 66/76] Update some flake stuff and CHANGELOG --- CHANGELOG.md | 2 ++ flake.lock | 18 +++++++++--------- flake.nix | 3 +++ 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32aa218..aabd8b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +* Remove question mark in Data.Map instance + ## 0.6.4.0 * Fix type for maps with non-string keys (#46, fixes #28, thanks @tfausak!) diff --git a/flake.lock b/flake.lock index bf6c88e..d658202 100644 --- a/flake.lock +++ b/flake.lock @@ -158,11 +158,11 @@ "hackage": { "flake": false, "locked": { - "lastModified": 1738628879, - "narHash": "sha256-fQNlSl5f6MPKLI7RmqLKHdix3YtxVkAyZ0b7XzNn1YQ=", + "lastModified": 1738715278, + "narHash": "sha256-SI154ShwJ24faTWlV/+phNfwOR7il5LPyRulpsCToHI=", "owner": "input-output-hk", "repo": "hackage.nix", - "rev": "901791fe0870fc8816fb52665774fb7b4d591ed9", + "rev": "08261aa338ce30b6817ec7ed37b097ef284154e0", "type": "github" }, "original": { @@ -211,11 +211,11 @@ "stackage": "stackage" }, "locked": { - "lastModified": 1738630291, - "narHash": "sha256-sT8M2+hNzQl2flJZY0lAD9Ygpr5f4deKecc/OuNRVP0=", + "lastModified": 1738716891, + "narHash": "sha256-DLK/yKwY19sRRRXQvrPkcUOqYwMBWCt1woiPxOuIYGs=", "owner": "input-output-hk", "repo": "haskell.nix", - "rev": "2cb66646461d4388b950621190af3840169fe883", + "rev": "908d11a14c51adecaa6d5fc6866b450a8fdd8a52", "type": "github" }, "original": { @@ -618,11 +618,11 @@ "stackage": { "flake": false, "locked": { - "lastModified": 1738627879, - "narHash": "sha256-NqNxhRroKBitD8BxoDTSXJbw9R3pPlsaVkoYqiPbDT0=", + "lastModified": 1738714273, + "narHash": "sha256-0X3JlXEcmLCVAM0kxU6ha3dmcoPjAMVs4Rt4zMrbJ0Q=", "owner": "input-output-hk", "repo": "stackage.nix", - "rev": "42916147b7e9e8f751cac1881a60bcbb8839ec3d", + "rev": "23b0d89937dadc38d96a9c0768dfcef0cf8e5a1b", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index b48a9ff..a29bd1f 100644 --- a/flake.nix +++ b/flake.nix @@ -14,6 +14,7 @@ let # compiler-nix-name = "ghc966"; compiler-nix-name = "ghc984"; + # compiler-nix-name = "ghc9101"; pkgs = import nixpkgs { inherit system; @@ -33,7 +34,9 @@ flakeWindows = (pkgs.pkgsCross.mingwW64.haskell-nix.hix.project { inherit src compiler-nix-name; evalSystem = system; + # projectFileName = "stack.yaml"; projectFileName = "stack-9.8.4.yaml"; + # projectFileName = "stack-9.10.1.yaml"; modules = [{ reinstallableLibGhc = false; }]; From 98f57d555ebed5254f3551e06a63c6eca35ea7dd Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Thu, 6 Feb 2025 19:10:12 -0800 Subject: [PATCH 67/76] ci: haskell/actions/setup -> haskell-actions/setup --- .github/workflows/aeson-typescript.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/aeson-typescript.yml b/.github/workflows/aeson-typescript.yml index 0a45431..e58e3a9 100644 --- a/.github/workflows/aeson-typescript.yml +++ b/.github/workflows/aeson-typescript.yml @@ -24,7 +24,7 @@ jobs: steps: - uses: actions/checkout@v2 - - uses: haskell/actions/setup@v2 + - uses: haskell-actions/setup@v2 id: setup-haskell-cabal name: Setup Haskell with: @@ -82,7 +82,7 @@ jobs: steps: - uses: actions/checkout@v3 - - uses: haskell/actions/setup@v2 + - uses: haskell-actions/setup@v2 name: Setup Haskell Stack with: ghc-version: ${{ matrix.ghc }} From 3d8bae393e826b1c7858fb509d320d3f82b82b3a Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Thu, 6 Feb 2025 19:37:53 -0800 Subject: [PATCH 68/76] ci: exclude older GHCs on macOS --- .github/workflows/aeson-typescript.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/aeson-typescript.yml b/.github/workflows/aeson-typescript.yml index e58e3a9..ac56835 100644 --- a/.github/workflows/aeson-typescript.yml +++ b/.github/workflows/aeson-typescript.yml @@ -20,6 +20,13 @@ jobs: - "9.6.6" - "9.8.4" - "9.10.1" + exclude: + # These don't work on GitHub CI anymore because they need llvm@13, which became + # disabled on 12/31/2024 + - os: macOS-latest + ghc: 8.10.7 + - os: macOS-latest + ghc: 9.0.2 steps: - uses: actions/checkout@v2 From eb5f6f611e64d83e778c7a1aca42e750fd474469 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Thu, 31 Jul 2025 09:29:45 -0700 Subject: [PATCH 69/76] stack-9.10.1.yaml -> stack-9.10.2.yaml --- stack-9.10.1.yaml | 5 ----- stack-9.10.2.yaml | 5 +++++ stack-9.10.1.yaml.lock => stack-9.10.2.yaml.lock | 10 +++++----- 3 files changed, 10 insertions(+), 10 deletions(-) delete mode 100644 stack-9.10.1.yaml create mode 100644 stack-9.10.2.yaml rename stack-9.10.1.yaml.lock => stack-9.10.2.yaml.lock (51%) diff --git a/stack-9.10.1.yaml b/stack-9.10.1.yaml deleted file mode 100644 index db6fede..0000000 --- a/stack-9.10.1.yaml +++ /dev/null @@ -1,5 +0,0 @@ - -resolver: nightly-2025-02-04 - -packages: -- . diff --git a/stack-9.10.2.yaml b/stack-9.10.2.yaml new file mode 100644 index 0000000..09bacd7 --- /dev/null +++ b/stack-9.10.2.yaml @@ -0,0 +1,5 @@ + +resolver: lts-24.2 + +packages: +- . diff --git a/stack-9.10.1.yaml.lock b/stack-9.10.2.yaml.lock similarity index 51% rename from stack-9.10.1.yaml.lock rename to stack-9.10.2.yaml.lock index d12fe41..8e22df7 100644 --- a/stack-9.10.1.yaml.lock +++ b/stack-9.10.2.yaml.lock @@ -1,12 +1,12 @@ # This file was autogenerated by Stack. # You should not edit this file by hand. # For more information, please see the documentation at: -# https://docs.haskellstack.org/en/stable/lock_files +# https://docs.haskellstack.org/en/stable/topics/lock_files packages: [] snapshots: - completed: - sha256: a1b6c372b9194401b72c7c707b257215a4bed0649b8114c778d9fa17db15a4cb - size: 650398 - url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/nightly/2025/2/4.yaml - original: nightly-2025-02-04 + sha256: cd28bd74375205718f1d5fa221730a9c17a203059708b1eb95f4b20d68bf82d9 + size: 724943 + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/24/2.yaml + original: lts-24.2 From dd6aaaca1723cee7da68848e19e0b9e81bd7d87a Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Thu, 31 Jul 2025 09:30:13 -0700 Subject: [PATCH 70/76] dev stack.yaml: bump to GHC 9.12 and use .envrc-provided ghc/HLS --- flake.lock | 245 ++++++++++++++++++++++++++++-------------------- flake.nix | 11 ++- stack.yaml | 6 +- stack.yaml.lock | 10 +- 4 files changed, 159 insertions(+), 113 deletions(-) diff --git a/flake.lock b/flake.lock index d658202..aeb0daf 100644 --- a/flake.lock +++ b/flake.lock @@ -158,11 +158,44 @@ "hackage": { "flake": false, "locked": { - "lastModified": 1738715278, - "narHash": "sha256-SI154ShwJ24faTWlV/+phNfwOR7il5LPyRulpsCToHI=", + "lastModified": 1753922646, + "narHash": "sha256-eVvEjP9s6iQCPQFbb66+Gzd3ZM6BjIqfFzuf/yk9D7U=", "owner": "input-output-hk", "repo": "hackage.nix", - "rev": "08261aa338ce30b6817ec7ed37b097ef284154e0", + "rev": "224f3770869031c2129c82061aeeabb6b8035aad", + "type": "github" + }, + "original": { + "owner": "input-output-hk", + "repo": "hackage.nix", + "type": "github" + } + }, + "hackage-for-stackage": { + "flake": false, + "locked": { + "lastModified": 1753921689, + "narHash": "sha256-F7yJ6l+Qb97hCTrBn24JeX4bzg5dEARtQ2HJKy3Vc48=", + "owner": "input-output-hk", + "repo": "hackage.nix", + "rev": "b8dbf163f00e329f2090733108b427c03d6976fc", + "type": "github" + }, + "original": { + "owner": "input-output-hk", + "ref": "for-stackage", + "repo": "hackage.nix", + "type": "github" + } + }, + "hackage-internal": { + "flake": false, + "locked": { + "lastModified": 1750307553, + "narHash": "sha256-iiafNoeLHwlSLQTyvy8nPe2t6g5AV4PPcpMeH/2/DLs=", + "owner": "input-output-hk", + "repo": "hackage.nix", + "rev": "f7867baa8817fab296528f4a4ec39d1c7c4da4f3", "type": "github" }, "original": { @@ -181,8 +214,13 @@ "flake-compat": "flake-compat", "ghc-8.6.5-iohk": "ghc-8.6.5-iohk", "hackage": "hackage", + "hackage-for-stackage": "hackage-for-stackage", + "hackage-internal": "hackage-internal", + "hls": "hls", "hls-1.10": "hls-1.10", "hls-2.0": "hls-2.0", + "hls-2.10": "hls-2.10", + "hls-2.11": "hls-2.11", "hls-2.2": "hls-2.2", "hls-2.3": "hls-2.3", "hls-2.4": "hls-2.4", @@ -197,25 +235,21 @@ "haskellNix", "nixpkgs-unstable" ], - "nixpkgs-2003": "nixpkgs-2003", - "nixpkgs-2105": "nixpkgs-2105", - "nixpkgs-2111": "nixpkgs-2111", - "nixpkgs-2205": "nixpkgs-2205", - "nixpkgs-2211": "nixpkgs-2211", "nixpkgs-2305": "nixpkgs-2305", "nixpkgs-2311": "nixpkgs-2311", "nixpkgs-2405": "nixpkgs-2405", "nixpkgs-2411": "nixpkgs-2411", + "nixpkgs-2505": "nixpkgs-2505", "nixpkgs-unstable": "nixpkgs-unstable", "old-ghc-nix": "old-ghc-nix", "stackage": "stackage" }, "locked": { - "lastModified": 1738716891, - "narHash": "sha256-DLK/yKwY19sRRRXQvrPkcUOqYwMBWCt1woiPxOuIYGs=", + "lastModified": 1753923139, + "narHash": "sha256-9LriT9Da9oQ5+PhUBZCHqmzRMv2M2lJ8ts6KgJX2DKQ=", "owner": "input-output-hk", "repo": "haskell.nix", - "rev": "908d11a14c51adecaa6d5fc6866b450a8fdd8a52", + "rev": "758d34c249352818ee786abb06068b8a9e29c098", "type": "github" }, "original": { @@ -224,6 +258,22 @@ "type": "github" } }, + "hls": { + "flake": false, + "locked": { + "lastModified": 1741604408, + "narHash": "sha256-tuq3+Ip70yu89GswZ7DSINBpwRprnWnl6xDYnS4GOsc=", + "owner": "haskell", + "repo": "haskell-language-server", + "rev": "682d6894c94087da5e566771f25311c47e145359", + "type": "github" + }, + "original": { + "owner": "haskell", + "repo": "haskell-language-server", + "type": "github" + } + }, "hls-1.10": { "flake": false, "locked": { @@ -258,6 +308,40 @@ "type": "github" } }, + "hls-2.10": { + "flake": false, + "locked": { + "lastModified": 1743069404, + "narHash": "sha256-q4kDFyJDDeoGqfEtrZRx4iqMVEC2MOzCToWsFY+TOzY=", + "owner": "haskell", + "repo": "haskell-language-server", + "rev": "2318c61db3a01e03700bd4b05665662929b7fe8b", + "type": "github" + }, + "original": { + "owner": "haskell", + "ref": "2.10.0.0", + "repo": "haskell-language-server", + "type": "github" + } + }, + "hls-2.11": { + "flake": false, + "locked": { + "lastModified": 1747306193, + "narHash": "sha256-/MmtpF8+FyQlwfKHqHK05BdsxC9LHV70d/FiMM7pzBM=", + "owner": "haskell", + "repo": "haskell-language-server", + "rev": "46ef4523ea4949f47f6d2752476239f1c6d806fe", + "type": "github" + }, + "original": { + "owner": "haskell", + "ref": "2.11.0.0", + "repo": "haskell-language-server", + "type": "github" + } + }, "hls-2.2": { "flake": false, "locked": { @@ -380,11 +464,11 @@ "hls-2.9": { "flake": false, "locked": { - "lastModified": 1720003792, - "narHash": "sha256-qnDx8Pk0UxtoPr7BimEsAZh9g2WuTuMB/kGqnmdryKs=", + "lastModified": 1719993701, + "narHash": "sha256-wy348++MiMm/xwtI9M3vVpqj2qfGgnDcZIGXw8sF1sA=", "owner": "haskell", "repo": "haskell-language-server", - "rev": "0c1817cb2babef0765e4e72dd297c013e8e3d12b", + "rev": "90319a7e62ab93ab65a95f8f2bcf537e34dae76a", "type": "github" }, "original": { @@ -413,11 +497,11 @@ "iserv-proxy": { "flake": false, "locked": { - "lastModified": 1717479972, - "narHash": "sha256-7vE3RQycHI1YT9LHJ1/fUaeln2vIpYm6Mmn8FTpYeVo=", + "lastModified": 1750543273, + "narHash": "sha256-WaswH0Y+Fmupvv8AkIlQBlUy/IdD3Inx9PDuE+5iRYY=", "owner": "stable-haskell", "repo": "iserv-proxy", - "rev": "2ed34002247213fc435d0062350b91bab920626e", + "rev": "a53c57c9a8d22a66a2f0c4c969e806da03f08c28", "type": "github" }, "original": { @@ -427,162 +511,114 @@ "type": "github" } }, - "nixpkgs-2003": { - "locked": { - "lastModified": 1620055814, - "narHash": "sha256-8LEHoYSJiL901bTMVatq+rf8y7QtWuZhwwpKE2fyaRY=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "1db42b7fe3878f3f5f7a4f2dc210772fd080e205", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-20.03-darwin", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs-2105": { - "locked": { - "lastModified": 1659914493, - "narHash": "sha256-lkA5X3VNMKirvA+SUzvEhfA7XquWLci+CGi505YFAIs=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "022caabb5f2265ad4006c1fa5b1ebe69fb0c3faf", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-21.05-darwin", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs-2111": { - "locked": { - "lastModified": 1659446231, - "narHash": "sha256-hekabNdTdgR/iLsgce5TGWmfIDZ86qjPhxDg/8TlzhE=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "eabc38219184cc3e04a974fe31857d8e0eac098d", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-21.11-darwin", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs-2205": { + "nixpkgs-2305": { "locked": { - "lastModified": 1685573264, - "narHash": "sha256-Zffu01pONhs/pqH07cjlF10NnMDLok8ix5Uk4rhOnZQ=", + "lastModified": 1705033721, + "narHash": "sha256-K5eJHmL1/kev6WuqyqqbS1cdNnSidIZ3jeqJ7GbrYnQ=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "380be19fbd2d9079f677978361792cb25e8a3635", + "rev": "a1982c92d8980a0114372973cbdfe0a307f1bdea", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixpkgs-22.05-darwin", + "ref": "nixpkgs-23.05-darwin", "repo": "nixpkgs", "type": "github" } }, - "nixpkgs-2211": { + "nixpkgs-2311": { "locked": { - "lastModified": 1688392541, - "narHash": "sha256-lHrKvEkCPTUO+7tPfjIcb7Trk6k31rz18vkyqmkeJfY=", + "lastModified": 1719957072, + "narHash": "sha256-gvFhEf5nszouwLAkT9nWsDzocUTqLWHuL++dvNjMp9I=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "ea4c80b39be4c09702b0cb3b42eab59e2ba4f24b", + "rev": "7144d6241f02d171d25fba3edeaf15e0f2592105", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixpkgs-22.11-darwin", + "ref": "nixpkgs-23.11-darwin", "repo": "nixpkgs", "type": "github" } }, - "nixpkgs-2305": { + "nixpkgs-2405": { "locked": { - "lastModified": 1705033721, - "narHash": "sha256-K5eJHmL1/kev6WuqyqqbS1cdNnSidIZ3jeqJ7GbrYnQ=", + "lastModified": 1735564410, + "narHash": "sha256-HB/FA0+1gpSs8+/boEavrGJH+Eq08/R2wWNph1sM1Dg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "a1982c92d8980a0114372973cbdfe0a307f1bdea", + "rev": "1e7a8f391f1a490460760065fa0630b5520f9cf8", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixpkgs-23.05-darwin", + "ref": "nixpkgs-24.05-darwin", "repo": "nixpkgs", "type": "github" } }, - "nixpkgs-2311": { + "nixpkgs-2411": { "locked": { - "lastModified": 1719957072, - "narHash": "sha256-gvFhEf5nszouwLAkT9nWsDzocUTqLWHuL++dvNjMp9I=", + "lastModified": 1748037224, + "narHash": "sha256-92vihpZr6dwEMV6g98M5kHZIttrWahb9iRPBm1atcPk=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "7144d6241f02d171d25fba3edeaf15e0f2592105", + "rev": "f09dede81861f3a83f7f06641ead34f02f37597f", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixpkgs-23.11-darwin", + "ref": "nixpkgs-24.11-darwin", "repo": "nixpkgs", "type": "github" } }, - "nixpkgs-2405": { + "nixpkgs-2505": { "locked": { - "lastModified": 1735564410, - "narHash": "sha256-HB/FA0+1gpSs8+/boEavrGJH+Eq08/R2wWNph1sM1Dg=", + "lastModified": 1748852332, + "narHash": "sha256-r/wVJWmLYEqvrJKnL48r90Wn9HWX9SHFt6s4LhuTh7k=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "1e7a8f391f1a490460760065fa0630b5520f9cf8", + "rev": "a8167f3cc2f991dd4d0055746df53dae5fd0c953", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixpkgs-24.05-darwin", + "ref": "nixpkgs-25.05-darwin", "repo": "nixpkgs", "type": "github" } }, - "nixpkgs-2411": { + "nixpkgs-unstable": { "locked": { - "lastModified": 1737255904, - "narHash": "sha256-r3fxHvh+M/mBgCZXOACzRFPsJdix2QSsKazb7VCXXo0=", + "lastModified": 1748856973, + "narHash": "sha256-RlTsJUvvr8ErjPBsiwrGbbHYW8XbB/oek0Gi78XdWKg=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "eacdab35066b0bb1c9413c96898e326b76398a81", + "rev": "e4b09e47ace7d87de083786b404bf232eb6c89d8", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixpkgs-24.11-darwin", + "ref": "nixpkgs-unstable", "repo": "nixpkgs", "type": "github" } }, - "nixpkgs-unstable": { + "nixpkgsMaster": { "locked": { - "lastModified": 1737110817, - "narHash": "sha256-DSenga8XjPaUV5KUFW/i3rNkN7jm9XmguW+qQ1ZJTR4=", + "lastModified": 1753975144, + "narHash": "sha256-QsCqY2NnLN+47+j/J8V0PHemua+iA7em8pw1yID1RN0=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "041c867bad68dfe34b78b2813028a2e2ea70a23c", + "rev": "63e24fbc205fc7484ac7c90212a94853be116de4", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixpkgs-unstable", + "ref": "master", "repo": "nixpkgs", "type": "github" } @@ -612,17 +648,18 @@ "nixpkgs": [ "haskellNix", "nixpkgs" - ] + ], + "nixpkgsMaster": "nixpkgsMaster" } }, "stackage": { "flake": false, "locked": { - "lastModified": 1738714273, - "narHash": "sha256-0X3JlXEcmLCVAM0kxU6ha3dmcoPjAMVs4Rt4zMrbJ0Q=", + "lastModified": 1753920846, + "narHash": "sha256-jk2dKSlLgEfwpwocH2GX9mfwLSV0anmyjJ400zqCGq8=", "owner": "input-output-hk", "repo": "stackage.nix", - "rev": "23b0d89937dadc38d96a9c0768dfcef0cf8e5a1b", + "rev": "edb12eda18a509b65576505316a7419ad2dbfb69", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index a29bd1f..268b584 100644 --- a/flake.nix +++ b/flake.nix @@ -8,8 +8,9 @@ }; inputs.haskellNix.url = "github:input-output-hk/haskell.nix"; inputs.nixpkgs.follows = "haskellNix/nixpkgs"; + inputs.nixpkgsMaster.url = "github:NixOS/nixpkgs/master"; - outputs = { self, flake-utils, gitignore, haskellNix, nixpkgs }: + outputs = { self, flake-utils, gitignore, haskellNix, nixpkgs, nixpkgsMaster }: flake-utils.lib.eachSystem [ "x86_64-linux" ] (system: let # compiler-nix-name = "ghc966"; @@ -22,6 +23,10 @@ inherit (haskellNix) config; }; + pkgsMaster = import nixpkgsMaster { + inherit system; + }; + src = gitignore.lib.gitignoreSource ./.; flake = (pkgs.haskell-nix.hix.project { @@ -62,7 +67,9 @@ devShells.default = pkgs.mkShell { buildInputs = with pkgs; [ - nodePackages.typescript + pkgs.nodePackages.typescript + pkgsMaster.haskell.compiler.ghc9122 + (pkgsMaster.haskell-language-server.override { supportedGhcVersions = ["9122"]; }) ]; }; }); diff --git a/stack.yaml b/stack.yaml index dfcce6a..b026e0d 100644 --- a/stack.yaml +++ b/stack.yaml @@ -1,8 +1,10 @@ -resolver: lts-23.7 +resolver: nightly-2025-07-31 nix: - pure: false + enable: false + +system-ghc: true packages: - . diff --git a/stack.yaml.lock b/stack.yaml.lock index 0e99322..76ec781 100644 --- a/stack.yaml.lock +++ b/stack.yaml.lock @@ -1,12 +1,12 @@ # This file was autogenerated by Stack. # You should not edit this file by hand. # For more information, please see the documentation at: -# https://docs.haskellstack.org/en/stable/lock_files +# https://docs.haskellstack.org/en/stable/topics/lock_files packages: [] snapshots: - completed: - sha256: 4ef79c30b9efcf07335cb3de532983a7ac4c5a4180bc17f6212a86b09ce2ff75 - size: 680777 - url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/23/7.yaml - original: lts-23.7 + sha256: 3dec7f4c6dc2dc10047d2941a6bc9ee8fa6a84f6db932096cbd83a0ace83dfa1 + size: 672916 + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/nightly/2025/7/31.yaml + original: nightly-2025-07-31 From a10b1babcaf77e7fd8e6e9794d66451245f931c9 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Thu, 31 Jul 2025 09:34:22 -0700 Subject: [PATCH 71/76] Handle Maybe correctly in tuple encodings (fixes #49) --- src/Data/Aeson/TypeScript/TH.hs | 9 +++++++-- test/Basic.hs | 9 +++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/Data/Aeson/TypeScript/TH.hs b/src/Data/Aeson/TypeScript/TH.hs index 4663a8f..3cd7227 100644 --- a/src/Data/Aeson/TypeScript/TH.hs +++ b/src/Data/Aeson/TypeScript/TH.hs @@ -307,10 +307,15 @@ handleConstructor (ExtraTypeScriptOptions {..}) options (DatatypeInfo {..}) gene -- * Type declaration to use interfaceName = "I" <> (lastNameComponent' $ constructorName ci) - tupleEncoding = + tupleEncoding = do + let typ = contentsTupleTypeSubstituted genericVariables ci + stringExp <- lift $ case typ of + (AppT (ConT name) t) | name == ''Maybe -> [|$(getTypeAsStringExp t) <> " | null"|] + _ -> getTypeAsStringExp typ + lift [|TSTypeAlternatives $(TH.stringE interfaceName) $(genericVariablesListExpr True genericVariables) - [getTypeScriptType (Proxy :: Proxy $(return (contentsTupleTypeSubstituted genericVariables ci)))] + [$(return stringExp)] $(tryGetDoc haddockModifier (constructorName ci))|] assembleInterfaceDeclaration members = [|TSInterfaceDeclaration $(TH.stringE interfaceName) diff --git a/test/Basic.hs b/test/Basic.hs index 18c226d..a6c7a86 100644 --- a/test/Basic.hs +++ b/test/Basic.hs @@ -17,6 +17,9 @@ data Unit2 = Unit2 $(deriveTypeScript (A.defaultOptions { A.tagSingleConstructors = True , A.constructorTagModifier = const "foo" }) ''Unit2) +data Test1 = Test1 (Maybe Int) +deriveTypeScript A.defaultOptions ''Test1 + tests :: SpecWith () tests = describe "Basic tests" $ do describe "tagSingleConstructors and constructorTagModifier" $ do @@ -31,6 +34,12 @@ tests = describe "Basic tests" $ do TSTypeAlternatives "Unit2" [] ["\"foo\""] Nothing ]) + it [i|Maybe tuple encoding includes null option|] $ do + (getTypeScriptDeclarations (Proxy :: Proxy Test1)) `shouldBe` ([ + TSTypeAlternatives "Test1" [] ["ITest1"] Nothing + , TSTypeAlternatives "ITest1" [] ["number | null"] Nothing + ]) + main :: IO () main = hspec tests From 5fc225d4c198b932fc7e78247620a3335b083a07 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Thu, 31 Jul 2025 11:01:04 -0700 Subject: [PATCH 72/76] stack-9.6.6.yaml -> stack-9.6.7.yaml + update CI --- .github/workflows/aeson-typescript.yml | 8 ++++---- stack-9.6.6.yaml | 5 ----- stack-9.6.7.yaml | 5 +++++ stack-9.6.6.yaml.lock => stack-9.6.7.yaml.lock | 10 +++++----- 4 files changed, 14 insertions(+), 14 deletions(-) delete mode 100644 stack-9.6.6.yaml create mode 100644 stack-9.6.7.yaml rename stack-9.6.6.yaml.lock => stack-9.6.7.yaml.lock (52%) diff --git a/.github/workflows/aeson-typescript.yml b/.github/workflows/aeson-typescript.yml index ac56835..f5f7830 100644 --- a/.github/workflows/aeson-typescript.yml +++ b/.github/workflows/aeson-typescript.yml @@ -17,9 +17,9 @@ jobs: - "9.0.2" - "9.2.8" - "9.4.8" - - "9.6.6" + - "9.6.7" - "9.8.4" - - "9.10.1" + - "9.10.2" exclude: # These don't work on GitHub CI anymore because they need llvm@13, which became # disabled on 12/31/2024 @@ -83,8 +83,8 @@ jobs: yaml: "stack-9.6.6.yaml" - ghc: "9.8.4" yaml: "stack-9.8.4.yaml" - - ghc: "9.10.1" - yaml: "stack-9.10.1.yaml" + - ghc: "9.10.2" + yaml: "stack-9.10.2.yaml" steps: - uses: actions/checkout@v3 diff --git a/stack-9.6.6.yaml b/stack-9.6.6.yaml deleted file mode 100644 index da3643b..0000000 --- a/stack-9.6.6.yaml +++ /dev/null @@ -1,5 +0,0 @@ - -resolver: lts-22.43 - -packages: -- . diff --git a/stack-9.6.7.yaml b/stack-9.6.7.yaml new file mode 100644 index 0000000..e06d1e2 --- /dev/null +++ b/stack-9.6.7.yaml @@ -0,0 +1,5 @@ + +resolver: lts-22.44 + +packages: +- . diff --git a/stack-9.6.6.yaml.lock b/stack-9.6.7.yaml.lock similarity index 52% rename from stack-9.6.6.yaml.lock rename to stack-9.6.7.yaml.lock index f9829eb..8d134eb 100644 --- a/stack-9.6.6.yaml.lock +++ b/stack-9.6.7.yaml.lock @@ -1,12 +1,12 @@ # This file was autogenerated by Stack. # You should not edit this file by hand. # For more information, please see the documentation at: -# https://docs.haskellstack.org/en/stable/lock_files +# https://docs.haskellstack.org/en/stable/topics/lock_files packages: [] snapshots: - completed: - sha256: 08bd13ce621b41a8f5e51456b38d5b46d7783ce114a50ab604d6bbab0d002146 - size: 720271 - url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/22/43.yaml - original: lts-22.43 + sha256: 238fa745b64f91184f9aa518fe04bdde6552533d169b0da5256670df83a0f1a9 + size: 721141 + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/22/44.yaml + original: lts-22.44 From 981defc26a2e6bd4c14c953fd3fba0d416121cf1 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Thu, 31 Jul 2025 11:47:33 -0700 Subject: [PATCH 73/76] ci: another update --- .github/workflows/aeson-typescript.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/aeson-typescript.yml b/.github/workflows/aeson-typescript.yml index f5f7830..784ec16 100644 --- a/.github/workflows/aeson-typescript.yml +++ b/.github/workflows/aeson-typescript.yml @@ -79,8 +79,8 @@ jobs: yaml: "stack-9.2.8.yaml" - ghc: "9.4.8" yaml: "stack-9.4.8.yaml" - - ghc: "9.6.6" - yaml: "stack-9.6.6.yaml" + - ghc: "9.6.7" + yaml: "stack-9.6.7.yaml" - ghc: "9.8.4" yaml: "stack-9.8.4.yaml" - ghc: "9.10.2" From 79816488ef338875b3808e69bb4b95a9b60f70da Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Thu, 31 Jul 2025 11:59:45 -0700 Subject: [PATCH 74/76] ci: try testing GHC 9.12.2 --- .github/workflows/aeson-typescript.yml | 3 +++ stack-9.12.2.yaml | 10 ++++++++++ stack-9.12.2.yaml.lock | 12 ++++++++++++ 3 files changed, 25 insertions(+) create mode 100644 stack-9.12.2.yaml create mode 100644 stack-9.12.2.yaml.lock diff --git a/.github/workflows/aeson-typescript.yml b/.github/workflows/aeson-typescript.yml index 784ec16..7cd9973 100644 --- a/.github/workflows/aeson-typescript.yml +++ b/.github/workflows/aeson-typescript.yml @@ -20,6 +20,7 @@ jobs: - "9.6.7" - "9.8.4" - "9.10.2" + - "9.12.2" exclude: # These don't work on GitHub CI anymore because they need llvm@13, which became # disabled on 12/31/2024 @@ -85,6 +86,8 @@ jobs: yaml: "stack-9.8.4.yaml" - ghc: "9.10.2" yaml: "stack-9.10.2.yaml" + - ghc: "9.12.2" + yaml: "stack-9.12.2.yaml" steps: - uses: actions/checkout@v3 diff --git a/stack-9.12.2.yaml b/stack-9.12.2.yaml new file mode 100644 index 0000000..b026e0d --- /dev/null +++ b/stack-9.12.2.yaml @@ -0,0 +1,10 @@ + +resolver: nightly-2025-07-31 + +nix: + enable: false + +system-ghc: true + +packages: +- . diff --git a/stack-9.12.2.yaml.lock b/stack-9.12.2.yaml.lock new file mode 100644 index 0000000..76ec781 --- /dev/null +++ b/stack-9.12.2.yaml.lock @@ -0,0 +1,12 @@ +# This file was autogenerated by Stack. +# You should not edit this file by hand. +# For more information, please see the documentation at: +# https://docs.haskellstack.org/en/stable/topics/lock_files + +packages: [] +snapshots: +- completed: + sha256: 3dec7f4c6dc2dc10047d2941a6bc9ee8fa6a84f6db932096cbd83a0ace83dfa1 + size: 672916 + url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/nightly/2025/7/31.yaml + original: nightly-2025-07-31 From b02479d9abfe0055c83a9dac411b831afbcbe13a Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Thu, 31 Jul 2025 22:57:34 -0700 Subject: [PATCH 75/76] flake.nix: use eachDefaultSystem --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 268b584..bebda18 100644 --- a/flake.nix +++ b/flake.nix @@ -11,7 +11,7 @@ inputs.nixpkgsMaster.url = "github:NixOS/nixpkgs/master"; outputs = { self, flake-utils, gitignore, haskellNix, nixpkgs, nixpkgsMaster }: - flake-utils.lib.eachSystem [ "x86_64-linux" ] (system: + flake-utils.lib.eachDefaultSystem (system: let # compiler-nix-name = "ghc966"; compiler-nix-name = "ghc984"; From 846f4de8d54278c49456a29803da6f01ab9b87f6 Mon Sep 17 00:00:00 2001 From: Tom McLaughlin Date: Fri, 1 Aug 2025 11:37:33 -0700 Subject: [PATCH 76/76] Fix more issues with Maybes inside tuple encodings (#52) * Add MaybeTuples tests * Add getTypeScriptTypeOrOptionalNull helper to use in tuple instances * Use TH to derive tuple instances up to size 10 * Use getTypeScriptTypeOrOptionalNull to tidy TH.hs * Fix a few warnings * Tighten up a couple haddocks * Add size-1 and size-2 tuples to TestBoilerplate.hs --- aeson-typescript.cabal | 5 +- src/Data/Aeson/TypeScript/Instances.hs | 23 +----- .../Aeson/TypeScript/Instances/TupleGen.hs | 36 +++++++++ src/Data/Aeson/TypeScript/Recursive.hs | 1 - src/Data/Aeson/TypeScript/TH.hs | 10 +-- src/Data/Aeson/TypeScript/Types.hs | 6 ++ src/Data/Aeson/TypeScript/Util.hs | 6 +- test/Basic.hs | 15 ---- test/MaybeTuples.hs | 78 +++++++++++++++++++ test/NoOmitNothingFields.hs | 6 +- test/OmitNothingFields.hs | 4 +- test/Spec.hs | 4 +- test/TestBoilerplate.hs | 22 ++++-- 13 files changed, 159 insertions(+), 57 deletions(-) create mode 100644 src/Data/Aeson/TypeScript/Instances/TupleGen.hs create mode 100644 test/MaybeTuples.hs diff --git a/aeson-typescript.cabal b/aeson-typescript.cabal index a448269..2387dd8 100644 --- a/aeson-typescript.cabal +++ b/aeson-typescript.cabal @@ -1,6 +1,6 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.37.0. +-- This file has been generated from package.yaml by hpack version 0.38.0. -- -- see: https://github.com/sol/hpack @@ -46,6 +46,7 @@ library other-modules: Data.Aeson.TypeScript.Formatting Data.Aeson.TypeScript.Instances + Data.Aeson.TypeScript.Instances.TupleGen Data.Aeson.TypeScript.Lookup Data.Aeson.TypeScript.Transform Data.Aeson.TypeScript.TypeManipulation @@ -89,6 +90,7 @@ test-suite aeson-typescript-tests GetDoc HigherKind LegalNameSpec + MaybeTuples NoOmitNothingFields ObjectWithSingleFieldNoTagSingleConstructors ObjectWithSingleFieldTagSingleConstructors @@ -106,6 +108,7 @@ test-suite aeson-typescript-tests Util.Aeson Data.Aeson.TypeScript.Formatting Data.Aeson.TypeScript.Instances + Data.Aeson.TypeScript.Instances.TupleGen Data.Aeson.TypeScript.Internal Data.Aeson.TypeScript.LegalName Data.Aeson.TypeScript.Lookup diff --git a/src/Data/Aeson/TypeScript/Instances.hs b/src/Data/Aeson/TypeScript/Instances.hs index 988aec0..2f61ce6 100644 --- a/src/Data/Aeson/TypeScript/Instances.hs +++ b/src/Data/Aeson/TypeScript/Instances.hs @@ -13,6 +13,7 @@ module Data.Aeson.TypeScript.Instances where import qualified Data.Aeson as A +import Data.Aeson.TypeScript.Instances.TupleGen import Data.Aeson.TypeScript.Types import Data.Data import Data.Functor.Compose (Compose) @@ -121,26 +122,8 @@ instance (TypeScript a, TypeScript b) => TypeScript (Either a b) where , (TSType (Proxy :: Proxy b)) ] -instance (TypeScript a, TypeScript b) => TypeScript (a, b) where - getTypeScriptType _ = [i|[#{getTypeScriptType (Proxy :: Proxy a)}, #{getTypeScriptType (Proxy :: Proxy b)}]|] - getParentTypes _ = L.nub [ (TSType (Proxy :: Proxy a)) - , (TSType (Proxy :: Proxy b)) - ] - -instance (TypeScript a, TypeScript b, TypeScript c) => TypeScript (a, b, c) where - getTypeScriptType _ = [i|[#{getTypeScriptType (Proxy :: Proxy a)}, #{getTypeScriptType (Proxy :: Proxy b)}, #{getTypeScriptType (Proxy :: Proxy c)}]|] - getParentTypes _ = L.nub [ (TSType (Proxy :: Proxy a)) - , (TSType (Proxy :: Proxy b)) - , (TSType (Proxy :: Proxy c)) - ] - -instance (TypeScript a, TypeScript b, TypeScript c, TypeScript d) => TypeScript (a, b, c, d) where - getTypeScriptType _ = [i|[#{getTypeScriptType (Proxy :: Proxy a)}, #{getTypeScriptType (Proxy :: Proxy b)}, #{getTypeScriptType (Proxy :: Proxy c)}, #{getTypeScriptType (Proxy :: Proxy d)}]|] - getParentTypes _ = L.nub [ (TSType (Proxy :: Proxy a)) - , (TSType (Proxy :: Proxy b)) - , (TSType (Proxy :: Proxy c)) - , (TSType (Proxy :: Proxy d)) - ] +-- Derive instance TypeScript (a, b), instance TypeScript (a, b, c), etc. up to size 10 +mkTupleInstances 10 instance forall a k (b :: k). (Typeable k, Typeable b, TypeScript a) => TypeScript (Const a b) where getTypeScriptType _ = getTypeScriptType (Proxy :: Proxy a) diff --git a/src/Data/Aeson/TypeScript/Instances/TupleGen.hs b/src/Data/Aeson/TypeScript/Instances/TupleGen.hs new file mode 100644 index 0000000..e4ca456 --- /dev/null +++ b/src/Data/Aeson/TypeScript/Instances/TupleGen.hs @@ -0,0 +1,36 @@ +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE QuasiQuotes #-} + +module Data.Aeson.TypeScript.Instances.TupleGen where + +import Data.Aeson.TypeScript.Types +import Data.Data +import Data.List (intercalate) +import qualified Data.List as L +import Language.Haskell.TH + + +mkTupleInstance :: Int -> Q Dec +mkTupleInstance n = do + let typeVars = take n $ map (mkName . (:[])) ['a'..] + constraints = map (\tv -> AppT (ConT ''TypeScript) (VarT tv)) typeVars + tupleType = foldl AppT (TupleT n) (map VarT typeVars) + instanceHead = AppT (ConT ''TypeScript) tupleType + + getTypeBody <- buildTypeBody typeVars + let getTypeMethod = FunD 'getTypeScriptType [Clause [WildP] (NormalB getTypeBody) []] + + let tsTypes = map (\tv -> AppE (ConE 'TSType) (SigE (ConE 'Proxy) (AppT (ConT ''Proxy) (VarT tv)))) typeVars + getParentsMethod = FunD 'getParentTypes [Clause [WildP] (NormalB (AppE (VarE 'L.nub) (ListE tsTypes))) []] + + return $ InstanceD Nothing constraints instanceHead [getTypeMethod, getParentsMethod] + +buildTypeBody :: [Name] -> Q Exp +buildTypeBody typeVars = do + let calls = map (\tv -> AppE (VarE 'getTypeScriptTypeOrOptionalNull) + (SigE (ConE 'Proxy) (AppT (ConT ''Proxy) (VarT tv)))) typeVars + parts = [LitE (StringL "[")] ++ intercalate [LitE (StringL ", ")] (map (:[]) calls) ++ [LitE (StringL "]")] + return $ foldr1 (\a b -> InfixE (Just a) (VarE '(++)) (Just b)) parts + +mkTupleInstances :: Int -> Q [Dec] +mkTupleInstances maxArity = mapM mkTupleInstance [2..maxArity] diff --git a/src/Data/Aeson/TypeScript/Recursive.hs b/src/Data/Aeson/TypeScript/Recursive.hs index 8eb673c..e5f5daa 100755 --- a/src/Data/Aeson/TypeScript/Recursive.hs +++ b/src/Data/Aeson/TypeScript/Recursive.hs @@ -32,7 +32,6 @@ import qualified Data.Set as S import Data.String.Interpolate import Language.Haskell.TH as TH import Language.Haskell.TH.Datatype -import Language.Haskell.TH.Syntax hiding (lift) getTransitiveClosure :: S.Set TSType -> S.Set TSType diff --git a/src/Data/Aeson/TypeScript/TH.hs b/src/Data/Aeson/TypeScript/TH.hs index 3cd7227..6f926cf 100644 --- a/src/Data/Aeson/TypeScript/TH.hs +++ b/src/Data/Aeson/TypeScript/TH.hs @@ -289,9 +289,7 @@ handleConstructor (ExtraTypeScriptOptions {..}) options (DatatypeInfo {..}) gene #if MIN_VERSION_aeson(0,10,0) | unwrapUnaryRecords options && (isSingleRecordConstructor ci) -> do let [typ] = constructorFields ci - stringExp <- lift $ case typ of - (AppT (ConT name) t) | name == ''Maybe && not (omitNothingFields options) -> [|$(getTypeAsStringExp t) <> " | null"|] - _ -> getTypeAsStringExp typ + stringExp <- lift $ [|getTypeScriptTypeOrOptionalNull (Proxy :: Proxy $(return typ))|] alternatives <- lift [|TSTypeAlternatives $(TH.stringE interfaceName) $(genericVariablesListExpr True genericVariables) [$(return stringExp)] @@ -309,9 +307,7 @@ handleConstructor (ExtraTypeScriptOptions {..}) options (DatatypeInfo {..}) gene tupleEncoding = do let typ = contentsTupleTypeSubstituted genericVariables ci - stringExp <- lift $ case typ of - (AppT (ConT name) t) | name == ''Maybe -> [|$(getTypeAsStringExp t) <> " | null"|] - _ -> getTypeAsStringExp typ + stringExp <- lift $ [|getTypeScriptTypeOrOptionalNull (Proxy :: Proxy $(return typ))|] lift [|TSTypeAlternatives $(TH.stringE interfaceName) $(genericVariablesListExpr True genericVariables) @@ -326,7 +322,7 @@ handleConstructor (ExtraTypeScriptOptions {..}) options (DatatypeInfo {..}) gene getTSFields :: WriterT [ExtraDeclOrGenericInfo] Q [Exp] 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) -> + (AppT (ConT name') t) | name' == ''Maybe && not (omitNothingFields options) -> ( , ) <$> [|$(getTypeAsStringExp t) <> " | null"|] <*> getOptionalAsBoolExp t _ -> ( , ) <$> getTypeAsStringExp typ <*> getOptionalAsBoolExp typ diff --git a/src/Data/Aeson/TypeScript/Types.hs b/src/Data/Aeson/TypeScript/Types.hs index a96f635..910ec73 100644 --- a/src/Data/Aeson/TypeScript/Types.hs +++ b/src/Data/Aeson/TypeScript/Types.hs @@ -70,6 +70,12 @@ class (Typeable a) => TypeScript a where -- ^ Special flag to indicate whether this type corresponds to a template variable. isGenericVariable _ = False + +getTypeScriptTypeOrOptionalNull :: TypeScript a => Proxy a -> String +getTypeScriptTypeOrOptionalNull proxy = getTypeScriptType proxy <> extra + where + extra = if getTypeScriptOptional proxy then " | null" else "" + -- | An existential wrapper for any TypeScript instance. data TSType = forall a. (Typeable a, TypeScript a) => TSType { unTSType :: Proxy a } diff --git a/src/Data/Aeson/TypeScript/Util.hs b/src/Data/Aeson/TypeScript/Util.hs index cedf0bf..29bff97 100644 --- a/src/Data/Aeson/TypeScript/Util.hs +++ b/src/Data/Aeson/TypeScript/Util.hs @@ -12,6 +12,7 @@ import Data.Aeson.TypeScript.Instances () import Data.Aeson.TypeScript.Types import qualified Data.List as L import Data.Proxy +import Data.String (IsString) import Data.String.Interpolate import qualified Data.Text as T import Language.Haskell.TH hiding (stringE) @@ -82,12 +83,12 @@ getTypeAsStringExp typ = [|getTypeScriptType (Proxy :: Proxy $(return typ))|] getOptionalAsBoolExp :: Type -> Q Exp getOptionalAsBoolExp typ = [|getTypeScriptOptional (Proxy :: Proxy $(return typ))|] --- | Helper to apply a type constructor to a list of type args +-- | Apply a type constructor to a list of type args applyToArgsT :: Type -> [Type] -> Type applyToArgsT constructor [] = constructor applyToArgsT constructor (x:xs) = applyToArgsT (AppT constructor x) xs --- | Helper to apply a function a list of args +-- | Apply a function to a list of args applyToArgsE :: Exp -> [Exp] -> Exp applyToArgsE f [] = f applyToArgsE f (x:xs) = applyToArgsE (AppE f x) xs @@ -183,6 +184,7 @@ mapType g (ImplicitParamT x typ) = ImplicitParamT x (mapType g typ) #endif mapType _ x = x +tryPromote :: (Eq a1, Eq a2, IsString a2) => Type -> [(a1, (a3, a2))] -> a1 -> Type tryPromote _ genericVariables (flip L.lookup genericVariables -> Just (_, "")) = ConT ''T tryPromote _ genericVariables (flip L.lookup genericVariables -> Just (_, "T")) = ConT ''T tryPromote _ genericVariables (flip L.lookup genericVariables -> Just (_, "T1")) = ConT ''T1 diff --git a/test/Basic.hs b/test/Basic.hs index a6c7a86..a8abb3e 100644 --- a/test/Basic.hs +++ b/test/Basic.hs @@ -17,9 +17,6 @@ data Unit2 = Unit2 $(deriveTypeScript (A.defaultOptions { A.tagSingleConstructors = True , A.constructorTagModifier = const "foo" }) ''Unit2) -data Test1 = Test1 (Maybe Int) -deriveTypeScript A.defaultOptions ''Test1 - tests :: SpecWith () tests = describe "Basic tests" $ do describe "tagSingleConstructors and constructorTagModifier" $ do @@ -29,17 +26,5 @@ tests = describe "Basic tests" $ do , TSTypeAlternatives "IUnit1" [] ["void[]"] Nothing ]) - it [i|Works with a unit with constructorTagModifier|] $ do - (getTypeScriptDeclarations (Proxy :: Proxy Unit2)) `shouldBe` ([ - TSTypeAlternatives "Unit2" [] ["\"foo\""] Nothing - ]) - - it [i|Maybe tuple encoding includes null option|] $ do - (getTypeScriptDeclarations (Proxy :: Proxy Test1)) `shouldBe` ([ - TSTypeAlternatives "Test1" [] ["ITest1"] Nothing - , TSTypeAlternatives "ITest1" [] ["number | null"] Nothing - ]) - - main :: IO () main = hspec tests diff --git a/test/MaybeTuples.hs b/test/MaybeTuples.hs new file mode 100644 index 0000000..d857f97 --- /dev/null +++ b/test/MaybeTuples.hs @@ -0,0 +1,78 @@ + +module MaybeTuples (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 + + +data Maybe1 = Maybe1 (Maybe Int) +deriveTypeScript A.defaultOptions ''Maybe1 + +data Maybe2 = Maybe2 String (Maybe Int) +deriveTypeScript A.defaultOptions ''Maybe2 + +data Maybe3 = Maybe3 String (String, String) (Maybe Int) +deriveTypeScript A.defaultOptions ''Maybe3 + +data Maybe4 = Maybe4 Int Int Int (Maybe Int) +deriveTypeScript A.defaultOptions ''Maybe4 + +data Maybe5 = Maybe5 Int Int Int Int (Maybe Int) +deriveTypeScript A.defaultOptions ''Maybe5 + +data Maybe6 = Maybe6 Int Int Int Int Int (Maybe Int) +deriveTypeScript A.defaultOptions ''Maybe6 + +data MaybeRecord = MaybeRecord { + foo :: String + , bar :: Maybe Int + } +deriveTypeScript A.defaultOptions ''MaybeRecord + +tests :: SpecWith () +tests = describe "Maybes in tuple encodings" $ do + describe "tagSingleConstructors and constructorTagModifier" $ do + it [i|Maybe 1 tuple encoding includes null option|] $ do + (getTypeScriptDeclarations (Proxy :: Proxy Maybe1)) `shouldBe` ([ + TSTypeAlternatives "Maybe1" [] ["IMaybe1"] Nothing + , TSTypeAlternatives "IMaybe1" [] ["number | null"] Nothing + ]) + + it [i|Maybe 2 tuple encoding includes null option|] $ do + (getTypeScriptDeclarations (Proxy :: Proxy Maybe2)) `shouldBe` ([ + TSTypeAlternatives "Maybe2" [] ["IMaybe2"] Nothing + , TSTypeAlternatives "IMaybe2" [] ["[string, number | null]"] Nothing + ]) + + it [i|Maybe 3 tuple encoding includes null option|] $ do + (getTypeScriptDeclarations (Proxy :: Proxy Maybe3)) `shouldBe` ([ + TSTypeAlternatives "Maybe3" [] ["IMaybe3"] Nothing + , TSTypeAlternatives "IMaybe3" [] ["[string, [string, string], number | null]"] Nothing + ]) + + it [i|Maybe 4 tuple encoding includes null option|] $ do + (getTypeScriptDeclarations (Proxy :: Proxy Maybe4)) `shouldBe` ([ + TSTypeAlternatives "Maybe4" [] ["IMaybe4"] Nothing + , TSTypeAlternatives "IMaybe4" [] ["[number, number, number, number | null]"] Nothing + ]) + + it [i|Maybe 5 tuple encoding includes null option|] $ do + (getTypeScriptDeclarations (Proxy :: Proxy Maybe5)) `shouldBe` ([ + TSTypeAlternatives "Maybe5" [] ["IMaybe5"] Nothing + , TSTypeAlternatives "IMaybe5" [] ["[number, number, number, number, number | null]"] Nothing + ]) + + it [i|Maybe 6 tuple encoding includes null option|] $ do + (getTypeScriptDeclarations (Proxy :: Proxy Maybe6)) `shouldBe` ([ + TSTypeAlternatives "Maybe6" [] ["IMaybe6"] Nothing + , TSTypeAlternatives "IMaybe6" [] ["[number, number, number, number, number, number | null]"] Nothing + ]) + + +main :: IO () +main = hspec tests diff --git a/test/NoOmitNothingFields.hs b/test/NoOmitNothingFields.hs index 148e822..4dd6dd8 100644 --- a/test/NoOmitNothingFields.hs +++ b/test/NoOmitNothingFields.hs @@ -13,9 +13,9 @@ $(testDeclarations "NoOmitNothingFields" (A.defaultOptions {omitNothingFields = allTests :: SpecWith () allTests = describe "NoOmitNothingFields" $ do it "encodes as expected" $ do - let decls = getTypeScriptDeclarations (Proxy :: Proxy Optional) + let decls = getTypeScriptDeclarations (Proxy :: Proxy OptionalRecord) - decls `shouldBe` [TSTypeAlternatives "Optional" [] ["IOptional"] Nothing - , TSInterfaceDeclaration "IOptional" [] [TSField False "optionalInt" "number | null" Nothing] Nothing] + decls `shouldBe` [TSTypeAlternatives "OptionalRecord" [] ["IOptionalRecord"] Nothing + , TSInterfaceDeclaration "IOptionalRecord" [] [TSField False "optionalInt" "number | null" Nothing] Nothing] tests diff --git a/test/OmitNothingFields.hs b/test/OmitNothingFields.hs index 360f2a1..f418b6f 100644 --- a/test/OmitNothingFields.hs +++ b/test/OmitNothingFields.hs @@ -13,10 +13,10 @@ $(testDeclarations "OmitNothingFields" (A.defaultOptions {omitNothingFields=True main :: IO () main = hspec $ describe "OmitNothingFields" $ do it "encodes as expected" $ do - let decls = getTypeScriptDeclarations (Proxy :: Proxy Optional) + let decls = getTypeScriptDeclarations (Proxy :: Proxy OptionalRecord) decls `shouldBe` [TSInterfaceDeclaration { - interfaceName = "Optional" + interfaceName = "OptionalRecord" , interfaceGenericVariables = [] , interfaceMembers = [ TSField True "optionalInt" "number" Nothing diff --git a/test/Spec.hs b/test/Spec.hs index d7f7548..11e0626 100644 --- a/test/Spec.hs +++ b/test/Spec.hs @@ -5,11 +5,12 @@ module Main where import Test.Hspec import qualified Basic +import qualified ClosedTypeFamilies import qualified Formatting import qualified Generic import qualified GetDoc import qualified HigherKind -import qualified ClosedTypeFamilies +import qualified MaybeTuples import qualified LegalNameSpec import qualified NoOmitNothingFields @@ -35,6 +36,7 @@ main = hspec $ parallel $ do GetDoc.tests #endif HigherKind.tests + MaybeTuples.tests LegalNameSpec.tests NoOmitNothingFields.allTests diff --git a/test/TestBoilerplate.hs b/test/TestBoilerplate.hs index 3b45997..bd4bd92 100644 --- a/test/TestBoilerplate.hs +++ b/test/TestBoilerplate.hs @@ -29,7 +29,9 @@ data TwoField = TwoField { doubleInt :: Int, doubleString :: String } data Hybrid = HybridSimple Int | HybridRecord { hybridString :: String } data TwoConstructor = Con1 { con1String :: String } | Con2 { con2String :: String, con2Int :: Int } data Complex a = Nullary | Unary Int | Product String Char a | Record { testOne :: Int, testTwo :: Bool, testThree :: Complex a} deriving Eq -data Optional = Optional {optionalInt :: Maybe Int} +data OptionalRecord = OptionalRecord {optionalInt :: Maybe Int} +data OptionalTuple1 = OptionalTuple1 (Maybe Int) +data OptionalTuple2 = OptionalTuple2 String (Maybe Int) data AesonTypes = AesonTypes { aesonValue :: A.Value, aesonObject :: A.Object } data Numbers = Numbers { natural :: Natural @@ -87,7 +89,9 @@ testDeclarations testName aesonOptions = do deriveInstances ''Hybrid deriveInstances ''TwoConstructor deriveInstances ''Complex - deriveInstances ''Optional + deriveInstances ''OptionalRecord + deriveInstances ''OptionalTuple1 + deriveInstances ''OptionalTuple2 deriveInstances ''AesonTypes deriveInstances ''Numbers deriveInstances ''FancyFunctors @@ -113,8 +117,14 @@ testDeclarations testName aesonOptions = do , (getTypeScriptType (Proxy :: Proxy (Complex Int)), A.encode (Product "asdf" 'g' 42 :: Complex Int)) , (getTypeScriptType (Proxy :: Proxy (Complex Int)), A.encode ((Record { testOne = 3, testTwo = True, testThree = Product "test" 'A' 123}) :: Complex Int)) - , (getTypeScriptType (Proxy :: Proxy Optional), A.encode (Optional { optionalInt = Nothing })) - , (getTypeScriptType (Proxy :: Proxy Optional), A.encode (Optional { optionalInt = Just 1 })) + , (getTypeScriptType (Proxy :: Proxy OptionalRecord), A.encode (OptionalRecord { optionalInt = Nothing })) + , (getTypeScriptType (Proxy :: Proxy OptionalRecord), A.encode (OptionalRecord { optionalInt = Just 1 })) + + , (getTypeScriptType (Proxy :: Proxy OptionalTuple1), A.encode (OptionalTuple1 Nothing)) + , (getTypeScriptType (Proxy :: Proxy OptionalTuple1), A.encode (OptionalTuple1 (Just 1))) + + , (getTypeScriptType (Proxy :: Proxy OptionalTuple2), A.encode (OptionalTuple2 "asdf" Nothing)) + , (getTypeScriptType (Proxy :: Proxy OptionalTuple2), A.encode (OptionalTuple2 "asdf" (Just 1))) , (getTypeScriptType (Proxy :: Proxy AesonTypes), A.encode (AesonTypes { aesonValue = A.object [("foo" :: AesonKey, A.Number 42)] @@ -133,7 +143,9 @@ testDeclarations testName aesonOptions = do <> getTypeScriptDeclarations (Proxy :: Proxy Hybrid) <> getTypeScriptDeclarations (Proxy :: Proxy TwoConstructor) <> getTypeScriptDeclarations (Proxy :: Proxy (Complex T)) - <> getTypeScriptDeclarations (Proxy :: Proxy Optional) + <> getTypeScriptDeclarations (Proxy :: Proxy OptionalRecord) + <> getTypeScriptDeclarations (Proxy :: Proxy OptionalTuple1) + <> getTypeScriptDeclarations (Proxy :: Proxy OptionalTuple2) <> getTypeScriptDeclarations (Proxy :: Proxy AesonTypes) <> getTypeScriptDeclarations (Proxy :: Proxy Numbers) <> getTypeScriptDeclarations (Proxy :: Proxy FancyFunctors)