1- // @ts -check
21import fs from 'node:fs'
32import path from 'node:path'
43import { fileURLToPath } from 'node:url'
@@ -19,10 +18,27 @@ import {
1918
2019// Avoids autoconversion to number of the project name by defining that the args
2120// non associated with an option ( _ ) needs to be parsed as a string. See #4606
22- const argv = minimist ( process . argv . slice ( 2 ) , { string : [ '_' ] } )
21+ const argv = minimist < {
22+ t ?: string
23+ template ?: string
24+ } > ( process . argv . slice ( 2 ) , { string : [ '_' ] } )
2325const cwd = process . cwd ( )
2426
25- const FRAMEWORKS = [
27+ type ColorFunc = ( str : string | number ) => string
28+ type Framework = {
29+ name : string
30+ display : string
31+ color : ColorFunc
32+ variants : FrameworkVariant [ ]
33+ }
34+ type FrameworkVariant = {
35+ name : string
36+ display : string
37+ color : ColorFunc
38+ customCommand ?: string
39+ }
40+
41+ const FRAMEWORKS : Framework [ ] = [
2642 {
2743 name : 'vanilla' ,
2844 display : 'Vanilla' ,
@@ -149,25 +165,29 @@ const TEMPLATES = FRAMEWORKS.map(
149165 ( f ) => ( f . variants && f . variants . map ( ( v ) => v . name ) ) || [ f . name ]
150166) . reduce ( ( a , b ) => a . concat ( b ) , [ ] )
151167
152- const renameFiles = {
168+ const renameFiles : Record < string , string | undefined > = {
153169 _gitignore : '.gitignore'
154170}
155171
172+ const defaultTargetDir = 'vite-project'
173+
156174async function init ( ) {
157- let targetDir = formatTargetDir ( argv . _ [ 0 ] )
158- let template = argv . template || argv . t
175+ const argTargetDir = formatTargetDir ( argv . _ [ 0 ] )
176+ const argTemplate = argv . template || argv . t
159177
160- const defaultTargetDir = 'vite-project'
178+ let targetDir = argTargetDir || defaultTargetDir
161179 const getProjectName = ( ) =>
162180 targetDir === '.' ? path . basename ( path . resolve ( ) ) : targetDir
163181
164- let result = { }
182+ let result : prompts . Answers <
183+ 'projectName' | 'overwrite' | 'packageName' | 'framework' | 'variant'
184+ >
165185
166186 try {
167187 result = await prompts (
168188 [
169189 {
170- type : targetDir ? null : 'text' ,
190+ type : argTargetDir ? null : 'text' ,
171191 name : 'projectName' ,
172192 message : reset ( 'Project name:' ) ,
173193 initial : defaultTargetDir ,
@@ -186,7 +206,7 @@ async function init() {
186206 ` is not empty. Remove existing files and continue?`
187207 } ,
188208 {
189- type : ( _ , { overwrite } = { } ) => {
209+ type : ( _ , { overwrite } : { overwrite ?: boolean } ) => {
190210 if ( overwrite === false ) {
191211 throw new Error ( red ( '✖' ) + ' Operation cancelled' )
192212 }
@@ -203,12 +223,13 @@ async function init() {
203223 isValidPackageName ( dir ) || 'Invalid package.json name'
204224 } ,
205225 {
206- type : template && TEMPLATES . includes ( template ) ? null : 'select' ,
226+ type :
227+ argTemplate && TEMPLATES . includes ( argTemplate ) ? null : 'select' ,
207228 name : 'framework' ,
208229 message :
209- typeof template === 'string' && ! TEMPLATES . includes ( template )
230+ typeof argTemplate === 'string' && ! TEMPLATES . includes ( argTemplate )
210231 ? reset (
211- `"${ template } " isn't a valid template. Please choose from below: `
232+ `"${ argTemplate } " isn't a valid template. Please choose from below: `
212233 )
213234 : reset ( 'Select a framework:' ) ,
214235 initial : 0 ,
@@ -221,12 +242,11 @@ async function init() {
221242 } )
222243 } ,
223244 {
224- type : ( framework ) =>
245+ type : ( framework : Framework ) =>
225246 framework && framework . variants ? 'select' : null ,
226247 name : 'variant' ,
227248 message : reset ( 'Select a variant:' ) ,
228- // @ts -ignore
229- choices : ( framework ) =>
249+ choices : ( framework : Framework ) =>
230250 framework . variants . map ( ( variant ) => {
231251 const variantColor = variant . color
232252 return {
@@ -242,7 +262,7 @@ async function init() {
242262 }
243263 }
244264 )
245- } catch ( cancelled ) {
265+ } catch ( cancelled : any ) {
246266 console . log ( cancelled . message )
247267 return
248268 }
@@ -259,23 +279,15 @@ async function init() {
259279 }
260280
261281 // determine template
262- template = variant || framework || template
282+ const template : string = variant || framework || argTemplate
263283
264284 const pkgInfo = pkgFromUserAgent ( process . env . npm_config_user_agent )
265285 const pkgManager = pkgInfo ? pkgInfo . name : 'npm'
266286 const isYarn1 = pkgManager === 'yarn' && pkgInfo ?. version . startsWith ( '1.' )
267287
268- if ( template . startsWith ( 'custom-' ) ) {
269- const getCustomCommand = ( name ) => {
270- for ( const f of FRAMEWORKS ) {
271- for ( const v of f . variants || [ ] ) {
272- if ( v . name === name ) {
273- return v . customCommand
274- }
275- }
276- }
277- }
278- const customCommand = getCustomCommand ( template )
288+ const { customCommand } =
289+ FRAMEWORKS . flatMap ( ( f ) => f . variants ) . find ( ( v ) => v . name === template ) ?? { }
290+ if ( customCommand ) {
279291 const fullCustomCommand = customCommand
280292 . replace ( 'TARGET_DIR' , targetDir )
281293 . replace ( / ^ n p m c r e a t e / , `${ pkgManager } create` )
@@ -309,10 +321,8 @@ async function init() {
309321 `template-${ template } `
310322 )
311323
312- const write = ( file , content ) => {
313- const targetPath = renameFiles [ file ]
314- ? path . join ( root , renameFiles [ file ] )
315- : path . join ( root , file )
324+ const write = ( file : string , content ?: string ) => {
325+ const targetPath = path . join ( root , renameFiles [ file ] ?? file )
316326 if ( content ) {
317327 fs . writeFileSync ( targetPath , content )
318328 } else {
@@ -350,14 +360,11 @@ async function init() {
350360 console . log ( )
351361}
352362
353- /**
354- * @param {string | undefined } targetDir
355- */
356- function formatTargetDir ( targetDir ) {
363+ function formatTargetDir ( targetDir : string | undefined ) {
357364 return targetDir ?. trim ( ) . replace ( / \/ + $ / g, '' )
358365}
359366
360- function copy ( src , dest ) {
367+ function copy ( src : string , dest : string ) {
361368 const stat = fs . statSync ( src )
362369 if ( stat . isDirectory ( ) ) {
363370 copyDir ( src , dest )
@@ -366,19 +373,13 @@ function copy(src, dest) {
366373 }
367374}
368375
369- /**
370- * @param {string } projectName
371- */
372- function isValidPackageName ( projectName ) {
376+ function isValidPackageName ( projectName : string ) {
373377 return / ^ (?: @ [ a - z 0 - 9 - * ~ ] [ a -z 0 -9 -* ._ ~ ] * \/ ) ? [ a - z 0 - 9 - ~ ] [ a - z 0 - 9 - ._ ~ ] * $ / . test (
374378 projectName
375379 )
376380}
377381
378- /**
379- * @param {string } projectName
380- */
381- function toValidPackageName ( projectName ) {
382+ function toValidPackageName ( projectName : string ) {
382383 return projectName
383384 . trim ( )
384385 . toLowerCase ( )
@@ -387,11 +388,7 @@ function toValidPackageName(projectName) {
387388 . replace ( / [ ^ a - z 0 - 9 - ~ ] + / g, '-' )
388389}
389390
390- /**
391- * @param {string } srcDir
392- * @param {string } destDir
393- */
394- function copyDir ( srcDir , destDir ) {
391+ function copyDir ( srcDir : string , destDir : string ) {
395392 fs . mkdirSync ( destDir , { recursive : true } )
396393 for ( const file of fs . readdirSync ( srcDir ) ) {
397394 const srcFile = path . resolve ( srcDir , file )
@@ -400,18 +397,12 @@ function copyDir(srcDir, destDir) {
400397 }
401398}
402399
403- /**
404- * @param {string } path
405- */
406- function isEmpty ( path ) {
400+ function isEmpty ( path : string ) {
407401 const files = fs . readdirSync ( path )
408402 return files . length === 0 || ( files . length === 1 && files [ 0 ] === '.git' )
409403}
410404
411- /**
412- * @param {string } dir
413- */
414- function emptyDir ( dir ) {
405+ function emptyDir ( dir : string ) {
415406 if ( ! fs . existsSync ( dir ) ) {
416407 return
417408 }
@@ -423,11 +414,7 @@ function emptyDir(dir) {
423414 }
424415}
425416
426- /**
427- * @param {string | undefined } userAgent process.env.npm_config_user_agent
428- * @returns object | undefined
429- */
430- function pkgFromUserAgent ( userAgent ) {
417+ function pkgFromUserAgent ( userAgent : string | undefined ) {
431418 if ( ! userAgent ) return undefined
432419 const pkgSpec = userAgent . split ( ' ' ) [ 0 ]
433420 const pkgSpecArr = pkgSpec . split ( '/' )
0 commit comments