|
1 | 1 | import { basename, resolve } from 'node:path'
|
2 |
| -import { render } from 'ejs' |
3 |
| -import { format } from 'prettier' |
4 | 2 |
|
5 | 3 | import {
|
6 |
| - CODE_ROUTER, |
7 | 4 | FILE_ROUTER,
|
8 | 5 | copyAddOnFile,
|
| 6 | + jsSafeName, |
9 | 7 | packageManagerExecute,
|
10 |
| - sortObject, |
11 | 8 | writeConfigFile,
|
12 | 9 | } from '@tanstack/cta-core'
|
13 | 10 |
|
14 |
| -import type { AddOn, Environment, Options } from '@tanstack/cta-core' |
15 |
| - |
16 |
| -function createCopyFiles(environment: Environment, targetDir: string) { |
17 |
| - return async function copyFiles( |
18 |
| - templateDir: string, |
19 |
| - files: Array<string>, |
20 |
| - // optionally copy files from a folder to the root |
21 |
| - toRoot?: boolean, |
22 |
| - ) { |
23 |
| - for (const file of files) { |
24 |
| - let targetFileName = file.replace('.tw', '') |
25 |
| - if (toRoot) { |
26 |
| - const fileNoPath = targetFileName.split('/').pop() |
27 |
| - targetFileName = fileNoPath ? `./${fileNoPath}` : targetFileName |
28 |
| - } |
29 |
| - await environment.copyFile( |
30 |
| - resolve(templateDir, file), |
31 |
| - resolve(targetDir, targetFileName), |
32 |
| - ) |
33 |
| - } |
34 |
| - } |
35 |
| -} |
36 |
| - |
37 |
| -function jsSafeName(name: string) { |
38 |
| - return name |
39 |
| - .split(/[^a-zA-Z0-9]/) |
40 |
| - .map((part) => part.charAt(0).toUpperCase() + part.slice(1)) |
41 |
| - .join('') |
42 |
| -} |
43 |
| - |
44 |
| -function createTemplateFile( |
45 |
| - environment: Environment, |
46 |
| - projectName: string, |
47 |
| - options: Options, |
48 |
| - targetDir: string, |
49 |
| -) { |
50 |
| - return async function templateFile( |
51 |
| - file: string, |
52 |
| - content: string, |
53 |
| - targetFileName?: string, |
54 |
| - extraTemplateValues?: Record<string, any>, |
55 |
| - ) { |
56 |
| - function getPackageManagerAddScript( |
57 |
| - packageName: string, |
58 |
| - isDev: boolean = false, |
59 |
| - ) { |
60 |
| - let command |
61 |
| - switch (options.packageManager) { |
62 |
| - case 'yarn': |
63 |
| - case 'pnpm': |
64 |
| - command = isDev |
65 |
| - ? `${options.packageManager} add ${packageName} --dev` |
66 |
| - : `${options.packageManager} add ${packageName}` |
67 |
| - break |
68 |
| - default: |
69 |
| - command = isDev |
70 |
| - ? `${options.packageManager} install ${packageName} -D` |
71 |
| - : `${options.packageManager} install ${packageName}` |
72 |
| - break |
73 |
| - } |
74 |
| - return command |
75 |
| - } |
| 11 | +import { createCopyFiles } from './copy-files.js' |
| 12 | +import { createPackageJSON } from './package-json.js' |
| 13 | +import { createTemplateFile } from './template-file.js' |
76 | 14 |
|
77 |
| - function getPackageManagerRunScript(scriptName: string) { |
78 |
| - let command |
79 |
| - switch (options.packageManager) { |
80 |
| - case 'yarn': |
81 |
| - case 'pnpm': |
82 |
| - command = `${options.packageManager} ${scriptName}` |
83 |
| - break |
84 |
| - case 'deno': |
85 |
| - command = `${options.packageManager} task ${scriptName}` |
86 |
| - break |
87 |
| - default: |
88 |
| - command = `${options.packageManager} run ${scriptName}` |
89 |
| - break |
90 |
| - } |
91 |
| - return command |
92 |
| - } |
93 |
| - |
94 |
| - const templateValues = { |
95 |
| - packageManager: options.packageManager, |
96 |
| - projectName: projectName, |
97 |
| - typescript: options.typescript, |
98 |
| - tailwind: options.tailwind, |
99 |
| - toolchain: options.toolchain, |
100 |
| - js: options.typescript ? 'ts' : 'js', |
101 |
| - jsx: options.typescript ? 'tsx' : 'jsx', |
102 |
| - fileRouter: options.mode === FILE_ROUTER, |
103 |
| - codeRouter: options.mode === CODE_ROUTER, |
104 |
| - addOnEnabled: options.chosenAddOns.reduce<Record<string, boolean>>( |
105 |
| - (acc, addOn) => { |
106 |
| - acc[addOn.id] = true |
107 |
| - return acc |
108 |
| - }, |
109 |
| - {}, |
110 |
| - ), |
111 |
| - addOns: options.chosenAddOns, |
112 |
| - |
113 |
| - ...extraTemplateValues, |
114 |
| - |
115 |
| - getPackageManagerAddScript, |
116 |
| - getPackageManagerRunScript, |
117 |
| - } |
118 |
| - |
119 |
| - try { |
120 |
| - content = render(content, templateValues) |
121 |
| - } catch (error) { |
122 |
| - environment.error(`EJS error in file ${file}`, error?.toString()) |
123 |
| - process.exit(1) |
124 |
| - } |
125 |
| - const target = targetFileName ?? file.replace('.ejs', '') |
126 |
| - |
127 |
| - if (target.endsWith('.ts') || target.endsWith('.tsx')) { |
128 |
| - content = await format(content, { |
129 |
| - semi: false, |
130 |
| - singleQuote: true, |
131 |
| - trailingComma: 'all', |
132 |
| - parser: 'typescript', |
133 |
| - }) |
134 |
| - } |
135 |
| - |
136 |
| - await environment.writeFile(resolve(targetDir, target), content) |
137 |
| - } |
138 |
| -} |
139 |
| - |
140 |
| -async function createPackageJSON( |
141 |
| - environment: Environment, |
142 |
| - projectName: string, |
143 |
| - options: Options, |
144 |
| - templateDir: string, |
145 |
| - routerDir: string, |
146 |
| - targetDir: string, |
147 |
| - addOns: Array<{ |
148 |
| - dependencies?: Record<string, string> |
149 |
| - devDependencies?: Record<string, string> |
150 |
| - scripts?: Record<string, string> |
151 |
| - }>, |
152 |
| -) { |
153 |
| - let packageJSON = JSON.parse( |
154 |
| - await environment.readFile(resolve(templateDir, 'package.json'), 'utf8'), |
155 |
| - ) |
156 |
| - packageJSON.name = projectName |
157 |
| - if (options.typescript) { |
158 |
| - const tsPackageJSON = JSON.parse( |
159 |
| - await environment.readFile( |
160 |
| - resolve(templateDir, 'package.ts.json'), |
161 |
| - 'utf8', |
162 |
| - ), |
163 |
| - ) |
164 |
| - packageJSON = { |
165 |
| - ...packageJSON, |
166 |
| - devDependencies: { |
167 |
| - ...packageJSON.devDependencies, |
168 |
| - ...tsPackageJSON.devDependencies, |
169 |
| - }, |
170 |
| - } |
171 |
| - } |
172 |
| - if (options.tailwind) { |
173 |
| - const twPackageJSON = JSON.parse( |
174 |
| - await environment.readFile( |
175 |
| - resolve(templateDir, 'package.tw.json'), |
176 |
| - 'utf8', |
177 |
| - ), |
178 |
| - ) |
179 |
| - packageJSON = { |
180 |
| - ...packageJSON, |
181 |
| - dependencies: { |
182 |
| - ...packageJSON.dependencies, |
183 |
| - ...twPackageJSON.dependencies, |
184 |
| - }, |
185 |
| - } |
186 |
| - } |
187 |
| - if (options.toolchain === 'biome') { |
188 |
| - const biomePackageJSON = JSON.parse( |
189 |
| - await environment.readFile( |
190 |
| - resolve(templateDir, 'package.biome.json'), |
191 |
| - 'utf8', |
192 |
| - ), |
193 |
| - ) |
194 |
| - packageJSON = { |
195 |
| - ...packageJSON, |
196 |
| - scripts: { |
197 |
| - ...packageJSON.scripts, |
198 |
| - ...biomePackageJSON.scripts, |
199 |
| - }, |
200 |
| - devDependencies: { |
201 |
| - ...packageJSON.devDependencies, |
202 |
| - ...biomePackageJSON.devDependencies, |
203 |
| - }, |
204 |
| - } |
205 |
| - } |
206 |
| - if (options.toolchain === 'eslint+prettier') { |
207 |
| - const eslintPrettierPackageJSON = JSON.parse( |
208 |
| - await environment.readFile( |
209 |
| - resolve(templateDir, 'package.eslintprettier.json'), |
210 |
| - 'utf-8', |
211 |
| - ), |
212 |
| - ) |
213 |
| - packageJSON = { |
214 |
| - ...packageJSON, |
215 |
| - scripts: { |
216 |
| - ...packageJSON.scripts, |
217 |
| - ...eslintPrettierPackageJSON.scripts, |
218 |
| - }, |
219 |
| - devDependencies: { |
220 |
| - ...packageJSON.devDependencies, |
221 |
| - ...eslintPrettierPackageJSON.devDependencies, |
222 |
| - }, |
223 |
| - } |
224 |
| - } |
225 |
| - if (options.mode === FILE_ROUTER) { |
226 |
| - const frPackageJSON = JSON.parse( |
227 |
| - await environment.readFile(resolve(routerDir, 'package.fr.json'), 'utf8'), |
228 |
| - ) |
229 |
| - packageJSON = { |
230 |
| - ...packageJSON, |
231 |
| - dependencies: { |
232 |
| - ...packageJSON.dependencies, |
233 |
| - ...frPackageJSON.dependencies, |
234 |
| - }, |
235 |
| - } |
236 |
| - } |
237 |
| - |
238 |
| - for (const addOn of addOns) { |
239 |
| - packageJSON = { |
240 |
| - ...packageJSON, |
241 |
| - dependencies: { |
242 |
| - ...packageJSON.dependencies, |
243 |
| - ...addOn.dependencies, |
244 |
| - }, |
245 |
| - devDependencies: { |
246 |
| - ...packageJSON.devDependencies, |
247 |
| - ...addOn.devDependencies, |
248 |
| - }, |
249 |
| - scripts: { |
250 |
| - ...packageJSON.scripts, |
251 |
| - ...addOn.scripts, |
252 |
| - }, |
253 |
| - } |
254 |
| - } |
255 |
| - |
256 |
| - packageJSON.dependencies = sortObject( |
257 |
| - packageJSON.dependencies as Record<string, string>, |
258 |
| - ) |
259 |
| - packageJSON.devDependencies = sortObject( |
260 |
| - packageJSON.devDependencies as Record<string, string>, |
261 |
| - ) |
262 |
| - |
263 |
| - await environment.writeFile( |
264 |
| - resolve(targetDir, 'package.json'), |
265 |
| - JSON.stringify(packageJSON, null, 2), |
266 |
| - ) |
267 |
| -} |
| 15 | +import type { AddOn, Environment, Options } from '@tanstack/cta-core' |
268 | 16 |
|
269 | 17 | export async function createApp(
|
270 | 18 | options: Options,
|
|
0 commit comments