11/**
22 * Create a blank ColdBox app from one of our app skeletons or a skeleton using a valid Endpoint ID which can come from .
3- * ForgeBox , HTTP/S, git, github, etc.
3+ * FORGEBOX , HTTP/S, git, github, etc.
44 * By default it will create the application in your current directory.
55 * .
66 * {code:bash}
77 * coldbox create app myApp
88 * {code}
99 * .
10- * Here are the basic skeletons that are available for you that come from ForgeBox
11- * - BoxLang
12- * - Default (default )
13- * - Elixir
14- * - Modern
15- * - rest
16- * - rest-hmvc
17- * - SuperSimple
18- * - Vite
10+ * Here are the basic skeletons that are available for you that come from FORGEBOX
11+ *
12+ * - BoxLang (Default )
13+ * - Modern (CFML + BoxLang Default)
14+ * - flat (CFML + BoxLang Flat)
15+ * - rest (CFML + BoxLang RESTful API)
16+ * - rest-hmvc (HMVC + REST)
17+ * - supersimple (bare bones)
18+ * - vite (flat + vite)
1919 * .
2020 * {code:bash}
21- * coldbox create app skeleton=rest
21+ * coldbox create app skeleton=modern
2222 * {code}
2323 * .
2424 * The skeleton parameter can also be any valid FORGEBOX Endpoint ID, which includes a Git repo or HTTP URL pointing to a package.
2525 * .
2626 * {code:bash}
2727 * coldbox create app skeleton=http://site.com/myCustomAppTemplate.zip
28- * coldbox create app skeleton=coldbox-templates/modern
28+ * coldbox create app skeleton=coldbox-templates/rest
2929 * {code}
3030 *
3131 **/
@@ -40,22 +40,24 @@ component extends="coldbox-cli.models.BaseCommand" {
4040 function init (){
4141 // Map these shortcut names to the actual ForgeBox slugs
4242 variables .templateMap = {
43- " Default" : " cbtemplate-advanced-script" ,
44- " BoxLang" : " cbtemplate-boxlang" ,
45- " Elixir" : " cbtemplate-elixir" ,
43+ " flat" : " cbtemplate-flat" ,
44+ " boxlang" : " cbtemplate-boxlang" ,
4645 " modern" : " cbtemplate-modern" ,
4746 " rest" : " cbtemplate-rest" ,
4847 " rest-hmvc" : " cbtemplate-rest-hmvc" ,
49- " Vite " : " cbtemplate-vite" ,
50- " SuperSimple " : " cbtemplate-supersimple"
48+ " vite " : " cbtemplate-vite" ,
49+ " supersimple " : " cbtemplate-supersimple"
5150 };
5251
5352 variables .defaultAppName = " My ColdBox App" ;
53+ variables .defaultSkeleton = " boxlang" ;
5454
5555 return this ;
5656 }
5757
5858 /**
59+ * Create a new ColdBox application
60+ *
5961 * @name The name of the app you want to create
6062 * @skeleton The name of the app skeleton to generate (or an endpoint ID like a forgebox slug)
6163 * @skeleton.optionsUDF skeletonComplete
@@ -66,41 +68,45 @@ component extends="coldbox-cli.models.BaseCommand" {
6668 * @verbose Verbose output
6769 * @migrations Run migration init after creation
6870 * @boxlang Set the language to BoxLang
71+ * @docker Include Docker files and setup Docker configuration
72+ * @vite Setup Vite for frontend asset building (For modern/boxlang apps only)
73+ * @rest Is this a REST API project? (For modern/boxlang apps only)
6974 **/
7075 function run (
7176 name = defaultAppName ,
72- skeleton = " default " ,
77+ skeleton = variables . defaultSkeleton ,
7378 directory = getCWD (),
7479 boolean init = true ,
7580 boolean wizard = false ,
7681 boolean initWizard = false ,
7782 boolean verbose = false ,
7883 boolean migrations = false ,
79- boolean boxlang = isBoxLangProject ( getCWD () )
84+ boolean boxlang = isBoxLangProject ( getCWD () ),
85+ boolean docker = true ,
86+ boolean vite = false ,
87+ boolean rest = false
8088 ){
8189 // Check for wizard argument
8290 if ( arguments .wizard ) {
8391 command ( " coldbox create app-wizard" ).params ( verbose = arguments .verbose ).run ();
8492 return ;
8593 }
8694
87- job .start ( " Creating App [#arguments .name #]" );
88-
95+ job .start ( " 🧑🍳 Creating & Prepping Your App [#arguments .name #]" );
8996 if ( arguments .verbose ) {
9097 job .setDumpLog ( arguments .verbose );
9198 }
9299
93100 // This will make the directory canonical and absolute
94101 arguments .directory = resolvePath ( arguments .directory );
95-
96102 // Validate directory, if it doesn't exist, create it.
97103 if ( ! directoryExists ( arguments .directory ) ) {
98104 directoryCreate ( arguments .directory );
99105 }
100106
101107 // If the skeleton = default and this is a boxlang project, then switch the skeleton to BoxLang
102108 if ( arguments .skeleton == " default" && arguments .boxlang ) {
103- arguments .skeleton = " BoxLang " ;
109+ arguments .skeleton = variables . defaultSkeleton ;
104110 }
105111
106112 // If the skeleton is one of our "shortcut" names
@@ -109,7 +115,7 @@ component extends="coldbox-cli.models.BaseCommand" {
109115 arguments .skeleton = variables .templateMap [ arguments .skeleton ];
110116 }
111117
112- // Install the skeleton
118+ // Install the skeleton from ForgeBox or other endpoint
113119 packageService .installPackage (
114120 ID : arguments .skeleton ,
115121 directory : arguments .directory ,
@@ -119,8 +125,6 @@ component extends="coldbox-cli.models.BaseCommand" {
119125 currentWorkingDirectory : arguments .directory
120126 );
121127
122- job .start ( " Preparing box.json" );
123-
124128 // Init, if not a package as a Box Package
125129 if ( arguments .init && ! packageService .isPackage ( arguments .directory ) ) {
126130 var originalPath = getCWD ();
@@ -138,7 +142,11 @@ component extends="coldbox-cli.models.BaseCommand" {
138142
139143 // Prepare language
140144 if ( arguments .boxlang ) {
145+ printInfo ( " Setting language to BoxLang" );
141146 command ( " package set" ).params ( language : " BoxLang" ).run ();
147+ } else {
148+ printInfo ( " Setting language to CFML" );
149+ command ( " package set" ).params ( language : " CFML" ).run ();
142150 }
143151
144152 // Prepare defaults on box.json so we remove template based ones
@@ -147,27 +155,198 @@ component extends="coldbox-cli.models.BaseCommand" {
147155 name : arguments .name ,
148156 slug : variables .formatterUtil .slugify ( arguments .name ),
149157 version : " 1.0.0" ,
150- location : " forgeboxStorage"
158+ location : " forgeboxStorage" ,
159+ ignore : []
151160 )
152161 .run ();
153162
154- job .complete ();
155-
156163 // set the server name if the user provided one
164+ printInfo ( " 🤖 Preparing server" );
157165 if ( arguments .name ! = defaultAppName ) {
158- job .start ( " Preparing server.json" );
159166 command ( " server set" ).params ( name = arguments .name ).run ();
160- job .complete ();
161167 }
162168
163- // Finalize Create app Job
164- job .complete ();
169+ // ENV File
170+ var envFile = arguments .directory & " .env" ;
171+ if ( ! fileExists ( envFile ) ) {
172+ printInfo ( " 🌿 Creating .env file" );
173+ if ( fileExists ( arguments .directory & " .env.example" ) ){
174+ fileCopy ( arguments .directory & " .env.example" , envFile );
175+ } else {
176+ fileCopy ( variables .settings .templatesPath & " .env.example" , envFile );
177+ }
178+ } else {
179+ printInfo ( " ⏭️ .env file already exists, skipping creation." )
180+ }
181+
182+ // Copilot instructions
183+ printInfo ( " 🤖 Preparing GitHub Copilot configuration" );
184+ var githubDir = arguments .directory & " .github" ;
185+ var copilotFile = githubDir & " /copilot-instructions.md" ;
186+ if ( ! directoryExists ( githubDir ) ){
187+ directoryCreate ( githubDir , true )
188+ }
189+ if ( ! fileExists ( copilotFile ) ){
190+ printInfo ( " 🥊 Creating copilot file" )
191+ // If the template has a copilot-instructions.md, use it, otherwise use the default one
192+ if ( fileExists ( arguments .directory & " resources/copilot-instructions.md" ) ){
193+ fileCopy ( arguments .directory & " resources/copilot-instructions.md" , copilotFile );
194+ } else {
195+ if ( arguments .skeleton == " modern" ){
196+ fileCopy ( variables .settings .templatesPath & " modern-copilot-instructions.md" , copilotFile );
197+ }
198+ else {
199+ fileCopy ( variables .settings .templatesPath & " flat-copilot-instructions.md" , copilotFile );
200+ }
201+ }
202+ } else {
203+ printInfo ( " ⏭️ copilot-instructions.md file already exists, skipping creation." )
204+ }
165205
166206 // Run migrations init
167207 if ( arguments .migrations ) {
208+ printInfo ( " 🚀 Initializing Migrations" );
168209 variables .utility .ensureMigrationsModule ();
169210 command ( " migrate init" ).run ();
211+ variables .print
212+ .line ( " 👉 You can run `migrate help` to see all available migration commands." )
213+ .toConsole ();
214+ }
215+
216+ if ( arguments .docker ){
217+ printInfo ( " 🥊 Setting up Docker for containerization" )
218+ if ( directoryExists ( arguments .directory & " docker" ) ){
219+ printInfo ( " ⏭️ Docker directory already exists, skipping creation." )
220+ } else {
221+ directoryCreate ( arguments .directory & " docker" , true )
222+ fileCopy (
223+ " #variables .settings .templatesPath #/docker/Dockerfile" ,
224+ arguments .directory & " docker/Dockerfile"
225+ )
226+ fileCopy (
227+ " #variables .settings .templatesPath #/docker/docker-compose.yml" ,
228+ arguments .directory & " docker/docker-compose.yml"
229+ )
230+ fileCopy (
231+ " #variables .settings .templatesPath #/docker/.dockerignore" ,
232+ arguments .directory & " docker/.dockerignore"
233+ )
234+ variables .print
235+ .line ( " ✅ Docker setup complete!" )
236+ .line ( " 👉 You can run 'box run-script docker:build' to build your Docker image." )
237+ .line ( " 👉 You can run 'box run-script docker:run' to run your Docker container." )
238+ .line ( " 👉 You can run 'box run-script docker:bash' to go into the container shell." )
239+ .line ( " 👉 You can run 'box run-script docker:stack' to startup the Docker Compose Stack" )
240+ .toConsole ();
241+ }
242+ }
243+
244+ // VITE Setup
245+ if ( arguments .vite ){
246+ if ( arguments .skeleton ! = " modern" && arguments .skeleton ! = " boxlang" ){
247+ printWarn ( " ⚠️ Vite setup is only supported for 'modern' or 'boxlang' skeletons. Skipping Vite setup." )
248+ } else {
249+ printInfo ( " 🥊 Setting up Vite for your frontend build system" )
250+ fileCopy ( " #variables .settings .templatesPath #/vite/.babelrc" , arguments .directory & " .babelrc" )
251+ fileCopy ( " #variables .settings .templatesPath #/vite/package.json" , arguments .directory & " package.json" )
252+ fileCopy ( " #variables .settings .templatesPath #/vite/vite.config.mjs" , arguments .directory & " vite.config.mjs" )
253+ fileDelete ( arguments .directory & " app/layouts/Main.bxm" )
254+ fileCopy ( " #variables .settings .templatesPath #/vite/layouts/Main.bxm" , arguments .directory & " app/layouts/Main.bxm" )
255+ fileCopy ( " #variables .settings .templatesPath #/vite/assets" , arguments .directory & " resources/assets" )
256+
257+ printInfo ( " 🥊 Installing ColdBox Vite Helpers" )
258+ command ( " install" )
259+ .params ( " vite-helpers" )
260+ .run ();
261+
262+ variables .print
263+ .line ( " ✅ Vite setup complete!" )
264+ .line ( " 👉 You can run 'npm install' to install the dependencies" )
265+ .line ( " 👉 You can run 'npm run dev' to start the development server" )
266+ .line ( " 👉 You can run 'npm run build' to build the production assets" )
267+ .toConsole ();
268+ }
269+ }
270+
271+ // REST Setup
272+ if ( arguments .rest ){
273+ if ( arguments .skeleton ! = " modern" && arguments .skeleton ! = " boxlang" ){
274+ printWarn ( " ⚠️ REST setup is only supported for 'modern' or 'boxlang' skeletons. Skipping REST setup." )
275+ } else {
276+ printInfo ( " 🥊 Setting up a REST API only ColdBox application" )
277+ printInfo ( " 👉 You can always add views and layouts later if you change your mind" )
278+
279+ // Router
280+ fileDelete ( arguments .directory & " app/config/Router.bx" )
281+ fileCopy ( " #variables .settings .templatesPath #/rest/Router.bx" , arguments .directory & " app/config/Router.bx" )
282+ // Tests
283+ directoryDelete ( arguments .directory & " tests/specs" , true )
284+ directoryCopy (
285+ source : " #variables .settings .templatesPath #/rest/specs" ,
286+ destination : arguments .directory & " tests/specs" ,
287+ recurse : true ,
288+ createPath : true
289+ )
290+ // Configuration
291+ directoryCopy (
292+ source : " #variables .settings .templatesPath #/rest/config/modules" ,
293+ destination : arguments .directory & " app/config/modules" ,
294+ recurse : false ,
295+ createPath : true
296+ )
297+ // Models
298+ directoryDelete ( arguments .directory & " app/models" , true )
299+ directoryCopy (
300+ source : " #variables .settings .templatesPath #/rest/models" ,
301+ destination : arguments .directory & " app/models" ,
302+ recurse : false ,
303+ createPath : true
304+ )
305+ // Handlers
306+ directoryDelete ( arguments .directory & " app/handlers" , true )
307+ directoryCopy (
308+ source : " #variables .settings .templatesPath #/rest/handlers" ,
309+ destination : arguments .directory & " app/handlers" ,
310+ recurse : false ,
311+ createPath : true
312+ )
313+ // Api Docs
314+ directoryCopy (
315+ source : " #variables .settings .templatesPath #/rest/apidocs" ,
316+ destination : arguments .directory & " resources/apidocs" ,
317+ recurse : true ,
318+ createPath : true
319+ )
320+ var newConfig = fileRead ( arguments .directory & " app/config/Coldbox.bx" )
321+ .replace ( " Main.index" , " Echo.index" )
322+ .replace ( " Main.onException" , " Echo.onError" );
323+ fileWrite ( " app/config/Coldbox.bx" , newConfig );
324+
325+ // Install CommandBox Modules
326+ printInfo ( " 🥊 Installing ColdBox API Production Modules: Security, Mementifier, Validation" )
327+ command ( " install" )
328+ .params ( " cbsecurity,mementifier,cbvalidation" )
329+ .run ();
330+
331+ printInfo ( " 🥊 Installing ColdBox API Development Modules: route-visualizer,relax" )
332+ command ( " install" )
333+ .params ( " cbsecurity,mementifier,cbvalidation" , " --saveDev" )
334+ .run ();
335+
336+ printInfo ( " ✅ REST API only setup complete!" )
337+ }
170338 }
339+
340+ // Finalize Create app Job
341+ job .complete ();
342+
343+ variables .print
344+ .line ( " 🥊 Your ColdBox BoxLang application is ready to roll!" )
345+ .line ( " 👉 Run 'box server start' to launch the development server." )
346+ .line ( " 👉 Run 'box coldbox help' to see a list of available commands from the ColdBox CLI" )
347+ .line ( " ℹ️. You can remove the [Setup.bx] file from your project now or keep it for future reference." )
348+ .line ( " 🗳️ Happy coding!" )
349+ .toConsole ();
171350 }
172351
173352 /**
0 commit comments