From 97b06af0abef55f74f89b858f28aa36a27c463b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Sodi=C4=87?= Date: Wed, 22 Jan 2025 11:48:24 +0100 Subject: [PATCH] Make wasp ts config work with project references --- .../templates/react-app/tsconfig.app.json | 4 ++-- waspc/src/Wasp/AppSpec.hs | 7 ++++--- waspc/src/Wasp/Generator/WebAppGenerator.hs | 20 +++++++++++++++++-- waspc/src/Wasp/Project/Analyze.hs | 6 ++++-- waspc/src/Wasp/Project/Common.hs | 15 +++++++++----- waspc/src/Wasp/Project/ExternalConfig.hs | 10 ++++++---- waspc/src/Wasp/Project/WaspFile.hs | 2 +- waspc/src/Wasp/Util/IO.hs | 6 +++--- 8 files changed, 48 insertions(+), 22 deletions(-) diff --git a/waspc/data/Generator/templates/react-app/tsconfig.app.json b/waspc/data/Generator/templates/react-app/tsconfig.app.json index e7688c01f8..f96645ff4e 100644 --- a/waspc/data/Generator/templates/react-app/tsconfig.app.json +++ b/waspc/data/Generator/templates/react-app/tsconfig.app.json @@ -1,3 +1,4 @@ +{{={= =}=}} { "extends": "@tsconfig/vite-react/tsconfig.json", "compilerOptions": { @@ -14,7 +15,6 @@ "src" ], "references": [ - // TODO: It would be better to inject this knowledge from Haskell. - { "path": "../../../tsconfig.json" } + { "path": "{= srcTsConfigPath =}" } ] } diff --git a/waspc/src/Wasp/AppSpec.hs b/waspc/src/Wasp/AppSpec.hs index 639ffbb4e3..8bf6e2536a 100644 --- a/waspc/src/Wasp/AppSpec.hs +++ b/waspc/src/Wasp/AppSpec.hs @@ -28,7 +28,7 @@ where import Data.List (find) import Data.Maybe (fromMaybe, isJust) import Data.Text (Text) -import StrongPath (Abs, Dir, File', Path', Rel, ()) +import StrongPath (Abs, Dir, File, File', Path', Rel, ()) import Wasp.AppSpec.Action (Action) import Wasp.AppSpec.Api (Api) import Wasp.AppSpec.ApiNamespace (ApiNamespace) @@ -50,7 +50,7 @@ import Wasp.Env (EnvVar) import Wasp.ExternalConfig.PackageJson (PackageJson) import Wasp.ExternalConfig.TsConfig (TsConfig) import Wasp.Node.Version (oldestWaspSupportedNodeVersion) -import Wasp.Project.Common (WaspProjectDir) +import Wasp.Project.Common (SrcTsConfigFile, WaspProjectDir) import Wasp.Project.Db.Migrations (DbMigrationsDir) import qualified Wasp.Psl.Ast.Schema as Psl.Schema import qualified Wasp.SemanticVersion as SV @@ -91,7 +91,8 @@ data AppSpec = AppSpec -- | Connection URL for a database used during development. If provided, generated app will -- make sure to use it when run in development mode. devDatabaseUrl :: Maybe String, - customViteConfigPath :: Maybe (Path' (Rel WaspProjectDir) File') + customViteConfigPath :: Maybe (Path' (Rel WaspProjectDir) File'), + srcTsConfigPath :: Path' (Rel WaspProjectDir) (File SrcTsConfigFile) } -- TODO: Make this return "Named" declarations? diff --git a/waspc/src/Wasp/Generator/WebAppGenerator.hs b/waspc/src/Wasp/Generator/WebAppGenerator.hs index d24be10e9e..fff849a3ab 100644 --- a/waspc/src/Wasp/Generator/WebAppGenerator.hs +++ b/waspc/src/Wasp/Generator/WebAppGenerator.hs @@ -12,6 +12,7 @@ import Data.Maybe (fromJust) import qualified FilePath.Extra as FP.Extra import StrongPath ( Dir, + File, File', Path, Path', @@ -56,7 +57,7 @@ import Wasp.JsImport makeJsImport, ) import qualified Wasp.Node.Version as NodeVersion -import Wasp.Project.Common (dotWaspDirInWaspProjectDir, generatedCodeDirInDotWaspDir) +import Wasp.Project.Common (SrcTsConfigFile, dotWaspDirInWaspProjectDir, generatedCodeDirInDotWaspDir, waspProjectDirFromAppComponentDir) import qualified Wasp.Project.Common as Project import Wasp.Util ((<++>)) @@ -65,7 +66,7 @@ genWebApp spec = do sequence [ genFileCopy [relfile|README.md|], genFileCopy [relfile|tsconfig.json|], - genFileCopy [relfile|tsconfig.app.json|], + genAppTsConfigJson spec, genFileCopy [relfile|tsconfig.node.json|], genFileCopy [relfile|netlify.toml|], genPackageJson spec (npmDepsForWasp spec), @@ -80,6 +81,21 @@ genWebApp spec = do where genFileCopy = return . C.mkTmplFd +genAppTsConfigJson :: AppSpec -> Generator FileDraft +genAppTsConfigJson spec = do + return $ + C.mkTmplFdWithDstAndData + (C.asTmplFile [relfile|tsconfig.app.json|]) + (C.asWebAppFile [relfile|tsconfig.app.json|]) + ( Just $ + object + [ "srcTsConfigPath" .= SP.fromRelFile srcTsConfigPath + ] + ) + where + srcTsConfigPath :: Path' (Rel C.WebAppRootDir) (File SrcTsConfigFile) = + waspProjectDirFromAppComponentDir AS.srcTsConfigPath spec + genDotEnv :: AppSpec -> Generator [FileDraft] -- Don't generate .env if we are building for production, since .env is to be used only for -- development. diff --git a/waspc/src/Wasp/Project/Analyze.hs b/waspc/src/Wasp/Project/Analyze.hs index 63736555b0..0912c5b7e3 100644 --- a/waspc/src/Wasp/Project/Analyze.hs +++ b/waspc/src/Wasp/Project/Analyze.hs @@ -86,7 +86,8 @@ constructAppSpec waspDir options externalConfigs parsedPrismaSchema decls = do clientEnvVars <- readDotEnvClient waspDir let packageJsonContent = EC._packageJson externalConfigs - let tsConfigContent = EC._tsConfig externalConfigs + tsConfigContent = EC._tsConfig externalConfigs + srcTsConfigPath = EC._srcTsConfigPath externalConfigs let appSpec = AS.AppSpec @@ -104,7 +105,8 @@ constructAppSpec waspDir options externalConfigs parsedPrismaSchema decls = do AS.userDockerfileContents = maybeUserDockerfileContents, AS.configFiles = configFiles, AS.devDatabaseUrl = devDbUrl, - AS.customViteConfigPath = customViteConfigPath + AS.customViteConfigPath = customViteConfigPath, + AS.srcTsConfigPath = srcTsConfigPath } return $ runValidation ASV.validateAppSpec appSpec diff --git a/waspc/src/Wasp/Project/Common.hs b/waspc/src/Wasp/Project/Common.hs index 525e3343b2..ecf95e89b3 100644 --- a/waspc/src/Wasp/Project/Common.hs +++ b/waspc/src/Wasp/Project/Common.hs @@ -26,13 +26,14 @@ module Wasp.Project.Common srcTsConfigInWaspLangProject, srcTsConfigInWaspTsProject, waspProjectDirFromSrcDir, + waspProjectDirFromAppComponentDir, ) where import StrongPath (Abs, Dir, File, File', Path', Rel, reldir, relfile, toFilePath, ()) import System.Directory (doesFileExist) import Wasp.AppSpec.ExternalFiles (SourceExternalCodeDir, SourceExternalPublicDir) -import qualified Wasp.Generator.Common +import qualified Wasp.Generator.Common as Generator type CompileError = String @@ -66,24 +67,28 @@ nodeModulesDirInWaspProjectDir = [reldir|node_modules|] -- | NOTE: If you change the depth of this path, also update @waspProjectDirFromProjectRootDir@ below. -- TODO: Hm this has different name than it has in Generator. -generatedCodeDirInDotWaspDir :: Path' (Rel DotWaspDir) (Dir Wasp.Generator.Common.ProjectRootDir) +generatedCodeDirInDotWaspDir :: Path' (Rel DotWaspDir) (Dir Generator.ProjectRootDir) generatedCodeDirInDotWaspDir = [reldir|out|] -- | NOTE: If you change the depth of this path, also update @waspProjectDirFromProjectRootDir@ below. -buildDirInDotWaspDir :: Path' (Rel DotWaspDir) (Dir Wasp.Generator.Common.ProjectRootDir) +buildDirInDotWaspDir :: Path' (Rel DotWaspDir) (Dir Generator.ProjectRootDir) buildDirInDotWaspDir = [reldir|build|] +-- Todo: find a better way to define this +waspProjectDirFromAppComponentDir :: Generator.AppComponentRootDir d => Path' (Rel d) (Dir WaspProjectDir) +waspProjectDirFromAppComponentDir = [reldir|../../../|] + -- | NOTE: This path is calculated from the values of @dotWaspDirInWaspProjectDir@, -- @generatedCodeDirInDotWaspDir@ and @buildDirInDotWaspDir@., which are the three functions just above. -- Also, it assumes @generatedCodeDirInDotWaspDir@ and @buildDirInDotWaspDir@ have same depth. -- If any of those change significantly (their depth), this path should be adjusted. -waspProjectDirFromProjectRootDir :: Path' (Rel Wasp.Generator.Common.ProjectRootDir) (Dir WaspProjectDir) +waspProjectDirFromProjectRootDir :: Path' (Rel Generator.ProjectRootDir) (Dir WaspProjectDir) waspProjectDirFromProjectRootDir = [reldir|../../|] dotWaspRootFileInWaspProjectDir :: Path' (Rel WaspProjectDir) File' dotWaspRootFileInWaspProjectDir = [relfile|.wasproot|] -dotWaspInfoFileInGeneratedCodeDir :: Path' (Rel Wasp.Generator.Common.ProjectRootDir) File' +dotWaspInfoFileInGeneratedCodeDir :: Path' (Rel Generator.ProjectRootDir) File' dotWaspInfoFileInGeneratedCodeDir = [relfile|.waspinfo|] packageJsonInWaspProjectDir :: Path' (Rel WaspProjectDir) (File PackageJsonFile) diff --git a/waspc/src/Wasp/Project/ExternalConfig.hs b/waspc/src/Wasp/Project/ExternalConfig.hs index 742d67285d..4080491a61 100644 --- a/waspc/src/Wasp/Project/ExternalConfig.hs +++ b/waspc/src/Wasp/Project/ExternalConfig.hs @@ -18,7 +18,8 @@ import Wasp.Project.ExternalConfig.TsConfig (analyzeSrcTsConfigFile) data ExternalConfigs = ExternalConfigs { _packageJson :: P.PackageJson, - _tsConfig :: T.TsConfig + _tsConfig :: T.TsConfig, + _srcTsConfigPath :: Path' (Rel WaspProjectDir) (File SrcTsConfigFile) } deriving (Show) @@ -26,12 +27,13 @@ analyzeExternalConfigs :: Path' Abs (Dir WaspProjectDir) -> Path' (Rel WaspProjectDir) (File SrcTsConfigFile) -> IO (Either [CompileError] ExternalConfigs) -analyzeExternalConfigs waspDir srcTsConfigFile = runExceptT $ do +analyzeExternalConfigs waspDir srcTsConfigPath = runExceptT $ do packageJsonContent <- ExceptT $ analyzePackageJsonFile waspDir - tsConfigContent <- ExceptT $ analyzeSrcTsConfigFile waspDir srcTsConfigFile + tsConfigContent <- ExceptT $ analyzeSrcTsConfigFile waspDir srcTsConfigPath return $ ExternalConfigs { _packageJson = packageJsonContent, - _tsConfig = tsConfigContent + _tsConfig = tsConfigContent, + _srcTsConfigPath = srcTsConfigPath } diff --git a/waspc/src/Wasp/Project/WaspFile.hs b/waspc/src/Wasp/Project/WaspFile.hs index 82502ca07a..afaac24c19 100644 --- a/waspc/src/Wasp/Project/WaspFile.hs +++ b/waspc/src/Wasp/Project/WaspFile.hs @@ -42,7 +42,7 @@ findWaspFile waspDir = do . (waspDir ) <$> find ((suffix `isSuffixOf`) . fromRelFile) files - fileNotFoundMessage = "Couldn't find the *.wasp or a *.wasp.ts file in the " ++ fromAbsDir waspDir ++ " directory" + fileNotFoundMessage = "Couldn't find a *.wasp or a *.wasp.ts file in the directory " ++ fromAbsDir waspDir ++ " ." bothFilesFoundMessage = "Found both *.wasp and *.wasp.ts files in the project directory. " ++ "You must choose how you want to define your app (using Wasp or TypeScript) and only keep one of them." diff --git a/waspc/src/Wasp/Util/IO.hs b/waspc/src/Wasp/Util/IO.hs index f91aaf8e0e..0f86df3ed0 100644 --- a/waspc/src/Wasp/Util/IO.hs +++ b/waspc/src/Wasp/Util/IO.hs @@ -66,7 +66,7 @@ listDirectoryDeep absDirPath = do -- TODO: write tests. -- | Lists files and directories at top lvl of the directory. -listDirectory :: forall d f. Path' Abs (Dir d) -> IO ([Path' (Rel d) (File f)], [Path' (Rel d) Dir']) +listDirectory :: forall r f d. Path' Abs (Dir r) -> IO ([Path' (Rel r) (File f)], [Path' (Rel r) (Dir d)]) listDirectory absDirPath = do fpRelItemPaths <- SD.listDirectory fpAbsDirPath relFilePaths <- filterFiles fpAbsDirPath fpRelItemPaths @@ -76,12 +76,12 @@ listDirectory absDirPath = do fpAbsDirPath :: FilePath fpAbsDirPath = toFilePath absDirPath - filterFiles :: FilePath -> [FilePath] -> IO [Path' (Rel d) (File f)] + filterFiles :: FilePath -> [FilePath] -> IO [Path' (Rel r) (File f)] filterFiles absDir relItems = filterM (SD.doesFileExist . (absDir FilePath.)) relItems >>= mapM parseRelFile - filterDirs :: FilePath -> [FilePath] -> IO [Path' (Rel d) Dir'] + filterDirs :: FilePath -> [FilePath] -> IO [Path' (Rel r) (Dir d)] filterDirs absDir relItems = filterM (SD.doesDirectoryExist . (absDir FilePath.)) relItems >>= mapM parseRelDir