11import fs from 'fs' ;
2+ import { spawnSync } from 'child_process' ;
23import { exec , execSync } from 'child_process' ;
34import Generator from 'yeoman-generator' ;
45import path from 'path' ;
@@ -8,6 +9,8 @@ import { fileURLToPath } from 'url';
89const __filename = fileURLToPath ( import . meta. url ) ;
910const __dirname = path . dirname ( __filename ) ;
1011
12+ const DOT = '.' ;
13+
1114function isKebabCase ( str ) {
1215 // Check if the string is empty
1316 if ( ! str || str . trim ( ) . length === 0 ) {
@@ -39,6 +42,12 @@ function toKebabCase(str) {
3942 . join ( '-' ) ;
4043}
4144
45+ function deleteFileIfExists ( filePath ) {
46+ if ( fs . existsSync ( filePath ) ) {
47+ fs . unlinkSync ( filePath ) ;
48+ }
49+ }
50+
4251export default class extends Generator {
4352 constructor ( args , opts ) {
4453 super ( args , opts ) ;
@@ -149,7 +158,16 @@ export default class extends Generator {
149158 . filter ( version => ! version . includes ( '-' ) ) ; // Exclude pre-releases like -alpha or -beta
150159
151160 // Sort descending and get the latest
152- const latest90 = stableVersions . sort ( ( a , b ) => ( a > b ? - 1 : 1 ) ) [ 0 ] ;
161+ const latest90 = stableVersions
162+ . sort ( ( a , b ) => {
163+ // Split version strings like '9.0.9' into [9, 0, 9]
164+ const aParts = a . split ( DOT ) . map ( Number ) ;
165+ const bParts = b . split ( DOT ) . map ( Number ) ;
166+ // Compare major, then minor, then patch
167+ if ( aParts [ 0 ] !== bParts [ 0 ] ) return bParts [ 0 ] - aParts [ 0 ] ;
168+ if ( aParts [ 1 ] !== bParts [ 1 ] ) return bParts [ 1 ] - aParts [ 1 ] ;
169+ return bParts [ 2 ] - aParts [ 2 ] ;
170+ } ) [ 0 ] ;
153171
154172 if ( ! latest90 ) {
155173 throw new Error ( 'No stable 9.0.x versions found.' ) ;
@@ -158,16 +176,22 @@ export default class extends Generator {
158176 // Log the chosen version (optional)
159177 this . log ( `Latest stable 9.0 version: ${ latest90 } ` ) ;
160178
161- // Use `this.spawnCommandSync` with the selected version
162- this . spawnCommandSync ( 'npx' , [
179+ spawnSync ( 'npx' , [
163180 '-y' ,
164181 `storybook@${ latest90 } ` ,
165182 'init' ,
166183 '--no-dev' ,
167184 '--yes' , // Skip all prompts
168185 '--type' , 'nextjs' , // Specify Next.js as the framework
169- ] ) ;
186+ ] , { stdio : 'inherit' , cwd : this . destinationRoot ( ) } ) ;
170187 this . log ( 'Storybook installed!' ) ;
188+ this . log ( 'Installing @storybook/react-vite for Vite builder support...' ) ;
189+ spawnSync ( 'npm' , [
190+ 'install' ,
191+ '--save-dev' ,
192+ '@storybook/react-vite'
193+ ] , { stdio : 'inherit' , cwd : this . destinationRoot ( ) } ) ;
194+ this . log ( '@storybook/react-vite installed!' ) ;
171195 // if (this.options.tailwind && this.options.storybook) {
172196 // Tailwind CSS specific setup for older versions of Storybook
173197 // this.spawnCommandSync('npx', ['storybook@latest', 'add', '@storybook/addon-styling-webpack']);
@@ -179,16 +203,16 @@ export default class extends Generator {
179203 // Conditionally add Cypress
180204 if ( this . options . cypress ) {
181205 this . log ( 'Installing Cypress...' ) ;
182- this . spawnCommandSync ( 'npm' , [ 'install' , '--save-dev' , 'cypress' ] ) ;
206+ spawnSync ( 'npm' , [ 'install' , '--save-dev' , 'cypress' ] , { stdio : 'inherit' , cwd : this . destinationRoot ( ) } ) ;
183207 this . log ( 'Cypress installed!' ) ;
184208 if ( this . options . bitloops ) {
185- this . spawnCommandSync ( 'npm' , [
209+ spawnSync ( 'npm' , [
186210 'install' ,
187211 '--save-dev' ,
188212 'mochawesome' ,
189213 'mochawesome-merge' ,
190214 'mochawesome-report-generator' ,
191- ] ) ;
215+ ] , { stdio : 'inherit' , cwd : this . destinationRoot ( ) } ) ;
192216 }
193217 }
194218 } ;
@@ -198,7 +222,7 @@ export default class extends Generator {
198222 if ( this . options . storybook ) {
199223 this . log ( 'Making Storybook changes...' ) ;
200224 if ( this . options . tailwind ) {
201- fs . unlinkSync ( this . destinationPath ( '.storybook/preview.ts' ) ) ;
225+ deleteFileIfExists ( this . destinationPath ( '.storybook/preview.ts' ) ) ;
202226 this . log ( 'Setting up Tailwind CSS with Storybook...' ) ;
203227 this . fs . copyTpl (
204228 this . templatePath ( 'storybook.preview.ts' ) ,
@@ -225,21 +249,21 @@ export default class extends Generator {
225249 ) ;
226250 }
227251
228- fs . unlinkSync ( this . destinationPath ( 'src/app/page.tsx' ) ) ;
252+ deleteFileIfExists ( this . destinationPath ( 'src/app/page.tsx' ) ) ;
229253 this . fs . copyTpl (
230254 this . templatePath ( 'next.app.page.tsx' ) ,
231255 this . destinationPath ( 'src/app/page.tsx' )
232256 ) ;
233257
234- fs . unlinkSync ( this . destinationPath ( 'src/app/layout.tsx' ) ) ;
258+ deleteFileIfExists ( this . destinationPath ( 'src/app/layout.tsx' ) ) ;
235259 this . fs . copyTpl (
236260 this . templatePath ( 'next.app.layout.tsx' ) ,
237261 this . destinationPath ( 'src/app/layout.tsx' ) ,
238262 { projectName : this . options . project }
239263 ) ;
240264
241265 this . log ( 'Adding Meyer reset in global.css...' ) ;
242- fs . unlinkSync ( this . destinationPath ( 'src/app/globals.css' ) ) ;
266+ deleteFileIfExists ( this . destinationPath ( 'src/app/globals.css' ) ) ;
243267 this . fs . copyTpl (
244268 this . templatePath ( 'globals.css' ) ,
245269 this . destinationPath ( 'src/app/globals.css' )
@@ -276,11 +300,11 @@ export default class extends Generator {
276300 const path = 'cypress/helpers/index.ts' ;
277301 this . fs . copyTpl ( this . templatePath ( path ) , this . destinationPath ( path ) ) ;
278302 }
279- this . spawnCommandSync ( 'npm' , [
303+ spawnSync ( 'npm' , [
280304 'install' ,
281305 '--save-dev' ,
282306 'react-aria-components' ,
283- ] ) ;
307+ ] , { stdio : 'inherit' , cwd : this . destinationRoot ( ) } ) ;
284308 }
285309 } ;
286310
0 commit comments