-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Using TS SDK from waspc
#2276
Using TS SDK from waspc
#2276
Changes from 16 commits
e228263
664eafe
1b75ab9
0c7b901
b7c4800
68bfe30
0758747
b7ecab4
e2e802e
2d27900
987243d
15e3e68
7600288
2b0c0ff
7ec9356
1597f4b
b887cd8
1bdc871
52378c4
115dce5
2617b6f
32275e5
b673308
3513b68
e9ef283
0dc7435
3e9efc8
24f65ec
edd7a85
ae76820
7eab0bc
8c8cb4f
d0ba9e5
4eec3c1
1699df2
5a6719e
3f48b98
67f1f9e
522e131
8ab0b3f
d90b235
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This file has a lot of diverse imports, indicating that it might want to be split into multiple files. I think we should split it probably -> we could certainly separate the logic that deals with WaspFile, and maybe then further split that into WaspLang and WaspTs logic, but not yet sure about that. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought about extracting a But yeah, if you like it too, I'll do it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Leaving this one for later. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done in #2407 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,26 @@ | ||
module Wasp.Project.Analyze | ||
( analyzeWaspProject, | ||
readPackageJsonFile, | ||
analyzeWaspFileContent, | ||
findWaspFile, | ||
findPackageJsonFile, | ||
analyzePrismaSchema, | ||
WaspFile (..), | ||
) | ||
where | ||
|
||
import Control.Applicative ((<|>)) | ||
import Control.Arrow (ArrowChoice (left)) | ||
import Control.Concurrent (newChan) | ||
import Control.Concurrent.Async (concurrently) | ||
import Control.Monad.Except (ExceptT (..), runExceptT) | ||
import Control.Monad.IO.Class (liftIO) | ||
import qualified Data.Aeson as Aeson | ||
import Data.Conduit.Process.Typed (ExitCode (..)) | ||
import Data.List (find, isSuffixOf) | ||
import StrongPath (Abs, Dir, File', Path', toFilePath, (</>)) | ||
import StrongPath (Abs, Dir, File', Path', Rel, toFilePath, (</>)) | ||
import qualified StrongPath as SP | ||
import StrongPath.TH (relfile) | ||
import StrongPath.Types (File) | ||
sodic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
import qualified Wasp.Analyzer as Analyzer | ||
import Wasp.Analyzer.AnalyzeError (getErrorMessageAndCtx) | ||
import Wasp.Analyzer.Parser.Ctx (Ctx) | ||
|
@@ -23,10 +32,14 @@ import qualified Wasp.CompileOptions as CompileOptions | |
import qualified Wasp.ConfigFile as CF | ||
import Wasp.Error (showCompilerErrorForTerminal) | ||
import qualified Wasp.Generator.ConfigFile as G.CF | ||
import qualified Wasp.Generator.Job as J | ||
import Wasp.Generator.Job.IO (readJobMessagesAndPrintThemPrefixed) | ||
import Wasp.Generator.Job.Process (runNodeCommandAsJob) | ||
Comment on lines
+43
to
+45
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this is used here, then it sounds like it maybe shouldn't be in the Generator hm. What do you think? I didn't check the code though to see if there is anything Generator specific about it really or not. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're right, nice catch. I didn't notice it was there. And there's nothing generator-specific about it. I think it's just there because the generator used to be the only one running jobs. I'll move it somewhere more appropriate. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Leaving this one for later. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done in #2407 |
||
import Wasp.Project.Common | ||
( CompileError, | ||
CompileWarning, | ||
WaspProjectDir, | ||
dotWaspDirInWaspProjectDir, | ||
findFileInWaspProjectDir, | ||
packageJsonInWaspProjectDir, | ||
prismaSchemaFileInWaspProjectDir, | ||
|
@@ -60,7 +73,7 @@ analyzeWaspProject waspDir options = do | |
(Left prismaSchemaErrors, prismaSchemaWarnings) -> return (Left prismaSchemaErrors, prismaSchemaWarnings) | ||
-- NOTE: we are ignoring prismaSchemaWarnings if the schema was parsed successfully | ||
(Right prismaSchemaAst, _) -> | ||
analyzeWaspFile prismaSchemaAst waspFilePath >>= \case | ||
analyzeWaspFile waspDir prismaSchemaAst waspFilePath >>= \case | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, I prefer keeping the |
||
Left errors -> return (Left errors, []) | ||
Right declarations -> | ||
analyzePackageJsonContent waspDir >>= \case | ||
|
@@ -69,8 +82,109 @@ analyzeWaspProject waspDir options = do | |
where | ||
fileNotFoundMessage = "Couldn't find the *.wasp file in the " ++ toFilePath waspDir ++ " directory" | ||
|
||
analyzeWaspFile :: Psl.Schema.Schema -> Path' Abs File' -> IO (Either [CompileError] [AS.Decl]) | ||
analyzeWaspFile prismaSchemaAst waspFilePath = do | ||
data WaspFile | ||
sodic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
= WaspLang !(Path' Abs (File WaspLangFile)) | ||
| WaspTs !(Path' Abs (File WaspTsFile)) | ||
|
||
data WaspLangFile | ||
|
||
data WaspTsFile | ||
sodic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
data CompiledWaspJsFile | ||
|
||
data SpecJsonFile | ||
|
||
analyzeWaspFile :: Path' Abs (Dir WaspProjectDir) -> Psl.Schema.Schema -> WaspFile -> IO (Either [CompileError] [AS.Decl]) | ||
analyzeWaspFile waspDir prismaSchemaAst = \case | ||
WaspLang waspFilePath -> analyzeWaspLangFile prismaSchemaAst waspFilePath | ||
WaspTs waspFilePath -> analyzeWaspTsFile waspDir prismaSchemaAst waspFilePath | ||
|
||
analyzeWaspTsFile :: Path' Abs (Dir WaspProjectDir) -> Psl.Schema.Schema -> Path' Abs (File WaspTsFile) -> IO (Either [CompileError] [AS.Decl]) | ||
analyzeWaspTsFile waspProjectDir _prismaSchemaAst _waspFilePath = runExceptT $ do | ||
-- TODO: I'm not yet sure where tsconfig.node.json location will come from | ||
-- because we also need that knowledge to generate a TS SDK project. | ||
compiledWaspJsFile <- ExceptT $ compileWaspTsFile waspProjectDir [relfile|tsconfig.node.json|] | ||
specJsonFile <- ExceptT $ executeMainWaspJsFile waspProjectDir compiledWaspJsFile | ||
contents <- ExceptT $ readDeclsJsonFile specJsonFile | ||
liftIO $ putStrLn "Here are the contents of the spec file:" | ||
liftIO $ print contents | ||
return [] | ||
|
||
-- TODO: Reconsider the return value. Can I write the function in such a way | ||
-- that it's impossible to get the absolute path to the compiled file without | ||
-- calling the function that compiles it? | ||
-- To do that, I'd have to craete a private module that knows where the file is | ||
-- and not expose the constant for creating the absoltue path (like I did with config/spec.json). | ||
-- Normally, I could just put the constant in the where clause like I did there, but I'm hesitant | ||
-- to do that since the path comes from the tsconfig. | ||
-- That is what I did currently, but I'll have to figure out the long-term solution. | ||
-- The ideal solution is reading the TS file, and passing its config to tsc | ||
-- manually (and getting the output file path in the process). | ||
compileWaspTsFile :: | ||
Path' Abs (Dir WaspProjectDir) -> | ||
Path' (Rel WaspProjectDir) File' -> | ||
IO (Either [CompileError] (Path' Abs (File CompiledWaspJsFile))) | ||
sodic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
compileWaspTsFile waspProjectDir tsconfigNodeFileInWaspProjectDir = do | ||
infomiho marked this conversation as resolved.
Show resolved
Hide resolved
|
||
chan <- newChan | ||
(_, tscExitCode) <- | ||
concurrently | ||
(readJobMessagesAndPrintThemPrefixed chan) | ||
( runNodeCommandAsJob | ||
sodic marked this conversation as resolved.
Show resolved
Hide resolved
sodic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
waspProjectDir | ||
"npx" | ||
[ "tsc", | ||
"-p", | ||
toFilePath (waspProjectDir </> tsconfigNodeFileInWaspProjectDir), | ||
sodic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"--noEmit", | ||
"false", | ||
"--outDir", | ||
toFilePath $ SP.parent absCompiledWaspJsFile | ||
] | ||
J.Wasp | ||
chan | ||
) | ||
case tscExitCode of | ||
ExitFailure _status -> return $ Left ["Error while running TypeScript compiler on the *.wasp.mts file."] | ||
ExitSuccess -> return $ Right absCompiledWaspJsFile | ||
where | ||
-- TODO: I should be getting the compiled file path from the tsconfig.node.file | ||
absCompiledWaspJsFile = waspProjectDir </> dotWaspDirInWaspProjectDir </> [relfile|config/main.wasp.mjs|] | ||
|
||
executeMainWaspJsFile :: Path' Abs (Dir WaspProjectDir) -> Path' Abs (File CompiledWaspJsFile) -> IO (Either [CompileError] (Path' Abs (File SpecJsonFile))) | ||
executeMainWaspJsFile waspProjectDir absCompiledMainWaspJsFile = do | ||
chan <- newChan | ||
(_, runExitCode) <- do | ||
concurrently | ||
(readJobMessagesAndPrintThemPrefixed chan) | ||
( runNodeCommandAsJob | ||
waspProjectDir | ||
"npx" | ||
-- TODO: Figure out how to keep running instructions in a single place | ||
-- (e.g., this is the same as the package name, but it's repeated in two places). | ||
-- Before this, I had the entrypoint file hardcoded, which was bad | ||
-- too: waspProjectDir </> [relfile|node_modules/wasp-config/dist/run.js|] | ||
[ "wasp-config", | ||
SP.fromAbsFile absCompiledMainWaspJsFile, | ||
sodic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
SP.fromAbsFile absSpecOutputFile | ||
] | ||
J.Wasp | ||
chan | ||
) | ||
case runExitCode of | ||
ExitFailure _status -> return $ Left ["Error while running the compiled *.wasp.mts file."] | ||
ExitSuccess -> return $ Right absSpecOutputFile | ||
where | ||
-- TODO: The config part of the path is problematic because it relies on TSC to create it during compilation, | ||
-- see notes in compileWaspFile. | ||
absSpecOutputFile = waspProjectDir </> dotWaspDirInWaspProjectDir </> [relfile|config/spec.json|] | ||
|
||
readDeclsJsonFile :: Path' Abs (File SpecJsonFile) -> IO (Either [CompileError] Aeson.Value) | ||
readDeclsJsonFile declsJsonFile = do | ||
byteString <- IOUtil.readFile declsJsonFile | ||
return $ Right $ Aeson.toJSON byteString | ||
|
||
analyzeWaspLangFile :: Psl.Schema.Schema -> Path' Abs (File WaspLangFile) -> IO (Either [CompileError] [AS.Decl]) | ||
analyzeWaspLangFile prismaSchemaAst waspFilePath = do | ||
waspFileContent <- IOUtil.readFile waspFilePath | ||
left (map $ showCompilerErrorForTerminal (waspFilePath, waspFileContent)) | ||
<$> analyzeWaspFileContent prismaSchemaAst waspFileContent | ||
|
@@ -118,15 +232,14 @@ constructAppSpec waspDir options packageJson parsedPrismaSchema decls = do | |
|
||
return $ runValidation ASV.validateAppSpec appSpec | ||
|
||
findWaspFile :: Path' Abs (Dir WaspProjectDir) -> IO (Maybe (Path' Abs File')) | ||
findWaspFile :: Path' Abs (Dir WaspProjectDir) -> IO (Maybe WaspFile) | ||
findWaspFile waspDir = do | ||
files <- fst <$> IOUtil.listDirectory waspDir | ||
return $ (waspDir </>) <$> find isWaspFile files | ||
return $ findWaspTsFile files <|> findWaspLangFile files | ||
sodic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
where | ||
isWaspFile path = | ||
".wasp" | ||
`isSuffixOf` toFilePath path | ||
&& (length (toFilePath path) > length (".wasp" :: String)) | ||
findWaspTsFile files = WaspTs <$> findFileThatEndsWith ".wasp.mts" files | ||
sodic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
findWaspLangFile files = WaspLang <$> findFileThatEndsWith ".wasp" files | ||
findFileThatEndsWith suffix files = SP.castFile . (waspDir </>) <$> find ((suffix `isSuffixOf`) . toFilePath) files | ||
infomiho marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
analyzePackageJsonContent :: Path' Abs (Dir WaspProjectDir) -> IO (Either [CompileError] PackageJson) | ||
analyzePackageJsonContent waspProjectDir = | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't have something like
data WaspFile
, so that we could doPath' Abs (File WaspFile)
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice catch. We didn't before, but we'll have it now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll take care of this later. It requires dealing with cyclic dependencies.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Solved in #2407