Generate all JS import statements in Haskell (#956)

This commit is contained in:
Mihovil Ilakovac 2023-02-13 16:57:31 +01:00 committed by GitHub
parent b79f694eef
commit 07b03fec5d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 351 additions and 115 deletions

View File

@ -7,7 +7,7 @@ import createAuthRequiredPage from "./auth/pages/createAuthRequiredPage.js"
{=/ isAuthEnabled =}
{=# pagesToImport =}
import {= importWhat =} from "{= importFrom =}"
{=& importStatement =}
{=/ pagesToImport =}
{=# isExternalAuthEnabled =}

View File

@ -1,8 +1,7 @@
{{={= =}=}}
import { handleRejection } from '../../utils.js'
import {= operationName =} from "{= operationImportPath =}"
{=& operationImportStmt =}
export default handleRejection(async (req, res) => {
const args = req.body || {}

View File

@ -1,7 +1,7 @@
{{={= =}=}}
import { handleRejection } from '../../utils.js'
import {= operationName =} from "{= operationImportPath =}"
{=& operationImportStmt =}
export default handleRejection(async (req, res) => {
{=! TODO: When generating express route for query, generated code would be most human-like if we

View File

@ -6,7 +6,7 @@ import auth from '../../core/auth.js'
{=/ isAuthEnabled =}
{=# operationRoutes =}
import {= importIdentifier =} from '{= importPath =}'
{=& importStatement =}
{=/ operationRoutes =}
const router = express.Router()

View File

@ -403,7 +403,7 @@
"file",
"web-app/src/router.js"
],
"65a91308a13f2c8444e3ad7372c1fca85a194b85e8f8f7d11613f78fcfe7af6f"
"62928b69543a870338ab09c2f7493ec7594993bc4f2922052da3c3a9d804e0cd"
],
[
[

View File

@ -2,7 +2,7 @@ import React from 'react'
import { Route, BrowserRouter as Router } from 'react-router-dom'
import MainPage from "./ext-src/MainPage"
import MainPage from './ext-src/MainPage'
const router = (

View File

@ -403,7 +403,7 @@
"file",
"web-app/src/router.js"
],
"65a91308a13f2c8444e3ad7372c1fca85a194b85e8f8f7d11613f78fcfe7af6f"
"62928b69543a870338ab09c2f7493ec7594993bc4f2922052da3c3a9d804e0cd"
],
[
[

View File

@ -2,7 +2,7 @@ import React from 'react'
import { Route, BrowserRouter as Router } from 'react-router-dom'
import MainPage from "./ext-src/MainPage"
import MainPage from './ext-src/MainPage'
const router = (

View File

@ -130,7 +130,7 @@
"file",
"server/src/jobs/MySpecialJob.js"
],
"69926a4b7eafc2e80e50732fee80865625c06f74004cbcd7be1701b4ce9249eb"
"9bf6a5f7005d3ab4ca933fb239ef21f13ba68aef30d8767230d6cc03911ca0e1"
],
[
[
@ -417,7 +417,7 @@
"file",
"web-app/src/router.js"
],
"65a91308a13f2c8444e3ad7372c1fca85a194b85e8f8f7d11613f78fcfe7af6f"
"62928b69543a870338ab09c2f7493ec7594993bc4f2922052da3c3a9d804e0cd"
],
[
[

View File

@ -1,6 +1,6 @@
import prisma from '../dbClient.js'
import { createJob } from './core/pgBoss/pgBossJob.js'
import { foo } from './../ext-src/jobs/bar.js'
import { foo } from '../ext-src/jobs/bar.js'
export const MySpecialJob = createJob({
jobName: "MySpecialJob",

View File

@ -2,7 +2,7 @@ import React from 'react'
import { Route, BrowserRouter as Router } from 'react-router-dom'
import MainPage from "./ext-src/MainPage"
import MainPage from './ext-src/MainPage'
const router = (

View File

@ -403,7 +403,7 @@
"file",
"web-app/src/router.js"
],
"65a91308a13f2c8444e3ad7372c1fca85a194b85e8f8f7d11613f78fcfe7af6f"
"62928b69543a870338ab09c2f7493ec7594993bc4f2922052da3c3a9d804e0cd"
],
[
[

View File

@ -2,7 +2,7 @@ import React from 'react'
import { Route, BrowserRouter as Router } from 'react-router-dom'
import MainPage from "./ext-src/MainPage"
import MainPage from './ext-src/MainPage'
const router = (

View File

@ -9,6 +9,7 @@ module Wasp.Generator.Common
npmVersionRange,
prismaVersion,
makeJsonWithEntityData,
GeneratedSrcDir,
)
where
@ -20,6 +21,10 @@ import Wasp.Util (toLowerFirst)
-- | Directory where the whole web app project (client, server, ...) is generated.
data ProjectRootDir
-- | Type representing top-level src/ dir in an app component (e.g. in web app or in server).
-- Examples: web-app/src/, server/src/, ... .
class GeneratedSrcDir d
class AppComponentRootDir d
data ServerRootDir

View File

@ -1,26 +1,34 @@
module Wasp.Generator.JsImport
( getJsImportDetailsForExtFnImport,
( extImportToJsImport,
PathFromImportLocationToSrcDir,
)
where
import StrongPath (Dir, Path, Posix, Rel, (</>))
import StrongPath (Dir, File', Path, Posix, Rel, (</>))
import qualified StrongPath as SP
import qualified Wasp.AppSpec.ExtImport as AS.ExtImport
import qualified Wasp.AppSpec.ExtImport as EI
import Wasp.Generator.Common (GeneratedSrcDir)
import Wasp.Generator.ExternalCodeGenerator.Common (GeneratedExternalCodeDir)
import Wasp.JsImport
( JsImport,
JsImportName (JsImportField, JsImportModule),
makeJsImport,
)
getJsImportDetailsForExtFnImport ::
-- | Path to generated external code directory, relative to the directory in which file doing the importing is.
Path Posix (Rel a) (Dir GeneratedExternalCodeDir) ->
AS.ExtImport.ExtImport ->
-- | (importIdentifier, importStmt)
-- - importIdentifier -> Identifier via which you can access ext js function after you import it with importStmt.
-- - importStmt -> Javascript import statement via which you should do the import.
(String, String)
getJsImportDetailsForExtFnImport relPosixPathToExtCodeDir extImport = (importIdentifier, importStmt)
type PathFromImportLocationToSrcDir d = Path Posix (Rel ()) (Dir d)
extImportToJsImport ::
GeneratedSrcDir d =>
Path Posix (Rel d) (Dir GeneratedExternalCodeDir) ->
PathFromImportLocationToSrcDir d ->
EI.ExtImport ->
JsImport
extImportToJsImport pathFromSrcDirToExtCodeDir pathFromImportLocationToSrcDir extImport = makeJsImport importPath importName
where
importStmt = "import " ++ importWhat ++ " from '" ++ importFrom ++ "'"
importFrom = "./" ++ SP.fromRelFileP (relPosixPathToExtCodeDir </> SP.castRel (AS.ExtImport.path extImport))
(importIdentifier, importWhat) =
case AS.ExtImport.name extImport of
AS.ExtImport.ExtImportModule defaultImport -> (defaultImport, defaultImport)
AS.ExtImport.ExtImportField namedImport -> (namedImport, "{ " ++ namedImport ++ " }")
userDefinedPathInExtSrcDir = SP.castRel $ EI.path extImport :: Path Posix (Rel GeneratedExternalCodeDir) File'
importName = extImportNameToJsImportName $ EI.name extImport
importPath = SP.castRel $ pathFromImportLocationToSrcDir </> pathFromSrcDirToExtCodeDir </> userDefinedPathInExtSrcDir
extImportNameToJsImportName :: EI.ExtImportName -> JsImportName
extImportNameToJsImportName (EI.ExtImportModule name) = JsImportModule name
extImportNameToJsImportName (EI.ExtImportField name) = JsImportField name

View File

@ -22,8 +22,8 @@ import StrongPath
Path',
Posix,
Rel,
relDirToPosix,
reldir,
reldirP,
relfile,
(</>),
)
@ -45,17 +45,16 @@ import Wasp.Generator.Common
prismaVersion,
)
import Wasp.Generator.ExternalCodeGenerator (genExternalCodeDir)
import Wasp.Generator.ExternalCodeGenerator.Common (GeneratedExternalCodeDir)
import Wasp.Generator.FileDraft (FileDraft, createCopyFileDraft)
import Wasp.Generator.JsImport (getJsImportDetailsForExtFnImport)
import Wasp.Generator.Monad (Generator)
import qualified Wasp.Generator.NpmDependencies as N
import Wasp.Generator.ServerGenerator.AuthG (genAuth)
import qualified Wasp.Generator.ServerGenerator.Common as C
import Wasp.Generator.ServerGenerator.ConfigG (genConfigFile)
import Wasp.Generator.ServerGenerator.ExternalAuthG (depsRequiredByPassport)
import Wasp.Generator.ServerGenerator.ExternalCodeGenerator (extServerCodeDirInServerSrcDir, extServerCodeGeneratorStrategy, extSharedCodeGeneratorStrategy)
import Wasp.Generator.ServerGenerator.ExternalCodeGenerator (extServerCodeGeneratorStrategy, extSharedCodeGeneratorStrategy)
import Wasp.Generator.ServerGenerator.JobGenerator (depsRequiredByJobs, genJobExecutors, genJobs)
import Wasp.Generator.ServerGenerator.JsImport (getJsImportStmtAndIdentifier)
import Wasp.Generator.ServerGenerator.OperationsG (genOperations)
import Wasp.Generator.ServerGenerator.OperationsRoutesG (genOperationsRoutes)
import Wasp.SemanticVersion (major)
@ -221,12 +220,12 @@ genServerJs spec =
)
where
maybeSetupJsFunction = AS.App.Server.setupFn =<< AS.App.server (snd $ getApp spec)
maybeSetupJsFnImportDetails = getJsImportDetailsForExtFnImport extServerCodeDirInServerSrcDirP <$> maybeSetupJsFunction
(maybeSetupJsFnImportIdentifier, maybeSetupJsFnImportStmt) =
maybeSetupJsFnImportDetails = getJsImportStmtAndIdentifier relPathToServerSrcDir <$> maybeSetupJsFunction
(maybeSetupJsFnImportStmt, maybeSetupJsFnImportIdentifier) =
(fst <$> maybeSetupJsFnImportDetails, snd <$> maybeSetupJsFnImportDetails)
extServerCodeDirInServerSrcDirP :: Path Posix (Rel C.ServerSrcDir) (Dir GeneratedExternalCodeDir)
extServerCodeDirInServerSrcDirP = fromJust $ relDirToPosix extServerCodeDirInServerSrcDir
relPathToServerSrcDir :: Path Posix (Rel ()) (Dir C.ServerSrcDir)
relPathToServerSrcDir = [reldirP|./|]
genRoutesDir :: AppSpec -> Generator [FileDraft]
genRoutesDir spec =

View File

@ -23,7 +23,7 @@ import StrongPath (Dir, File', Path', Rel, reldir, relfile, (</>))
import qualified StrongPath as SP
import System.FilePath (splitExtension)
import Wasp.Common (WaspProjectDir)
import Wasp.Generator.Common (ProjectRootDir, ServerRootDir)
import Wasp.Generator.Common (GeneratedSrcDir, ProjectRootDir, ServerRootDir)
import Wasp.Generator.FileDraft (FileDraft, createTemplateFileDraft)
import Wasp.Generator.Templates (TemplatesDir)
@ -33,6 +33,8 @@ data ServerTemplatesDir
data ServerTemplatesSrcDir
instance GeneratedSrcDir ServerSrcDir
asTmplFile :: Path' (Rel d) File' -> Path' (Rel ServerTemplatesDir) File'
asTmplFile = SP.castRel

View File

@ -6,7 +6,7 @@ where
import Data.Aeson (object, (.=))
import qualified Data.Aeson as Aeson
import Data.Maybe (fromJust, fromMaybe, isJust)
import Data.Maybe (fromMaybe, isJust)
import StrongPath
( Dir,
File',
@ -26,12 +26,10 @@ import qualified Wasp.AppSpec.App.Auth as AS.App.Auth
import qualified Wasp.AppSpec.App.Auth as AS.Auth
import qualified Wasp.AppSpec.App.Dependency as App.Dependency
import Wasp.AppSpec.Valid (getApp)
import Wasp.Generator.ExternalCodeGenerator.Common (GeneratedExternalCodeDir)
import Wasp.Generator.FileDraft (FileDraft)
import Wasp.Generator.JsImport (getJsImportDetailsForExtFnImport)
import Wasp.Generator.Monad (Generator)
import qualified Wasp.Generator.ServerGenerator.Common as C
import Wasp.Generator.ServerGenerator.ExternalCodeGenerator (extServerCodeDirInServerSrcDir)
import Wasp.Generator.ServerGenerator.JsImport (getJsImportStmtAndIdentifier)
import Wasp.Generator.WebAppGenerator.ExternalAuthG (ExternalAuthInfo (..), gitHubAuthInfo, googleAuthInfo, templateFilePathInPassportDir)
import Wasp.Util ((<++>))
@ -135,16 +133,17 @@ getTmplDataForAuthMethodConfig auth authMethod =
"getUserFieldsFnIdentifier" .= fromMaybe "" maybeOnSignInFnImportIdentifier
]
where
getJsImportStmtAndIdentifier' = getJsImportStmtAndIdentifier relPathFromAuthConfigToServerSrcDir
maybeConfigFn = AS.Auth.configFn =<< authMethod (AS.Auth.methods auth)
maybeConfigFnImportDetails = getJsImportDetailsForExtFnImport relPosixPathFromAuthMethodDirToExtSrcDir <$> maybeConfigFn
(maybeConfigFnImportIdentifier, maybeConfigFnImportStmt) = (fst <$> maybeConfigFnImportDetails, snd <$> maybeConfigFnImportDetails)
maybeConfigFnImportDetails = getJsImportStmtAndIdentifier' <$> maybeConfigFn
(maybeConfigFnImportStmt, maybeConfigFnImportIdentifier) = (fst <$> maybeConfigFnImportDetails, snd <$> maybeConfigFnImportDetails)
maybeGetUserFieldsFn = AS.Auth.getUserFieldsFn =<< authMethod (AS.Auth.methods auth)
maybeOnSignInFnImportDetails = getJsImportDetailsForExtFnImport relPosixPathFromAuthMethodDirToExtSrcDir <$> maybeGetUserFieldsFn
(maybeOnSignInFnImportIdentifier, maybeOnSignInFnImportStmt) = (fst <$> maybeOnSignInFnImportDetails, snd <$> maybeOnSignInFnImportDetails)
maybeOnSignInFnImportDetails = getJsImportStmtAndIdentifier' <$> maybeGetUserFieldsFn
(maybeOnSignInFnImportStmt, maybeOnSignInFnImportIdentifier) = (fst <$> maybeOnSignInFnImportDetails, snd <$> maybeOnSignInFnImportDetails)
relPosixPathFromAuthMethodDirToExtSrcDir :: Path Posix (Rel (Dir C.ServerSrcDir)) (Dir GeneratedExternalCodeDir)
relPosixPathFromAuthMethodDirToExtSrcDir = [reldirP|../../../../|] </> fromJust (SP.relDirToPosix extServerCodeDirInServerSrcDir)
relPathFromAuthConfigToServerSrcDir :: Path Posix (Rel ()) (Dir C.ServerSrcDir)
relPathFromAuthConfigToServerSrcDir = [reldirP|../../../../|]
depsRequiredByPassport :: AppSpec -> [App.Dependency.Dependency]
depsRequiredByPassport spec =

View File

@ -33,17 +33,14 @@ import Wasp.AppSpec.Job (Job, JobExecutor (PgBoss, Simple), jobExecutors)
import qualified Wasp.AppSpec.Job as J
import Wasp.AppSpec.Util (isPgBossJobExecutorUsed)
import Wasp.Generator.Common (ServerRootDir, makeJsonWithEntityData)
import Wasp.Generator.ExternalCodeGenerator.Common (GeneratedExternalCodeDir)
import Wasp.Generator.FileDraft (FileDraft)
import Wasp.Generator.JsImport (getJsImportDetailsForExtFnImport)
import Wasp.Generator.Monad (Generator)
import Wasp.Generator.ServerGenerator.Common
( ServerSrcDir,
ServerTemplatesDir,
( ServerTemplatesDir,
srcDirInServerTemplatesDir,
)
import qualified Wasp.Generator.ServerGenerator.Common as C
import Wasp.Generator.ServerGenerator.ExternalCodeGenerator (extServerCodeDirInServerSrcDir)
import Wasp.Generator.ServerGenerator.JsImport (getJsImportStmtAndIdentifier)
import qualified Wasp.SemanticVersion as SV
genJobs :: AppSpec -> Generator [FileDraft]
@ -71,7 +68,7 @@ genJob (jobName, job) =
where
tmplFile = C.asTmplFile $ jobsDirInServerTemplatesDir SP.</> [relfile|_job.js|]
dstFile = jobsDirInServerRootDir SP.</> fromJust (parseRelFile $ jobName ++ ".js")
(jobPerformFnName, jobPerformFnImportStatement) = getJsImportDetailsForExtFnImport relPosixPathFromJobFileToExtSrcDir $ (J.fn . J.perform) job
(jobPerformFnImportStatement, jobPerformFnName) = getJsImportStmtAndIdentifier relPathFromJobsDirToServerSrcDir $ (J.fn . J.perform) job
maybeJobPerformOptions = J.performExecutorOptionsJson job
jobScheduleTmplData s =
object
@ -81,6 +78,9 @@ genJob (jobName, job) =
]
maybeJobSchedule = jobScheduleTmplData <$> J.schedule job
relPathFromJobsDirToServerSrcDir :: Path Posix (Rel ()) (Dir C.ServerSrcDir)
relPathFromJobsDirToServerSrcDir = [reldirP|../|]
-- Creates a file that is imported on the server to ensure all job JS modules are loaded
-- even if they are not referenced by user code. This ensures schedules are started, etc.
genAllJobImports :: AppSpec -> FileDraft
@ -101,9 +101,6 @@ genAllJobImports spec =
[ "name" .= jobName
]
relPosixPathFromJobFileToExtSrcDir :: Path Posix (Rel ServerSrcDir) (Dir GeneratedExternalCodeDir)
relPosixPathFromJobFileToExtSrcDir = [reldirP|../|] SP.</> fromJust (SP.relDirToPosix extServerCodeDirInServerSrcDir)
genJobExecutors :: Generator [FileDraft]
genJobExecutors = return $ jobExecutorFds ++ jobExecutorHelperFds
where

View File

@ -0,0 +1,29 @@
module Wasp.Generator.ServerGenerator.JsImport where
import Data.Maybe (fromJust)
import qualified StrongPath as SP
import qualified Wasp.AppSpec.ExtImport as EI
import Wasp.Generator.JsImport (PathFromImportLocationToSrcDir)
import qualified Wasp.Generator.JsImport as GJI
import Wasp.Generator.ServerGenerator.Common (ServerSrcDir)
import Wasp.Generator.ServerGenerator.ExternalCodeGenerator (extServerCodeDirInServerSrcDir)
import Wasp.JsImport
( JsImport,
JsImportIdentifier,
JsImportStatement,
)
import qualified Wasp.JsImport as JI
getJsImportStmtAndIdentifier ::
PathFromImportLocationToSrcDir ServerSrcDir ->
EI.ExtImport ->
(JsImportStatement, JsImportIdentifier)
getJsImportStmtAndIdentifier pathFromImportLocationToExtCodeDir = JI.getJsImportStmtAndIdentifier . extImportToJsImport pathFromImportLocationToExtCodeDir
extImportToJsImport ::
PathFromImportLocationToSrcDir ServerSrcDir ->
EI.ExtImport ->
JsImport
extImportToJsImport = GJI.extImportToJsImport serverExtDir
where
serverExtDir = fromJust (SP.relDirToPosix extServerCodeDirInServerSrcDir)

View File

@ -12,7 +12,7 @@ import Data.Aeson (object, (.=))
import qualified Data.Aeson as Aeson
import Data.List (nub)
import Data.Maybe (fromJust, fromMaybe)
import StrongPath (Dir, Dir', File', Path, Path', Posix, Rel, relDirToPosix, reldir, reldirP, relfile, (</>))
import StrongPath (Dir, File', Path, Path', Posix, Rel, reldir, reldirP, relfile, (</>))
import qualified StrongPath as SP
import Wasp.AppSpec (AppSpec)
import qualified Wasp.AppSpec as AS
@ -22,12 +22,10 @@ import qualified Wasp.AppSpec.Operation as AS.Operation
import qualified Wasp.AppSpec.Query as AS.Query
import Wasp.AppSpec.Valid (isAuthEnabled)
import Wasp.Generator.Common (ServerRootDir, makeJsonWithEntityData)
import Wasp.Generator.ExternalCodeGenerator.Common (GeneratedExternalCodeDir)
import Wasp.Generator.FileDraft (FileDraft)
import Wasp.Generator.JsImport (getJsImportDetailsForExtFnImport)
import Wasp.Generator.Monad (Generator)
import qualified Wasp.Generator.ServerGenerator.Common as C
import Wasp.Generator.ServerGenerator.ExternalCodeGenerator (extServerCodeDirInServerSrcDir)
import Wasp.Generator.ServerGenerator.JsImport (getJsImportStmtAndIdentifier)
import Wasp.Util (toUpperFirst, (<++>))
genOperations :: AppSpec -> Generator [FileDraft]
@ -122,10 +120,6 @@ operationFileInSrcDir :: AS.Operation.Operation -> Path' (Rel C.ServerSrcDir) Fi
operationFileInSrcDir (AS.Operation.QueryOp name _) = queryFileInSrcDir name
operationFileInSrcDir (AS.Operation.ActionOp name _) = actionFileInSrcDir name
relPosixPathFromOperationFileToExtSrcDir :: Path Posix (Rel Dir') (Dir GeneratedExternalCodeDir)
relPosixPathFromOperationFileToExtSrcDir =
[reldirP|../|] </> fromJust (relDirToPosix extServerCodeDirInServerSrcDir)
operationTmplData :: AS.Operation.Operation -> Aeson.Value
operationTmplData operation =
object
@ -138,6 +132,7 @@ operationTmplData operation =
(AS.Operation.getEntities operation)
]
where
(importIdentifier, importStmt) =
getJsImportDetailsForExtFnImport relPosixPathFromOperationFileToExtSrcDir $
AS.Operation.getFn operation
(importStmt, importIdentifier) = getJsImportStmtAndIdentifier relPathFromOperationsDirToServerSrcDir (AS.Operation.getFn operation)
relPathFromOperationsDirToServerSrcDir :: Path Posix (Rel ()) (Dir C.ServerSrcDir)
relPathFromOperationsDirToServerSrcDir = [reldirP|../|]

View File

@ -24,6 +24,7 @@ import Wasp.Generator.FileDraft (FileDraft)
import Wasp.Generator.Monad (Generator, GeneratorError (GenericGeneratorError), logAndThrowGeneratorError)
import qualified Wasp.Generator.ServerGenerator.Common as C
import Wasp.Generator.ServerGenerator.OperationsG (operationFileInSrcDir)
import Wasp.JsImport (JsImportName (..), getJsImportStmtAndIdentifier, makeJsImport)
import qualified Wasp.Util as U
genOperationsRoutes :: AppSpec -> Generator [FileDraft]
@ -53,8 +54,8 @@ genOperationRoute spec operation tmplFile = return $ C.mkTmplFdWithDstAndData tm
baseTmplData =
object
[ "operationImportPath" .= (operationImportPath :: FilePath),
"operationName" .= (AS.Operation.getName operation :: String)
[ "operationName" .= (operationImportIdentifier :: String),
"operationImportStmt" .= (operationImportStmt :: String)
]
tmplData = case AS.App.auth (snd $ getApp spec) of
@ -65,11 +66,19 @@ genOperationRoute spec operation tmplFile = return $ C.mkTmplFdWithDstAndData tm
(Aeson.toJSON (U.toLowerFirst $ AS.refName $ AS.Auth.userEntity auth))
baseTmplData
pathToOperationFile =
relPosixPathFromOperationsRoutesDirToSrcDir
</> fromJust (SP.relFileToPosix $ operationFileInSrcDir operation)
operationImportPath =
C.toESModulesImportPath $
SP.fromRelFileP $
relPosixPathFromOperationsRoutesDirToSrcDir
</> fromJust (SP.relFileToPosix $ operationFileInSrcDir operation)
fromJust $
SP.parseRelFileP $
C.toESModulesImportPath $
SP.fromRelFileP pathToOperationFile
operationName = AS.Operation.getName operation
(operationImportStmt, operationImportIdentifier) = getJsImportStmtAndIdentifier $ makeJsImport operationImportPath (JsImportModule operationName)
data OperationsRoutesDir
@ -103,14 +112,11 @@ genOperationsRouter spec
]
makeOperationRoute operation =
let operationName = AS.Operation.getName operation
importPath = fromJust $ SP.relFileToPosix $ SP.castRel $ operationRouteFileInOperationsRoutesDir operation
(importStmt, importIdentifier) = getJsImportStmtAndIdentifier $ makeJsImport importPath (JsImportModule operationName)
in object
[ "importIdentifier" .= operationName,
"importPath"
.= ( "./"
++ SP.fromRelFileP
( fromJust $ SP.relFileToPosix $ operationRouteFileInOperationsRoutesDir operation
)
),
[ "importIdentifier" .= importIdentifier,
"importStatement" .= importStmt,
"routePath" .= ("/" ++ operationRouteInOperationsRouter operation),
"isUsingAuth" .= isAuthEnabledForOperation operation
]

View File

@ -8,7 +8,7 @@ where
import Data.Aeson (object, (.=))
import Data.List (intercalate)
import Data.Maybe (fromJust, fromMaybe, isJust)
import Data.Maybe (fromMaybe, isJust)
import StrongPath
( Dir,
File',
@ -16,8 +16,8 @@ import StrongPath
Path',
Posix,
Rel,
relDirToPosix,
reldir,
reldirP,
relfile,
(</>),
)
@ -37,19 +37,17 @@ import Wasp.Generator.Common
)
import qualified Wasp.Generator.ConfigFile as G.CF
import Wasp.Generator.ExternalCodeGenerator (genExternalCodeDir)
import Wasp.Generator.ExternalCodeGenerator.Common (GeneratedExternalCodeDir)
import Wasp.Generator.FileDraft
import Wasp.Generator.JsImport (getJsImportDetailsForExtFnImport)
import Wasp.Generator.Monad (Generator)
import qualified Wasp.Generator.NpmDependencies as N
import Wasp.Generator.WebAppGenerator.AuthG (genAuth)
import qualified Wasp.Generator.WebAppGenerator.Common as C
import Wasp.Generator.WebAppGenerator.ExternalAuthG (ExternalAuthInfo (..), gitHubAuthInfo, googleAuthInfo)
import Wasp.Generator.WebAppGenerator.ExternalCodeGenerator
( extClientCodeDirInWebAppSrcDir,
extClientCodeGeneratorStrategy,
( extClientCodeGeneratorStrategy,
extSharedCodeGeneratorStrategy,
)
import Wasp.Generator.WebAppGenerator.JsImport (getJsImportStmtAndIdentifier)
import Wasp.Generator.WebAppGenerator.OperationsGenerator (genOperations)
import Wasp.Generator.WebAppGenerator.RouterGenerator (genRouter)
import Wasp.Util ((<++>))
@ -257,9 +255,9 @@ genIndexJs spec =
)
where
maybeSetupJsFunction = AS.App.Client.setupFn =<< AS.App.client (snd $ getApp spec)
maybeSetupJsFnImportDetails = getJsImportDetailsForExtFnImport extClientCodeDirInWebAppSrcDirP <$> maybeSetupJsFunction
(maybeSetupJsFnImportIdentifier, maybeSetupJsFnImportStmt) =
maybeSetupJsFnImportDetails = getJsImportStmtAndIdentifier relPathToWebAppSrcDir <$> maybeSetupJsFunction
(maybeSetupJsFnImportStmt, maybeSetupJsFnImportIdentifier) =
(fst <$> maybeSetupJsFnImportDetails, snd <$> maybeSetupJsFnImportDetails)
extClientCodeDirInWebAppSrcDirP :: Path Posix (Rel C.WebAppSrcDir) (Dir GeneratedExternalCodeDir)
extClientCodeDirInWebAppSrcDirP = fromJust $ relDirToPosix extClientCodeDirInWebAppSrcDir
relPathToWebAppSrcDir :: Path Posix (Rel ()) (Dir C.WebAppSrcDir)
relPathToWebAppSrcDir = [reldirP|./|]

View File

@ -23,7 +23,7 @@ import qualified Data.Aeson as Aeson
import StrongPath (Dir, File', Path', Rel, reldir, relfile, (</>))
import qualified StrongPath as SP
import Wasp.Common (WaspProjectDir)
import Wasp.Generator.Common (ProjectRootDir, WebAppRootDir)
import Wasp.Generator.Common (GeneratedSrcDir, ProjectRootDir, WebAppRootDir)
import Wasp.Generator.FileDraft (FileDraft, createTemplateFileDraft)
import Wasp.Generator.Templates (TemplatesDir)
@ -33,6 +33,8 @@ data WebAppTemplatesDir
data WebAppTemplatesSrcDir
instance GeneratedSrcDir WebAppSrcDir
asTmplFile :: Path' (Rel d) File' -> Path' (Rel WebAppTemplatesDir) File'
asTmplFile = SP.castRel

View File

@ -0,0 +1,29 @@
module Wasp.Generator.WebAppGenerator.JsImport where
import Data.Maybe (fromJust)
import qualified StrongPath as SP
import qualified Wasp.AppSpec.ExtImport as EI
import Wasp.Generator.JsImport (PathFromImportLocationToSrcDir)
import qualified Wasp.Generator.JsImport as GJI
import Wasp.Generator.WebAppGenerator.Common (WebAppSrcDir)
import Wasp.Generator.WebAppGenerator.ExternalCodeGenerator (extClientCodeDirInWebAppSrcDir)
import Wasp.JsImport
( JsImport,
JsImportIdentifier,
JsImportStatement,
)
import qualified Wasp.JsImport as JI
getJsImportStmtAndIdentifier ::
PathFromImportLocationToSrcDir WebAppSrcDir ->
EI.ExtImport ->
(JsImportStatement, JsImportIdentifier)
getJsImportStmtAndIdentifier pathFromImportLocationToSrcDir = JI.getJsImportStmtAndIdentifier . extImportToJsImport pathFromImportLocationToSrcDir
extImportToJsImport ::
PathFromImportLocationToSrcDir WebAppSrcDir ->
EI.ExtImport ->
JsImport
extImportToJsImport = GJI.extImportToJsImport webAppExtDir
where
webAppExtDir = fromJust (SP.relDirToPosix extClientCodeDirInWebAppSrcDir)

View File

@ -8,9 +8,8 @@ where
import Data.Aeson (ToJSON (..), object, (.=))
import Data.List (find)
import Data.Maybe (fromMaybe)
import StrongPath (reldir, relfile, (</>))
import qualified StrongPath as SP
import qualified System.FilePath as FP
import StrongPath (Dir, Path, Rel, reldir, reldirP, relfile, (</>))
import StrongPath.Types (Posix)
import Wasp.AppSpec (AppSpec)
import qualified Wasp.AppSpec as AS
import qualified Wasp.AppSpec.App as AS.App
@ -24,7 +23,8 @@ import Wasp.Generator.Monad (Generator)
import Wasp.Generator.WebAppGenerator.Common (asTmplFile, asWebAppSrcFile)
import qualified Wasp.Generator.WebAppGenerator.Common as C
import Wasp.Generator.WebAppGenerator.ExternalAuthG (ExternalAuthInfo (..), frontendLoginUrl, gitHubAuthInfo, googleAuthInfo, serverOauthRedirectHandlerUrl)
import Wasp.Generator.WebAppGenerator.ExternalCodeGenerator (extClientCodeDirInWebAppSrcDir)
import Wasp.Generator.WebAppGenerator.JsImport (extImportToJsImport)
import Wasp.JsImport (applyJsImportAlias, getJsImportStmtAndIdentifier)
data RouterTemplateData = RouterTemplateData
{ _routes :: ![RouteTemplateData],
@ -57,16 +57,14 @@ instance ToJSON RouteTemplateData where
]
data PageTemplateData = PageTemplateData
{ _importWhat :: !String,
_importFrom :: !String
{ _importStmt :: !String
}
deriving (Show, Eq)
instance ToJSON PageTemplateData where
toJSON pageTD =
object
[ "importWhat" .= _importWhat pageTD,
"importFrom" .= _importFrom pageTD
[ "importStatement" .= _importStmt pageTD
]
data ExternalAuthProviderTemplateData = ExternalAuthProviderTemplateData
@ -163,21 +161,17 @@ determineRouteTargetComponent spec (_, route) =
createPageTemplateData :: (String, AS.Page.Page) -> PageTemplateData
createPageTemplateData page =
PageTemplateData
{ _importFrom = relPathToExtSrcDir FP.</> SP.fromRelFileP (AS.ExtImport.path pageComponent),
_importWhat = case AS.ExtImport.name pageComponent of
AS.ExtImport.ExtImportModule _ -> pageName
AS.ExtImport.ExtImportField identifier -> "{ " ++ mkNamedImportExpr identifier pageName ++ " }"
{ _importStmt = importStmt
}
where
relPathToExtSrcDir = "./" FP.</> SP.toFilePath extClientCodeDirInWebAppSrcDir
importStmt :: String
(importStmt, _) = getJsImportStmtAndIdentifier $ applyJsImportAlias (Just importAlias) $ extImportToJsImport relPathToWebAppSrcDir pageComponent
pageName :: String
pageName = fst page
relPathToWebAppSrcDir :: Path Posix (Rel ()) (Dir C.WebAppSrcDir)
relPathToWebAppSrcDir = [reldirP|./|]
pageComponent :: AS.ExtImport.ExtImport
pageComponent = AS.Page.component $ snd page
mkNamedImportExpr :: String -> String -> String
mkNamedImportExpr identifier alias
| identifier == alias = identifier
| otherwise = identifier ++ " as " ++ alias
importAlias :: String
importAlias = fst page

View File

@ -0,0 +1,90 @@
{-# LANGUAGE DeriveDataTypeable #-}
module Wasp.JsImport
( JsImport (..),
JsImportName (..),
JsImportAlias,
JsImportPath,
JsImportIdentifier,
JsImportStatement,
makeJsImport,
applyJsImportAlias,
getJsImportStmtAndIdentifier,
)
where
import Data.Data (Data)
import Data.List (isPrefixOf)
import StrongPath (Dir', File', Path, Posix, Rel)
import qualified StrongPath as SP
-- | Represents a JS import data type that can be used to generate import statements
-- in generated code. It doesn't fully support all types of JS imports (multiple imports)
-- but this is enough for our current use case.
data JsImport = JsImport
{ -- | Path from which we are importing.
_path :: JsImportPath,
-- | What is being imported. NOTE: We don't currenly support multiple names in one statement,
-- that's why it's "name" and not "names".
_name :: JsImportName,
-- | Alias for the imported name.
_importAlias :: Maybe JsImportAlias
}
deriving (Show, Eq, Data)
type JsImportPath = Path Posix (Rel Dir') File'
type JsImportAlias = String
data JsImportName
= -- | Represents external imports like @import Identifier from "file.js"@
JsImportModule JsImportIdentifier
| -- | Represents external imports like @import { Identifier } from "file.js"@
JsImportField JsImportIdentifier
deriving (Show, Eq, Data)
type JsImportIdentifier = String
-- | Represents the left side of the import statement, between @import@ and @from@,
-- e.g. @{ Name }@ or @{ Name as Alias }@ or @NameForDefault@ .
type JsImportClause = String
-- | Represents the full import statement e.g. @import { Name } from "file.js"@
type JsImportStatement = String
makeJsImport :: JsImportPath -> JsImportName -> JsImport
makeJsImport importPath importName = JsImport importPath importName Nothing
applyJsImportAlias :: Maybe JsImportAlias -> JsImport -> JsImport
applyJsImportAlias importAlias jsImport = jsImport {_importAlias = importAlias}
getJsImportStmtAndIdentifier :: JsImport -> (JsImportStatement, JsImportIdentifier)
getJsImportStmtAndIdentifier (JsImport importPath importName maybeImportAlias) =
(importStatement, importIdentifier)
where
(importIdentifier, importClause) = jsImportIdentifierAndClause
importStatement :: JsImportStatement
importStatement = "import " ++ importClause ++ " from '" ++ normalizedPath ++ "'"
where
filePath = SP.fromRelFileP importPath
normalizedPath = if ".." `isPrefixOf` filePath then filePath else "./" ++ filePath
-- First part of import statement based on type of import and alias
-- e.g. for import { Name as Alias } from "file.js" it returns ("Alias", "{ Name as Alias }")
-- e.g. for import Name from "file.js" it returns ("Name", "Name")
jsImportIdentifierAndClause :: (JsImportIdentifier, JsImportClause)
jsImportIdentifierAndClause = case importName of
JsImportModule defaultImport -> getForDefault defaultImport maybeImportAlias
JsImportField namedImport -> getForNamed namedImport maybeImportAlias
where
getForDefault :: JsImportIdentifier -> Maybe JsImportAlias -> (JsImportIdentifier, JsImportClause)
getForDefault identifier Nothing = (identifier, identifier)
getForDefault _ (Just importAlias) = (importAlias, importAlias)
getForNamed :: JsImportIdentifier -> Maybe JsImportAlias -> (JsImportIdentifier, JsImportClause)
getForNamed identifier Nothing = (identifier, "{ " ++ identifier ++ " }")
getForNamed identifier (Just importAlias) = (importAlias, "{ " ++ resolvedIdentifier ++ " }")
where
resolvedIdentifier =
if identifier == importAlias then identifier else identifier ++ " as " ++ importAlias

View File

@ -0,0 +1,28 @@
module Generator.JsImportTest where
import StrongPath (Dir, Path, Posix, Rel)
import qualified StrongPath as SP
import Test.Tasty.Hspec
import Wasp.AppSpec.ExtImport
import Wasp.Generator.ExternalCodeGenerator.Common (GeneratedExternalCodeDir)
import Wasp.Generator.JsImport
import Wasp.Generator.ServerGenerator.Common (ServerSrcDir)
import Wasp.JsImport as JI
spec_GeneratorJsImportTest :: Spec
spec_GeneratorJsImportTest = do
describe "extImportToJsImport" $ do
let pathToExtCodeDir = [SP.reldirP|ext-src|] :: (Path Posix (Rel ServerSrcDir) (Dir GeneratedExternalCodeDir))
pathFromImportLocationToExtCodeDir = [SP.reldirP|../|]
extImport =
ExtImport
{ name = ExtImportModule "test",
path = [SP.relfileP|folder/test.js|]
}
it "makes a JsImport from ExtImport" $ do
extImportToJsImport pathToExtCodeDir pathFromImportLocationToExtCodeDir extImport
`shouldBe` JI.JsImport
{ JI._path = [SP.relfileP|../ext-src/folder/test.js|],
JI._name = JsImportModule "test",
JI._importAlias = Nothing
}

View File

@ -0,0 +1,51 @@
module JsImportTest where
import StrongPath (Dir', File', Path, Posix, Rel, (</>))
import qualified StrongPath as SP
import Test.Tasty.Hspec (Spec, describe, it, shouldBe)
import Wasp.JsImport
spec_JsImportTest :: Spec
spec_JsImportTest = do
describe "makeJsImport" $ do
it "makes JsImport with default import from a path" $ do
makeJsImport testJsFileImportPath (JsImportModule "test")
`shouldBe` JsImport
{ _path = testJsFileImportPath,
_name = JsImportModule "test",
_importAlias = Nothing
}
describe "applyJsImportAlias" $ do
it "applies alias to JsImport" $ do
let jsImport = makeJsImport testJsFileImportPath (JsImportModule "test")
applyJsImportAlias (Just "alias") jsImport
`shouldBe` jsImport {_importAlias = Just "alias"}
describe "getJsImportStmtAndIdentifier" $ do
describe "generates import statement and identifier from" $ do
it "default import" $ do
getJsImportStmtAndIdentifier
(makeJsImport testJsFileImportPath (JsImportModule "test"))
`shouldBe` ("import test from '" ++ generatedImportPathForTestJsFile ++ "'", "test")
it "default import with alias" $ do
getJsImportStmtAndIdentifier
( applyJsImportAlias
(Just "alias")
(makeJsImport testJsFileImportPath (JsImportModule "test"))
)
`shouldBe` ("import alias from '" ++ generatedImportPathForTestJsFile ++ "'", "alias")
it "named import" $ do
getJsImportStmtAndIdentifier
(makeJsImport testJsFileImportPath (JsImportField "test"))
`shouldBe` ("import { test } from '" ++ generatedImportPathForTestJsFile ++ "'", "test")
it "named import with alias" $ do
getJsImportStmtAndIdentifier
( applyJsImportAlias
(Just "alias")
(makeJsImport testJsFileImportPath (JsImportField "test"))
)
`shouldBe` ("import { test as alias } from '" ++ generatedImportPathForTestJsFile ++ "'", "alias")
where
testJsFileImportPath :: Path Posix (Rel Dir') File'
testJsFileImportPath = [SP.reldirP|ext-src|] </> [SP.relfileP|folder/test.js|]
generatedImportPathForTestJsFile = "./ext-src/folder/test.js"

View File

@ -207,6 +207,7 @@ library
Wasp.Data
Wasp.Error
Wasp.ExternalCode
Wasp.JsImport
Wasp.Generator
Wasp.Generator.Common
Wasp.Generator.ConfigFile
@ -234,6 +235,7 @@ library
Wasp.Generator.JsImport
Wasp.Generator.Monad
Wasp.Generator.ServerGenerator
Wasp.Generator.ServerGenerator.JsImport
Wasp.Generator.ServerGenerator.AuthG
Wasp.Generator.ServerGenerator.Common
Wasp.Generator.ServerGenerator.ConfigG
@ -248,6 +250,7 @@ library
Wasp.Generator.Start
Wasp.Generator.Templates
Wasp.Generator.WebAppGenerator
Wasp.Generator.WebAppGenerator.JsImport
Wasp.Generator.WebAppGenerator.AuthG
Wasp.Generator.WebAppGenerator.Common
Wasp.Generator.WebAppGenerator.ExternalAuthG
@ -424,6 +427,7 @@ test-suite waspc-test
Generator.MockWriteableMonad
Generator.WebAppGeneratorTest
Generator.WriteFileDraftsTest
Generator.JsImportTest
Psl.Common.ModelTest
Psl.Generator.ModelTest
Psl.Parser.ModelTest
@ -436,6 +440,7 @@ test-suite waspc-test
WaspignoreFileTest
Paths_waspc
Generator.NpmDependenciesTest
JsImportTest
test-suite cli-test
import: common-all, common-exe