11import fs from 'node:fs'
22import path from 'node:path'
33import type { SupportedFrontend } from 'src/constants'
4-
5- type SourcePath = `${SupportedFrontend } -graphql` | 'shared'
6-
7- type FilesConfig = {
8- targetPath : string
9- sourcePath : SourcePath
10- fileName : string
11- rename ?: string
12- }
13-
14- type ScaffoldFilesPerFrontend = Record <
15- SupportedFrontend ,
16- {
17- files : FilesConfig [ ]
18- }
19- >
4+ import {
5+ DrupalAuthFile ,
6+ DrupalClientFile ,
7+ EnvFile ,
8+ TailwindCSSFile ,
9+ } from './files/shared'
2010
2111const SCAFFOLD_FILES_PER_FRONTEND : Readonly < ScaffoldFilesPerFrontend > = {
2212 remix : {
2313 files : [
14+ DrupalClientFile ,
15+ DrupalAuthFile ,
16+ EnvFile ,
2417 {
25- targetPath : 'app/utils/drupal' ,
26- sourcePath : 'shared ' ,
27- fileName : 'client.server.ts ' ,
18+ ... EnvFile ,
19+ rename : '.env ' ,
20+ operation : 'update ' ,
2821 } ,
2922 {
30- targetPath : 'app/utils/drupal' ,
23+ targetPath : 'app' ,
24+ sourcePath : 'remix-graphql' ,
25+ fileName : 'tailwind.css' ,
26+ operation : 'update' ,
27+ } ,
28+ {
29+ targetPath : 'app/utils' ,
3130 sourcePath : 'remix-graphql' ,
3231 fileName : 'calculate-path.server.ts' ,
32+ operation : 'create' ,
3333 } ,
3434 {
3535 targetPath : 'app/routes' ,
3636 sourcePath : 'remix-graphql' ,
3737 fileName : '$.tsx' ,
38+ operation : 'create' ,
3839 } ,
3940 {
40- targetPath : 'app' ,
41- sourcePath : 'shared' ,
42- fileName : 'tailwind.css' ,
43- } ,
44- {
45- targetPath : '.' ,
46- sourcePath : 'shared' ,
47- fileName : '.env.example' ,
41+ targetPath : 'app/routes' ,
42+ sourcePath : 'remix-graphql' ,
43+ fileName : '$.tsx' ,
44+ rename : '_index.tsx' ,
45+ operation : 'update' ,
4846 } ,
4947 ] ,
5048 } ,
5149 next : {
5250 files : [
5351 {
54- targetPath : 'utils/drupal' ,
55- sourcePath : 'shared' ,
56- fileName : 'client.server.ts' ,
52+ ...DrupalClientFile ,
53+ targetPath : '/utils' ,
5754 rename : 'client.ts' ,
55+ sanitize : ( fileContent : string ) =>
56+ fileContent . replace (
57+ "import { getToken } from './auth.server'" ,
58+ "import { getToken } from './auth'"
59+ ) ,
60+ } ,
61+ {
62+ ...DrupalAuthFile ,
63+ targetPath : '/utils' ,
64+ rename : 'auth.ts' ,
65+ } ,
66+ {
67+ ...TailwindCSSFile ,
68+ rename : 'globals.css' ,
5869 } ,
70+ EnvFile ,
5971 {
60- targetPath : 'utils/drupal' ,
72+ ...EnvFile ,
73+ rename : '.env.local' ,
74+ operation : 'update' ,
75+ } ,
76+ {
77+ targetPath : 'utils' ,
6178 sourcePath : 'next-graphql' ,
6279 fileName : 'calculate-path.ts' ,
80+ operation : 'create' ,
6381 } ,
6482 {
65- targetPath : 'app/[...slug]' ,
83+ targetPath : 'app/[[ ...slug] ]' ,
6684 sourcePath : 'next-graphql' ,
6785 fileName : 'page.tsx' ,
86+ operation : 'create' ,
6887 } ,
6988 {
89+ operation : 'delete' ,
7090 targetPath : 'app' ,
71- sourcePath : 'shared' ,
72- fileName : 'tailwind.css' ,
73- rename : 'globals.css' ,
91+ fileName : 'page.tsx' ,
92+ } ,
93+ ] ,
94+ } ,
95+ 'react-router' : {
96+ files : [
97+ DrupalClientFile ,
98+ DrupalAuthFile ,
99+ EnvFile ,
100+ {
101+ ...EnvFile ,
102+ rename : '.env' ,
103+ operation : 'update' ,
74104 } ,
75105 {
76- targetPath : '.' ,
106+ ...TailwindCSSFile ,
107+ rename : 'app.css' ,
108+ operation : 'update' ,
109+ } ,
110+ {
111+ targetPath : 'app/utils' ,
77112 sourcePath : 'shared' ,
78- fileName : '.env.example' ,
113+ fileName : 'metatags.ts' ,
114+ operation : 'create' ,
115+ } ,
116+ {
117+ targetPath : 'app' ,
118+ sourcePath : 'react-router-graphql' ,
119+ fileName : 'routes.ts' ,
120+ operation : 'update' ,
121+ } ,
122+ {
123+ targetPath : 'app/routes' ,
124+ sourcePath : 'react-router-graphql' ,
125+ fileName : '$.tsx' ,
126+ operation : 'create' ,
127+ } ,
128+ {
129+ targetPath : 'app/routes' ,
130+ fileName : 'home.tsx' ,
131+ operation : 'delete' ,
132+ } ,
133+ {
134+ targetPath : 'app/utils' ,
135+ sourcePath : 'react-router-graphql' ,
136+ fileName : 'calculatePath.ts' ,
137+ rename : 'routes.ts' ,
138+ operation : 'create' ,
79139 } ,
80140 ] ,
81141 } ,
@@ -85,13 +145,65 @@ export function isJavascriptProject(projectPath: string) {
85145 return fs . existsSync ( path . join ( projectPath , 'package.json' ) )
86146}
87147
148+ // Validate if the project
149+ export function isValidFramework (
150+ projectPath : string ,
151+ frontend : SupportedFrontend
152+ ) {
153+ const packageJsonPath = path . join ( projectPath , 'package.json' )
154+ if ( ! fs . existsSync ( packageJsonPath ) ) {
155+ return false
156+ }
157+
158+ const packageJson = JSON . parse ( fs . readFileSync ( packageJsonPath , 'utf-8' ) )
159+ const dependencies = packageJson . dependencies || { }
160+ const devDependencies = packageJson . devDependencies || { }
161+
162+ if ( frontend === 'next' ) {
163+ return Boolean ( dependencies [ 'next' ] )
164+ }
165+
166+ if ( frontend === 'remix' ) {
167+ return Boolean ( devDependencies [ '@remix-run/dev' ] )
168+ }
169+
170+ if ( frontend === 'react-router' ) {
171+ return Boolean ( devDependencies [ '@react-router/dev' ] )
172+ }
173+
174+ return false
175+ }
176+
177+ export function updateGitignore (
178+ frontend : SupportedFrontend ,
179+ projectPath : string
180+ ) {
181+ const gitignorePath = path . join ( projectPath , '.gitignore' )
182+ const gitignoreContent = fs . readFileSync ( gitignorePath , 'utf-8' )
183+ const envFileName = frontend === 'next' ? '.env*' : '.env'
184+
185+ if ( ! gitignoreContent . includes ( envFileName ) ) {
186+ fs . appendFileSync ( gitignorePath , `\n${ envFileName } \n` )
187+ }
188+ }
189+
88190export function scaffoldFrontend (
89191 frontend : SupportedFrontend ,
90192 projectPath : string
91193) {
92194 const frontendFiles = SCAFFOLD_FILES_PER_FRONTEND [ frontend ] . files
93195
94- return frontendFiles . map ( ( { targetPath, sourcePath, fileName, rename } ) => {
196+ return frontendFiles . map ( ( config ) => {
197+ const { operation, fileName, targetPath } = config
198+
199+ if ( operation === 'delete' ) {
200+ const filePath = path . join ( projectPath , targetPath , fileName )
201+ if ( fs . existsSync ( filePath ) ) {
202+ fs . rmSync ( filePath , { recursive : true , force : true } )
203+ }
204+ return `Deleted ${ targetPath === '.' ? '' : `${ targetPath } /` } ${ fileName } `
205+ }
206+ const { sourcePath, rename, sanitize } = config
95207 const name = rename || fileName
96208
97209 const templatePath = path . join ( __dirname , 'templates' , sourcePath , fileName )
@@ -101,10 +213,17 @@ export function scaffoldFrontend(
101213 targetPath ,
102214 name
103215 )
104-
105216 fs . mkdirSync ( path . dirname ( destinationPath ) , { recursive : true } )
106- fs . copyFileSync ( templatePath , destinationPath )
107217
108- return `${ targetPath === '.' ? '' : `${ targetPath } /` } ${ name } `
218+ let fileContent = fs . readFileSync ( templatePath , 'utf-8' )
219+
220+ if ( sanitize ) {
221+ fileContent = sanitize ( fileContent )
222+ }
223+
224+ fs . writeFileSync ( destinationPath , fileContent )
225+
226+ const message = operation === 'update' ? 'Updated' : 'Created'
227+ return `${ message } ${ targetPath === '.' ? '' : `${ targetPath } /` } ${ name } `
109228 } )
110229}
0 commit comments