-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
Copy pathStarterTemplates.hs
238 lines (209 loc) · 9.29 KB
/
StarterTemplates.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
{-# LANGUAGE TupleSections #-}
module Wasp.Cli.Command.CreateNewProject.StarterTemplates
( getStarterTemplates,
StarterTemplate (..),
DirBasedTemplateMetadata (..),
findTemplateByString,
defaultStarterTemplate,
readWaspProjectSkeletonFiles,
getTemplateStartingInstructions,
)
where
import Data.Foldable (find)
import Data.Text (Text)
import StrongPath (Dir', File', Path, Path', Rel, Rel', System, reldir, (</>))
import qualified System.FilePath as FP
import qualified Wasp.Cli.GithubRepo as GhRepo
import qualified Wasp.Cli.Interactive as Interactive
import qualified Wasp.Data as Data
import Wasp.Project.Common (WaspProjectDir)
import Wasp.Util.IO (listDirectoryDeep, readFileStrict)
import qualified Wasp.Util.Terminal as Term
data StarterTemplate
= -- | Template from a Github repo.
GhRepoStarterTemplate !GhRepo.GithubRepoRef !DirBasedTemplateMetadata
| -- | Template from a disk, that comes bundled with wasp CLI.
LocalStarterTemplate !DirBasedTemplateMetadata
| -- | Template that will be dynamically generated by Wasp AI based on user's input.
AiGeneratedStarterTemplate
data DirBasedTemplateMetadata = DirBasedTemplateMetadata
{ _name :: !String,
_path :: !(Path' Rel' Dir'), -- Path to a directory containing template files.
_description :: !String,
_buildStartingInstructions :: !StartingInstructionsBuilder
}
instance Show StarterTemplate where
show (GhRepoStarterTemplate _ metadata) = _name metadata
show (LocalStarterTemplate metadata) = _name metadata
show AiGeneratedStarterTemplate = "ai-generated"
instance Interactive.IsOption StarterTemplate where
showOption = show
showOptionDescription (GhRepoStarterTemplate _ metadata) = Just $ _description metadata
showOptionDescription (LocalStarterTemplate metadata) = Just $ _description metadata
showOptionDescription AiGeneratedStarterTemplate =
Just "🤖 Describe an app in a couple of sentences and have Wasp AI generate initial code for you. (experimental)"
type StartingInstructionsBuilder = String -> String
{- HLINT ignore getTemplateStartingInstructions "Redundant $" -}
-- | Returns instructions for running the newly created (from the template) Wasp project.
-- Instructions assume that user is positioned right next to the just created project directory,
-- whose name is provided via projectDirName.
getTemplateStartingInstructions :: String -> StarterTemplate -> String
getTemplateStartingInstructions projectDirName = \case
GhRepoStarterTemplate _ metadata -> _buildStartingInstructions metadata projectDirName
LocalStarterTemplate metadata -> _buildStartingInstructions metadata projectDirName
AiGeneratedStarterTemplate ->
unlines
[ styleText $ "To run your new app, do:",
styleCode $ " cd " <> projectDirName,
styleCode $ " wasp db migrate-dev",
styleCode $ " wasp start"
]
getStarterTemplates :: [StarterTemplate]
getStarterTemplates =
[ defaultStarterTemplate,
todoTsStarterTemplate,
openSaasStarterTemplate,
embeddingsStarterTemplate,
AiGeneratedStarterTemplate
]
defaultStarterTemplate :: StarterTemplate
defaultStarterTemplate = basicStarterTemplate
{- HLINT ignore basicStarterTemplate "Redundant $" -}
basicStarterTemplate :: StarterTemplate
basicStarterTemplate =
LocalStarterTemplate $
DirBasedTemplateMetadata
{ _path = [reldir|basic|],
_name = "basic",
_description = "Simple starter template with a single page.",
_buildStartingInstructions = \projectDirName ->
unlines
[ styleText $ "To run your new app, do:",
styleCode $ " cd " <> projectDirName,
styleCode $ " wasp start"
]
}
{- HLINT ignore openSaasStarterTemplate "Redundant $" -}
openSaasStarterTemplate :: StarterTemplate
openSaasStarterTemplate =
simpleGhRepoTemplate
("open-saas", [reldir|template|])
( "saas",
"Everything a SaaS needs! Comes with Auth, ChatGPT API, Tailwind, Stripe payments and more."
<> " Check out https://opensaas.sh/ for more details."
)
( \projectDirName ->
unlines
[ styleText $ "To run your new app, follow the instructions below:",
styleText $ "",
styleText $ " 1. Position into app's root directory:",
styleCode $ " cd " <> projectDirName FP.</> "app",
styleText $ "",
styleText $ " 2. Run the development database (and leave it running):",
styleCode $ " wasp db start",
styleText $ "",
styleText $ " 3. Open new terminal window (or tab) in that same dir and continue in it.",
styleText $ "",
styleText $ " 4. Apply initial database migrations:",
styleCode $ " wasp db migrate-dev",
styleText $ "",
styleText $ " 5. Create initial dot env file from the template:",
styleCode $ " cp .env.server.example .env.server",
styleText $ "",
styleText $ " 6. Last step: run the app!",
styleCode $ " wasp start",
styleText $ "",
styleText $ "Check the README for additional guidance and the link to docs!"
]
)
{- HLINT ignore todoTsStarterTemplate "Redundant $" -}
todoTsStarterTemplate :: StarterTemplate
todoTsStarterTemplate =
simpleGhRepoTemplate
("starters", [reldir|todo-ts|])
( "todo-ts",
"Simple but well-rounded Wasp app implemented with Typescript & full-stack type safety."
)
( \projectDirName ->
unlines
[ styleText $ "To run your new app, do:",
styleCode $ " cd " ++ projectDirName,
styleCode $ " wasp db migrate-dev",
styleCode $ " wasp start",
styleText $ "",
styleText $ "Check the README for additional guidance!"
]
)
{- Functions for styling instructions. Their names are on purpose of same length, for nicer code formatting. -}
styleCode :: String -> String
styleCode = Term.applyStyles [Term.Bold]
styleText :: String -> String
styleText = id
{- -}
{- HLINT ignore embeddingsStarterTemplate "Redundant $" -}
embeddingsStarterTemplate :: StarterTemplate
embeddingsStarterTemplate =
simpleGhRepoTemplate
("starters", [reldir|embeddings|])
( "embeddings",
"Comes with code for generating vector embeddings and performing vector similarity search."
)
( \projectDirName ->
unlines
[ styleText $ "To run your new app, follow the instructions below:",
styleText $ "",
styleText $ " 1. Position into app's root directory:",
styleCode $ " cd " <> projectDirName,
styleText $ "",
styleText $ " 2. Create initial dot env file from the template and fill in your API keys:",
styleCode $ " cp .env.server.example .env.server",
styleText $ " Fill in your API keys!",
styleText $ "",
styleText $ " 3. Run the development database (and leave it running):",
styleCode $ " wasp db start",
styleText $ "",
styleText $ " 4. Open new terminal window (or tab) in that same dir and continue in it.",
styleText $ "",
styleText $ " 5. Apply initial database migrations:",
styleCode $ " wasp db migrate-dev",
styleText $ "",
styleText $ " 6. Run wasp seed script that will generate embeddings from the text files in src/shared/docs:",
styleCode $ " wasp db seed",
styleText $ "",
styleText $ " 7. Last step: run the app!",
styleCode $ " wasp start",
styleText $ "",
styleText $ "Check the README for more detailed instructions and additional guidance!"
]
)
simpleGhRepoTemplate :: (String, Path' Rel' Dir') -> (String, String) -> StartingInstructionsBuilder -> StarterTemplate
simpleGhRepoTemplate (repoName, tmplPathInRepo) (tmplDisplayName, tmplDescription) buildStartingInstructions =
GhRepoStarterTemplate
( GhRepo.GithubRepoRef
{ GhRepo._repoOwner = waspGhOrgName,
GhRepo._repoName = repoName,
GhRepo._repoReferenceName = waspVersionTemplateGitTag
}
)
( DirBasedTemplateMetadata
{ _name = tmplDisplayName,
_description = tmplDescription,
_path = tmplPathInRepo,
_buildStartingInstructions = buildStartingInstructions
}
)
waspGhOrgName :: String
waspGhOrgName = "wasp-lang"
-- NOTE: As version of Wasp CLI changes, so we should update this tag name here,
-- and also create it on gh repos of templates.
-- By tagging templates for each version of Wasp CLI, we ensure that each release of
-- Wasp CLI uses correct version of templates, that work with it.
waspVersionTemplateGitTag :: String
waspVersionTemplateGitTag = "wasp-v0.15-template"
findTemplateByString :: [StarterTemplate] -> String -> Maybe StarterTemplate
findTemplateByString templates query = find ((== query) . show) templates
readWaspProjectSkeletonFiles :: IO [(Path System (Rel WaspProjectDir) File', Text)]
readWaspProjectSkeletonFiles = do
skeletonFilesDir <- (</> [reldir|Cli/templates/skeleton|]) <$> Data.getAbsDataDirPath
skeletonFilePaths <- listDirectoryDeep skeletonFilesDir
mapM (\path -> (path,) <$> readFileStrict (skeletonFilesDir </> path)) skeletonFilePaths