@idealyst/cli 1.0.24 ā 1.0.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +109 -109
- package/dist/index.js +233 -36
- package/dist/types/generators/api.d.ts +2 -0
- package/dist/types/generators/index.d.ts +1 -0
- package/dist/types/generators/utils.d.ts +18 -1
- package/dist/types/types.d.ts +2 -1
- package/package.json +1 -1
- package/templates/api/README.md +207 -0
- package/templates/api/env.example +12 -0
- package/templates/api/package.json +49 -0
- package/templates/api/prisma/schema.prisma +21 -0
- package/templates/api/src/context.ts +23 -0
- package/templates/api/src/controllers/UserController.ts +102 -0
- package/templates/api/src/index.ts +14 -0
- package/templates/api/src/lib/controller.ts +90 -0
- package/templates/api/src/lib/middleware.ts +170 -0
- package/templates/api/src/middleware/auth.ts +75 -0
- package/templates/api/src/middleware/common.ts +103 -0
- package/templates/api/src/router/index.ts +130 -0
- package/templates/api/src/server.ts +50 -0
- package/templates/api/src/trpc.ts +28 -0
- package/templates/api/tsconfig.json +44 -0
- package/templates/native/.yarnrc.yml +18 -18
- package/templates/native/App.tsx +23 -23
- package/templates/native/README.md +85 -85
- package/templates/native/app.json +4 -4
- package/templates/native/babel.config.js +9 -9
- package/templates/native/index.js +5 -5
- package/templates/native/metro.config.js +27 -27
- package/templates/native/package.json +9 -9
- package/templates/native/src/App-with-trpc.tsx +72 -0
- package/templates/native/src/utils/trpc.ts +127 -0
- package/templates/native/tsconfig.json +29 -29
- package/templates/shared/README.md +108 -108
- package/templates/shared/package.json +39 -39
- package/templates/shared/tsconfig.json +24 -24
- package/templates/web/README.md +89 -89
- package/templates/web/index.html +12 -12
- package/templates/web/package.json +55 -51
- package/templates/web/src/App-with-trpc.tsx +80 -0
- package/templates/web/src/App.tsx +14 -14
- package/templates/web/src/main.tsx +24 -24
- package/templates/web/src/utils/trpc.ts +93 -0
- package/templates/web/tsconfig.json +26 -26
- package/templates/web/vite.config.ts +68 -68
- package/templates/workspace/.yarnrc.yml +25 -25
- package/templates/workspace/README.md +79 -79
- package/templates/workspace/package.json +24 -24
package/README.md
CHANGED
|
@@ -1,110 +1,110 @@
|
|
|
1
|
-
# @idealyst/cli
|
|
2
|
-
|
|
3
|
-
CLI tool for generating Idealyst Framework projects.
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
Install globally:
|
|
8
|
-
```bash
|
|
9
|
-
npm install -g @idealyst/cli
|
|
10
|
-
# or
|
|
11
|
-
yarn global add @idealyst/cli
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
## Usage
|
|
15
|
-
|
|
16
|
-
### Create a new project
|
|
17
|
-
|
|
18
|
-
```bash
|
|
19
|
-
idealyst create <project-name> [options]
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
Options:
|
|
23
|
-
- `-t, --type <type>` - Project type: `native`, `web`, or `shared` (default: `native`)
|
|
24
|
-
- `-d, --directory <directory>` - Output directory (default: current directory)
|
|
25
|
-
- `--skip-install` - Skip installing dependencies
|
|
26
|
-
|
|
27
|
-
### Initialize a new workspace
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
idealyst init [options]
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
Options:
|
|
34
|
-
- `-d, --directory <directory>` - Output directory (default: current directory)
|
|
35
|
-
- `--skip-install` - Skip installing dependencies
|
|
36
|
-
|
|
37
|
-
## Examples
|
|
38
|
-
|
|
39
|
-
Create a React Native app:
|
|
40
|
-
```bash
|
|
41
|
-
idealyst create my-app --type native
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
Create a React web app:
|
|
45
|
-
```bash
|
|
46
|
-
idealyst create my-web-app --type web
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
Create a shared library:
|
|
50
|
-
```bash
|
|
51
|
-
idealyst create my-lib --type shared
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
Initialize a new workspace:
|
|
55
|
-
```bash
|
|
56
|
-
idealyst init
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
## Project Types
|
|
60
|
-
|
|
61
|
-
### Native (React Native)
|
|
62
|
-
- React Native 0.80.1
|
|
63
|
-
- Idealyst Components
|
|
64
|
-
- Idealyst Navigation
|
|
65
|
-
- Idealyst Theme
|
|
66
|
-
- TypeScript configuration
|
|
67
|
-
- Metro bundler configuration
|
|
68
|
-
- Babel configuration
|
|
69
|
-
|
|
70
|
-
### Web (React + Vite)
|
|
71
|
-
- React 19.1
|
|
72
|
-
- Vite build system
|
|
73
|
-
- Idealyst Components (web-compatible)
|
|
74
|
-
- Idealyst Navigation
|
|
75
|
-
- Idealyst Theme
|
|
76
|
-
- TypeScript configuration
|
|
77
|
-
- React Native Web support
|
|
78
|
-
|
|
79
|
-
### Shared Library
|
|
80
|
-
- Cross-platform components
|
|
81
|
-
- TypeScript definitions
|
|
82
|
-
- Rollup build system
|
|
83
|
-
- Peer dependencies for React/React Native
|
|
84
|
-
- Idealyst Theme integration
|
|
85
|
-
|
|
86
|
-
### Workspace
|
|
87
|
-
- Yarn workspace configuration
|
|
88
|
-
- Monorepo structure
|
|
89
|
-
- Version management scripts
|
|
90
|
-
- Build scripts for all packages
|
|
91
|
-
|
|
92
|
-
## Development
|
|
93
|
-
|
|
94
|
-
Build the CLI:
|
|
95
|
-
```bash
|
|
96
|
-
cd packages/cli
|
|
97
|
-
yarn build
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
Link for local development:
|
|
101
|
-
```bash
|
|
102
|
-
yarn link
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
## Learn More
|
|
106
|
-
|
|
107
|
-
- [Idealyst Framework Documentation](https://github.com/your-username/idealyst-framework)
|
|
108
|
-
- [React Native Documentation](https://reactnative.dev/)
|
|
109
|
-
- [React Documentation](https://react.dev/)
|
|
1
|
+
# @idealyst/cli
|
|
2
|
+
|
|
3
|
+
CLI tool for generating Idealyst Framework projects.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Install globally:
|
|
8
|
+
```bash
|
|
9
|
+
npm install -g @idealyst/cli
|
|
10
|
+
# or
|
|
11
|
+
yarn global add @idealyst/cli
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
### Create a new project
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
idealyst create <project-name> [options]
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Options:
|
|
23
|
+
- `-t, --type <type>` - Project type: `native`, `web`, or `shared` (default: `native`)
|
|
24
|
+
- `-d, --directory <directory>` - Output directory (default: current directory)
|
|
25
|
+
- `--skip-install` - Skip installing dependencies
|
|
26
|
+
|
|
27
|
+
### Initialize a new workspace
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
idealyst init [options]
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Options:
|
|
34
|
+
- `-d, --directory <directory>` - Output directory (default: current directory)
|
|
35
|
+
- `--skip-install` - Skip installing dependencies
|
|
36
|
+
|
|
37
|
+
## Examples
|
|
38
|
+
|
|
39
|
+
Create a React Native app:
|
|
40
|
+
```bash
|
|
41
|
+
idealyst create my-app --type native
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Create a React web app:
|
|
45
|
+
```bash
|
|
46
|
+
idealyst create my-web-app --type web
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Create a shared library:
|
|
50
|
+
```bash
|
|
51
|
+
idealyst create my-lib --type shared
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Initialize a new workspace:
|
|
55
|
+
```bash
|
|
56
|
+
idealyst init
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Project Types
|
|
60
|
+
|
|
61
|
+
### Native (React Native)
|
|
62
|
+
- React Native 0.80.1
|
|
63
|
+
- Idealyst Components
|
|
64
|
+
- Idealyst Navigation
|
|
65
|
+
- Idealyst Theme
|
|
66
|
+
- TypeScript configuration
|
|
67
|
+
- Metro bundler configuration
|
|
68
|
+
- Babel configuration
|
|
69
|
+
|
|
70
|
+
### Web (React + Vite)
|
|
71
|
+
- React 19.1
|
|
72
|
+
- Vite build system
|
|
73
|
+
- Idealyst Components (web-compatible)
|
|
74
|
+
- Idealyst Navigation
|
|
75
|
+
- Idealyst Theme
|
|
76
|
+
- TypeScript configuration
|
|
77
|
+
- React Native Web support
|
|
78
|
+
|
|
79
|
+
### Shared Library
|
|
80
|
+
- Cross-platform components
|
|
81
|
+
- TypeScript definitions
|
|
82
|
+
- Rollup build system
|
|
83
|
+
- Peer dependencies for React/React Native
|
|
84
|
+
- Idealyst Theme integration
|
|
85
|
+
|
|
86
|
+
### Workspace
|
|
87
|
+
- Yarn workspace configuration
|
|
88
|
+
- Monorepo structure
|
|
89
|
+
- Version management scripts
|
|
90
|
+
- Build scripts for all packages
|
|
91
|
+
|
|
92
|
+
## Development
|
|
93
|
+
|
|
94
|
+
Build the CLI:
|
|
95
|
+
```bash
|
|
96
|
+
cd packages/cli
|
|
97
|
+
yarn build
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Link for local development:
|
|
101
|
+
```bash
|
|
102
|
+
yarn link
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Learn More
|
|
106
|
+
|
|
107
|
+
- [Idealyst Framework Documentation](https://github.com/your-username/idealyst-framework)
|
|
108
|
+
- [React Native Documentation](https://reactnative.dev/)
|
|
109
|
+
- [React Documentation](https://react.dev/)
|
|
110
110
|
- [Vite Documentation](https://vitejs.dev/)
|
package/dist/index.js
CHANGED
|
@@ -16,7 +16,7 @@ function validateProjectName(name) {
|
|
|
16
16
|
function createPackageName(name) {
|
|
17
17
|
return name.toLowerCase().replace(/[^a-z0-9-]/g, '-');
|
|
18
18
|
}
|
|
19
|
-
async function updateWorkspacePackageJson(
|
|
19
|
+
async function updateWorkspacePackageJson(workspacePath, directory) {
|
|
20
20
|
// Look for package.json in the directory to see if we're in a workspace
|
|
21
21
|
const packageJsonPath = path.join(directory, 'package.json');
|
|
22
22
|
if (await fs.pathExists(packageJsonPath)) {
|
|
@@ -24,11 +24,18 @@ async function updateWorkspacePackageJson(projectName, directory) {
|
|
|
24
24
|
const packageJson = await fs.readJSON(packageJsonPath);
|
|
25
25
|
// Check if this is a workspace (has workspaces property)
|
|
26
26
|
if (packageJson.workspaces && Array.isArray(packageJson.workspaces)) {
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
// Check if workspace already covers this path with a wildcard
|
|
28
|
+
const workspaceDir = path.dirname(workspacePath);
|
|
29
|
+
const wildcardPattern = `${workspaceDir}/*`;
|
|
30
|
+
const isAlreadyCovered = packageJson.workspaces.some((ws) => ws === wildcardPattern || ws === workspacePath);
|
|
31
|
+
// Add the new project to workspaces if not already present or covered
|
|
32
|
+
if (!isAlreadyCovered) {
|
|
33
|
+
packageJson.workspaces.push(workspacePath);
|
|
30
34
|
await fs.writeJSON(packageJsonPath, packageJson, { spaces: 2 });
|
|
31
|
-
console.log(chalk.green(`ā
Added ${
|
|
35
|
+
console.log(chalk.green(`ā
Added ${workspacePath} to workspace configuration`));
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
console.log(chalk.blue(`š¦ Project ${workspacePath} already covered by existing workspace configuration`));
|
|
32
39
|
}
|
|
33
40
|
}
|
|
34
41
|
}
|
|
@@ -78,6 +85,9 @@ async function processTemplateFile(filePath, data) {
|
|
|
78
85
|
content = content.replace(/\{\{packageName\}\}/g, data.packageName);
|
|
79
86
|
content = content.replace(/\{\{version\}\}/g, data.version);
|
|
80
87
|
content = content.replace(/\{\{description\}\}/g, data.description);
|
|
88
|
+
// Handle appName (with fallback to projectName if not provided)
|
|
89
|
+
const appName = data.appName || data.projectName;
|
|
90
|
+
content = content.replace(/\{\{appName\}\}/g, appName);
|
|
81
91
|
await fs.writeFile(filePath, content);
|
|
82
92
|
}
|
|
83
93
|
catch (error) {
|
|
@@ -133,6 +143,43 @@ function getTemplateData(projectName, description, appName) {
|
|
|
133
143
|
appName
|
|
134
144
|
};
|
|
135
145
|
}
|
|
146
|
+
/**
|
|
147
|
+
* Detects if we're in a workspace root directory
|
|
148
|
+
*/
|
|
149
|
+
async function isWorkspaceRoot(directory) {
|
|
150
|
+
const packageJsonPath = path.join(directory, 'package.json');
|
|
151
|
+
if (await fs.pathExists(packageJsonPath)) {
|
|
152
|
+
try {
|
|
153
|
+
const packageJson = await fs.readJSON(packageJsonPath);
|
|
154
|
+
return !!(packageJson.workspaces && Array.isArray(packageJson.workspaces));
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Resolves the correct project path for individual projects (native, web, shared).
|
|
164
|
+
* Individual projects can ONLY be created within an existing workspace.
|
|
165
|
+
* This enforces proper monorepo structure and prevents scattered individual projects.
|
|
166
|
+
*/
|
|
167
|
+
async function resolveProjectPath(projectName, directory) {
|
|
168
|
+
// Check if we're in a workspace directory
|
|
169
|
+
const isWorkspace = await isWorkspaceRoot(directory);
|
|
170
|
+
if (!isWorkspace) {
|
|
171
|
+
throw new Error(`Individual projects can only be created within a workspace.\n` +
|
|
172
|
+
`Please first create a workspace with: idealyst init my-workspace\n` +
|
|
173
|
+
`Then navigate to the workspace directory and create your project.`);
|
|
174
|
+
}
|
|
175
|
+
// Create project in workspace's packages/ folder
|
|
176
|
+
const packagesDir = path.join(directory, 'packages');
|
|
177
|
+
await fs.ensureDir(packagesDir);
|
|
178
|
+
return {
|
|
179
|
+
projectPath: path.join(packagesDir, projectName),
|
|
180
|
+
workspacePath: `packages/${projectName}`
|
|
181
|
+
};
|
|
182
|
+
}
|
|
136
183
|
async function initializeReactNativeProject(projectName, directory, displayName, skipInstall) {
|
|
137
184
|
const spinner = ora('Initializing React Native project...').start();
|
|
138
185
|
try {
|
|
@@ -206,6 +253,10 @@ async function mergePackageJsonDependencies(templatePath, projectPath) {
|
|
|
206
253
|
'@react-navigation/drawer': '^7.5.3',
|
|
207
254
|
'@react-navigation/native': '^7.1.14',
|
|
208
255
|
'@react-navigation/native-stack': '^7.3.21',
|
|
256
|
+
'@tanstack/react-query': '^5.83.0',
|
|
257
|
+
'@trpc/client': '^11.4.3',
|
|
258
|
+
'@trpc/react-query': '^11.4.3',
|
|
259
|
+
'@trpc/server': '^11.4.3',
|
|
209
260
|
'react-native-edge-to-edge': '^1.6.2',
|
|
210
261
|
'react-native-gesture-handler': '^2.27.1',
|
|
211
262
|
'react-native-nitro-modules': '^0.26.3',
|
|
@@ -259,7 +310,8 @@ async function promptForProjectType() {
|
|
|
259
310
|
choices: [
|
|
260
311
|
{ name: 'React Native App', value: 'native' },
|
|
261
312
|
{ name: 'React Web App', value: 'web' },
|
|
262
|
-
{ name: 'Shared Library', value: 'shared' }
|
|
313
|
+
{ name: 'Shared Library', value: 'shared' },
|
|
314
|
+
{ name: 'API Server (tRPC + Prisma + Zod)', value: 'api' }
|
|
263
315
|
],
|
|
264
316
|
default: 'native'
|
|
265
317
|
}
|
|
@@ -284,6 +336,71 @@ async function promptForAppName(projectName) {
|
|
|
284
336
|
]);
|
|
285
337
|
return appName;
|
|
286
338
|
}
|
|
339
|
+
async function promptForTrpcIntegration() {
|
|
340
|
+
const { withTrpc } = await inquirer.prompt([
|
|
341
|
+
{
|
|
342
|
+
type: 'confirm',
|
|
343
|
+
name: 'withTrpc',
|
|
344
|
+
message: 'Would you like to include tRPC client setup and boilerplate?',
|
|
345
|
+
default: false
|
|
346
|
+
}
|
|
347
|
+
]);
|
|
348
|
+
return withTrpc;
|
|
349
|
+
}
|
|
350
|
+
async function copyTrpcFiles(templatePath, projectPath, data) {
|
|
351
|
+
const spinner = ora('Adding tRPC client utilities...').start();
|
|
352
|
+
try {
|
|
353
|
+
const trpcUtilsSource = path.join(templatePath, 'src', 'utils', 'trpc.ts');
|
|
354
|
+
const trpcUtilsTarget = path.join(projectPath, 'src', 'utils', 'trpc.ts');
|
|
355
|
+
// Ensure utils directory exists
|
|
356
|
+
await fs.ensureDir(path.join(projectPath, 'src', 'utils'));
|
|
357
|
+
// Copy and process the tRPC utils file
|
|
358
|
+
await fs.copy(trpcUtilsSource, trpcUtilsTarget);
|
|
359
|
+
await processTemplateFile(trpcUtilsTarget, data);
|
|
360
|
+
spinner.succeed('tRPC client utilities added');
|
|
361
|
+
}
|
|
362
|
+
catch (error) {
|
|
363
|
+
spinner.fail('Failed to add tRPC client utilities');
|
|
364
|
+
console.warn(chalk.yellow('ā ļø tRPC utilities could not be copied, but the project was created successfully'));
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
async function copyTrpcAppComponent(templatePath, projectPath, data) {
|
|
368
|
+
const spinner = ora('Setting up tRPC App component...').start();
|
|
369
|
+
try {
|
|
370
|
+
const trpcAppSource = path.join(templatePath, 'src', 'App-with-trpc.tsx');
|
|
371
|
+
const appTarget = path.join(projectPath, 'src', 'App.tsx');
|
|
372
|
+
// Copy the tRPC-enabled App component over the default one
|
|
373
|
+
await fs.copy(trpcAppSource, appTarget, { overwrite: true });
|
|
374
|
+
await processTemplateFile(appTarget, data);
|
|
375
|
+
spinner.succeed('tRPC App component configured');
|
|
376
|
+
}
|
|
377
|
+
catch (error) {
|
|
378
|
+
spinner.fail('Failed to configure tRPC App component');
|
|
379
|
+
console.warn(chalk.yellow('ā ļø tRPC App component could not be configured, but the project was created successfully'));
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
async function removeTrpcDependencies(projectPath) {
|
|
383
|
+
try {
|
|
384
|
+
const packageJsonPath = path.join(projectPath, 'package.json');
|
|
385
|
+
const packageJson = await fs.readJSON(packageJsonPath);
|
|
386
|
+
// Remove tRPC-related dependencies
|
|
387
|
+
const trpcDeps = [
|
|
388
|
+
'@tanstack/react-query',
|
|
389
|
+
'@trpc/client',
|
|
390
|
+
'@trpc/react-query',
|
|
391
|
+
'@trpc/server'
|
|
392
|
+
];
|
|
393
|
+
trpcDeps.forEach(dep => {
|
|
394
|
+
if (packageJson.dependencies && packageJson.dependencies[dep]) {
|
|
395
|
+
delete packageJson.dependencies[dep];
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
await fs.writeJSON(packageJsonPath, packageJson, { spaces: 2 });
|
|
399
|
+
}
|
|
400
|
+
catch (error) {
|
|
401
|
+
console.warn(chalk.yellow('ā ļø Could not remove tRPC dependencies from package.json'));
|
|
402
|
+
}
|
|
403
|
+
}
|
|
287
404
|
async function configureAndroidVectorIcons(projectPath) {
|
|
288
405
|
const buildGradlePath = path.join(projectPath, 'android', 'app', 'build.gradle');
|
|
289
406
|
try {
|
|
@@ -323,10 +440,13 @@ var utils = /*#__PURE__*/Object.freeze({
|
|
|
323
440
|
__proto__: null,
|
|
324
441
|
configureAndroidVectorIcons: configureAndroidVectorIcons,
|
|
325
442
|
copyTemplate: copyTemplate,
|
|
443
|
+
copyTrpcAppComponent: copyTrpcAppComponent,
|
|
444
|
+
copyTrpcFiles: copyTrpcFiles,
|
|
326
445
|
createPackageName: createPackageName,
|
|
327
446
|
getTemplateData: getTemplateData,
|
|
328
447
|
initializeReactNativeProject: initializeReactNativeProject,
|
|
329
448
|
installDependencies: installDependencies,
|
|
449
|
+
isWorkspaceRoot: isWorkspaceRoot,
|
|
330
450
|
mergePackageJsonDependencies: mergePackageJsonDependencies,
|
|
331
451
|
overlayIdealystFiles: overlayIdealystFiles,
|
|
332
452
|
processTemplateFile: processTemplateFile,
|
|
@@ -334,34 +454,49 @@ var utils = /*#__PURE__*/Object.freeze({
|
|
|
334
454
|
promptForAppName: promptForAppName,
|
|
335
455
|
promptForProjectName: promptForProjectName,
|
|
336
456
|
promptForProjectType: promptForProjectType,
|
|
457
|
+
promptForTrpcIntegration: promptForTrpcIntegration,
|
|
458
|
+
removeTrpcDependencies: removeTrpcDependencies,
|
|
459
|
+
resolveProjectPath: resolveProjectPath,
|
|
337
460
|
runCommand: runCommand,
|
|
338
461
|
updateWorkspacePackageJson: updateWorkspacePackageJson,
|
|
339
462
|
validateProjectName: validateProjectName
|
|
340
463
|
});
|
|
341
464
|
|
|
342
|
-
const __filename$
|
|
343
|
-
const __dirname$
|
|
465
|
+
const __filename$4 = fileURLToPath(import.meta.url);
|
|
466
|
+
const __dirname$4 = path.dirname(__filename$4);
|
|
344
467
|
async function generateNativeProject(options) {
|
|
345
|
-
const { name, directory, skipInstall, appName } = options;
|
|
468
|
+
const { name, directory, skipInstall, appName, withTrpc } = options;
|
|
346
469
|
if (!validateProjectName(name)) {
|
|
347
470
|
throw new Error(`Invalid project name: ${name}`);
|
|
348
471
|
}
|
|
349
472
|
const displayName = appName || name.split('-').map(word => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(' ');
|
|
350
473
|
console.log(chalk.blue(`š± Creating React Native project: ${name}`));
|
|
351
474
|
console.log(chalk.gray(` App display name: ${displayName}`));
|
|
352
|
-
const projectPath =
|
|
353
|
-
const templatePath = path.join(__dirname$
|
|
475
|
+
const { projectPath, workspacePath } = await resolveProjectPath(name, directory);
|
|
476
|
+
const templatePath = path.join(__dirname$4, '..', 'templates', 'native');
|
|
354
477
|
const templateData = getTemplateData(name, `React Native app built with Idealyst Framework`, displayName);
|
|
355
478
|
try {
|
|
356
479
|
// Step 1: Update workspace configuration FIRST (before React Native CLI)
|
|
357
|
-
await updateWorkspacePackageJson(
|
|
480
|
+
await updateWorkspacePackageJson(workspacePath, directory);
|
|
358
481
|
// Step 2: Initialize React Native project using CLI with --skip-install
|
|
359
|
-
|
|
482
|
+
// Note: For React Native CLI, we need to run it in the parent directory and specify the project name
|
|
483
|
+
const projectDir = path.dirname(projectPath);
|
|
484
|
+
const projectName = path.basename(projectPath);
|
|
485
|
+
await initializeReactNativeProject(projectName, projectDir, displayName, true);
|
|
360
486
|
// Step 3: Overlay Idealyst-specific files
|
|
361
487
|
await overlayIdealystFiles(templatePath, projectPath, templateData);
|
|
362
|
-
// Step 4:
|
|
488
|
+
// Step 4: Handle tRPC setup
|
|
489
|
+
if (withTrpc) {
|
|
490
|
+
await copyTrpcFiles(templatePath, projectPath, templateData);
|
|
491
|
+
await copyTrpcAppComponent(templatePath, projectPath, templateData);
|
|
492
|
+
}
|
|
493
|
+
// Step 5: Configure Android vector icons
|
|
363
494
|
await configureAndroidVectorIcons(projectPath);
|
|
364
|
-
// Step
|
|
495
|
+
// Step 6: Remove tRPC dependencies if not requested (after merge but before install)
|
|
496
|
+
if (!withTrpc) {
|
|
497
|
+
await removeTrpcDependencies(projectPath);
|
|
498
|
+
}
|
|
499
|
+
// Step 7: Install dependencies (including Idealyst packages) after workspace config is updated
|
|
365
500
|
await installDependencies(projectPath, skipInstall);
|
|
366
501
|
console.log(chalk.green('ā
React Native project created successfully!'));
|
|
367
502
|
console.log(chalk.blue('š Project includes:'));
|
|
@@ -374,6 +509,11 @@ async function generateNativeProject(options) {
|
|
|
374
509
|
console.log(chalk.white(' ⢠Metro configuration'));
|
|
375
510
|
console.log(chalk.white(' ⢠Babel configuration'));
|
|
376
511
|
console.log(chalk.white(' ⢠Native platform directories (android/, ios/)'));
|
|
512
|
+
if (withTrpc) {
|
|
513
|
+
console.log(chalk.white(' ⢠tRPC client setup and utilities'));
|
|
514
|
+
console.log(chalk.white(' ⢠React Query integration'));
|
|
515
|
+
console.log(chalk.white(' ⢠Pre-configured tRPC provider'));
|
|
516
|
+
}
|
|
377
517
|
}
|
|
378
518
|
catch (error) {
|
|
379
519
|
console.error(chalk.red('ā Error creating React Native project:'));
|
|
@@ -382,20 +522,29 @@ async function generateNativeProject(options) {
|
|
|
382
522
|
}
|
|
383
523
|
}
|
|
384
524
|
|
|
385
|
-
const __filename$
|
|
386
|
-
const __dirname$
|
|
525
|
+
const __filename$3 = fileURLToPath(import.meta.url);
|
|
526
|
+
const __dirname$3 = path.dirname(__filename$3);
|
|
387
527
|
async function generateWebProject(options) {
|
|
388
|
-
const { name, directory, skipInstall } = options;
|
|
528
|
+
const { name, directory, skipInstall, withTrpc } = options;
|
|
389
529
|
if (!validateProjectName(name)) {
|
|
390
530
|
throw new Error(`Invalid project name: ${name}`);
|
|
391
531
|
}
|
|
392
532
|
console.log(chalk.blue(`š Creating React Web project: ${name}`));
|
|
393
|
-
const projectPath =
|
|
394
|
-
const templatePath = path.join(__dirname$
|
|
533
|
+
const { projectPath, workspacePath } = await resolveProjectPath(name, directory);
|
|
534
|
+
const templatePath = path.join(__dirname$3, '..', 'templates', 'web');
|
|
395
535
|
const templateData = getTemplateData(name, `React web app built with Idealyst Framework`);
|
|
396
536
|
await copyTemplate(templatePath, projectPath, templateData);
|
|
537
|
+
// Handle tRPC setup
|
|
538
|
+
if (withTrpc) {
|
|
539
|
+
await copyTrpcFiles(templatePath, projectPath, templateData);
|
|
540
|
+
await copyTrpcAppComponent(templatePath, projectPath, templateData);
|
|
541
|
+
}
|
|
542
|
+
else {
|
|
543
|
+
// Remove tRPC dependencies if not requested
|
|
544
|
+
await removeTrpcDependencies(projectPath);
|
|
545
|
+
}
|
|
397
546
|
await installDependencies(projectPath, skipInstall);
|
|
398
|
-
await updateWorkspacePackageJson(
|
|
547
|
+
await updateWorkspacePackageJson(workspacePath, directory);
|
|
399
548
|
console.log(chalk.green('ā
React Web project created successfully!'));
|
|
400
549
|
console.log(chalk.blue('š Project includes:'));
|
|
401
550
|
console.log(chalk.white(' ⢠React 19.1'));
|
|
@@ -405,22 +554,27 @@ async function generateWebProject(options) {
|
|
|
405
554
|
console.log(chalk.white(' ⢠Idealyst Theme'));
|
|
406
555
|
console.log(chalk.white(' ⢠TypeScript configuration'));
|
|
407
556
|
console.log(chalk.white(' ⢠React Router'));
|
|
557
|
+
if (withTrpc) {
|
|
558
|
+
console.log(chalk.white(' ⢠tRPC client setup and utilities'));
|
|
559
|
+
console.log(chalk.white(' ⢠React Query integration'));
|
|
560
|
+
console.log(chalk.white(' ⢠Pre-configured tRPC provider'));
|
|
561
|
+
}
|
|
408
562
|
}
|
|
409
563
|
|
|
410
|
-
const __filename$
|
|
411
|
-
const __dirname$
|
|
564
|
+
const __filename$2 = fileURLToPath(import.meta.url);
|
|
565
|
+
const __dirname$2 = path.dirname(__filename$2);
|
|
412
566
|
async function generateSharedLibrary(options) {
|
|
413
567
|
const { name, directory, skipInstall } = options;
|
|
414
568
|
if (!validateProjectName(name)) {
|
|
415
569
|
throw new Error(`Invalid project name: ${name}`);
|
|
416
570
|
}
|
|
417
571
|
console.log(chalk.blue(`š¦ Creating shared library: ${name}`));
|
|
418
|
-
const projectPath =
|
|
419
|
-
const templatePath = path.join(__dirname$
|
|
572
|
+
const { projectPath, workspacePath } = await resolveProjectPath(name, directory);
|
|
573
|
+
const templatePath = path.join(__dirname$2, '..', 'templates', 'shared');
|
|
420
574
|
const templateData = getTemplateData(name, `Shared library built with Idealyst Framework`);
|
|
421
575
|
await copyTemplate(templatePath, projectPath, templateData);
|
|
422
576
|
await installDependencies(projectPath, skipInstall);
|
|
423
|
-
await updateWorkspacePackageJson(
|
|
577
|
+
await updateWorkspacePackageJson(workspacePath, directory);
|
|
424
578
|
console.log(chalk.green('ā
Shared library created successfully!'));
|
|
425
579
|
console.log(chalk.blue('š Project includes:'));
|
|
426
580
|
console.log(chalk.white(' ⢠Cross-platform components'));
|
|
@@ -430,8 +584,8 @@ async function generateSharedLibrary(options) {
|
|
|
430
584
|
console.log(chalk.white(' ⢠React & React Native support'));
|
|
431
585
|
}
|
|
432
586
|
|
|
433
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
434
|
-
const __dirname = path.dirname(__filename);
|
|
587
|
+
const __filename$1 = fileURLToPath(import.meta.url);
|
|
588
|
+
const __dirname$1 = path.dirname(__filename$1);
|
|
435
589
|
async function generateWorkspace(options) {
|
|
436
590
|
const { name, directory, skipInstall } = options;
|
|
437
591
|
if (!validateProjectName(name)) {
|
|
@@ -439,7 +593,7 @@ async function generateWorkspace(options) {
|
|
|
439
593
|
}
|
|
440
594
|
console.log(chalk.blue(`šļø Creating Idealyst workspace: ${name}`));
|
|
441
595
|
const projectPath = path.join(directory, name);
|
|
442
|
-
const templatePath = path.join(__dirname, '..', 'templates', 'workspace');
|
|
596
|
+
const templatePath = path.join(__dirname$1, '..', 'templates', 'workspace');
|
|
443
597
|
const templateData = getTemplateData(name, `Idealyst Framework monorepo workspace`);
|
|
444
598
|
await copyTemplate(templatePath, projectPath, templateData);
|
|
445
599
|
await installDependencies(projectPath, skipInstall);
|
|
@@ -452,6 +606,32 @@ async function generateWorkspace(options) {
|
|
|
452
606
|
console.log(chalk.white(' ⢠Version management scripts'));
|
|
453
607
|
}
|
|
454
608
|
|
|
609
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
610
|
+
const __dirname = path.dirname(__filename);
|
|
611
|
+
async function generateApiProject(options) {
|
|
612
|
+
const { name, directory, skipInstall } = options;
|
|
613
|
+
if (!validateProjectName(name)) {
|
|
614
|
+
throw new Error(`Invalid project name: ${name}`);
|
|
615
|
+
}
|
|
616
|
+
console.log(chalk.blue(`š Creating API project: ${name}`));
|
|
617
|
+
const { projectPath, workspacePath } = await resolveProjectPath(name, directory);
|
|
618
|
+
const templatePath = path.join(__dirname, '..', 'templates', 'api');
|
|
619
|
+
const templateData = getTemplateData(name, `Clean API server template with tRPC, Prisma, and Zod`);
|
|
620
|
+
await copyTemplate(templatePath, projectPath, templateData);
|
|
621
|
+
await installDependencies(projectPath, skipInstall);
|
|
622
|
+
await updateWorkspacePackageJson(workspacePath, directory);
|
|
623
|
+
console.log(chalk.green('ā
API project created successfully!'));
|
|
624
|
+
console.log(chalk.blue('š Project includes:'));
|
|
625
|
+
console.log(chalk.white(' ⢠tRPC for type-safe APIs'));
|
|
626
|
+
console.log(chalk.white(' ⢠Prisma for database management'));
|
|
627
|
+
console.log(chalk.white(' ⢠Zod for schema validation'));
|
|
628
|
+
console.log(chalk.white(' ⢠Express.js server'));
|
|
629
|
+
console.log(chalk.white(' ⢠TypeScript configuration'));
|
|
630
|
+
console.log(chalk.white(' ⢠CORS and middleware setup'));
|
|
631
|
+
console.log(chalk.white(' ⢠Database migration scripts'));
|
|
632
|
+
console.log(chalk.white(' ⢠Clean template ready for your models'));
|
|
633
|
+
}
|
|
634
|
+
|
|
455
635
|
async function generateProject(options) {
|
|
456
636
|
const { type } = options;
|
|
457
637
|
switch (type) {
|
|
@@ -467,6 +647,9 @@ async function generateProject(options) {
|
|
|
467
647
|
case 'workspace':
|
|
468
648
|
await generateWorkspace(options);
|
|
469
649
|
break;
|
|
650
|
+
case 'api':
|
|
651
|
+
await generateApiProject(options);
|
|
652
|
+
break;
|
|
470
653
|
default:
|
|
471
654
|
throw new Error(`Unknown project type: ${type}`);
|
|
472
655
|
}
|
|
@@ -480,9 +663,10 @@ program
|
|
|
480
663
|
program
|
|
481
664
|
.command('create [project-name]')
|
|
482
665
|
.description('Create a new Idealyst project')
|
|
483
|
-
.option('-t, --type <type>', 'Project type: native, web, or
|
|
666
|
+
.option('-t, --type <type>', 'Project type: native, web, shared, or api')
|
|
484
667
|
.option('-d, --directory <directory>', 'Output directory', '.')
|
|
485
668
|
.option('-a, --app-name <app-name>', 'Display name for native apps (e.g., "My Awesome App")')
|
|
669
|
+
.option('--with-trpc', 'Include tRPC boilerplate and setup (for web/native projects)')
|
|
486
670
|
.option('--skip-install', 'Skip installing dependencies')
|
|
487
671
|
.action(async (projectName, options) => {
|
|
488
672
|
try {
|
|
@@ -505,7 +689,7 @@ program
|
|
|
505
689
|
if (!projectType) {
|
|
506
690
|
projectType = await promptForProjectType();
|
|
507
691
|
}
|
|
508
|
-
const validTypes = ['native', 'web', 'shared'];
|
|
692
|
+
const validTypes = ['native', 'web', 'shared', 'api'];
|
|
509
693
|
if (!validTypes.includes(projectType)) {
|
|
510
694
|
console.error(chalk.red(`Invalid project type: ${projectType}`));
|
|
511
695
|
console.error(chalk.yellow(`Valid types are: ${validTypes.join(', ')}`));
|
|
@@ -516,28 +700,41 @@ program
|
|
|
516
700
|
if (projectType === 'native' && !appName) {
|
|
517
701
|
appName = await promptForAppName(projectName);
|
|
518
702
|
}
|
|
703
|
+
// Prompt for tRPC integration if it's a web/native project and flag not provided
|
|
704
|
+
let withTrpc = options.withTrpc;
|
|
705
|
+
if ((projectType === 'web' || projectType === 'native') && withTrpc === undefined) {
|
|
706
|
+
withTrpc = await promptForTrpcIntegration();
|
|
707
|
+
}
|
|
519
708
|
await generateProject({
|
|
520
709
|
name: projectName,
|
|
521
710
|
type: projectType,
|
|
522
711
|
directory: options.directory,
|
|
523
712
|
skipInstall: options.skipInstall || false,
|
|
524
|
-
appName
|
|
713
|
+
appName,
|
|
714
|
+
withTrpc: withTrpc || false
|
|
525
715
|
});
|
|
526
716
|
console.log(chalk.green(`⨠Successfully created ${projectName}!`));
|
|
527
|
-
console.log(chalk.blue(`š Project created in: ${options.directory}/${projectName}`));
|
|
717
|
+
console.log(chalk.blue(`š Project created in: ${options.directory}/packages/${projectName}`));
|
|
528
718
|
if (projectType === 'native') {
|
|
529
719
|
console.log(chalk.yellow('\nš± Next steps for React Native:'));
|
|
530
|
-
console.log(chalk.white(' cd ' + projectName));
|
|
720
|
+
console.log(chalk.white(' cd packages/' + projectName));
|
|
531
721
|
console.log(chalk.white(' yarn android # or yarn ios'));
|
|
532
722
|
}
|
|
533
723
|
else if (projectType === 'web') {
|
|
534
724
|
console.log(chalk.yellow('\nš Next steps for React Web:'));
|
|
535
|
-
console.log(chalk.white(' cd ' + projectName));
|
|
725
|
+
console.log(chalk.white(' cd packages/' + projectName));
|
|
536
726
|
console.log(chalk.white(' yarn dev'));
|
|
537
727
|
}
|
|
728
|
+
else if (projectType === 'api') {
|
|
729
|
+
console.log(chalk.yellow('\nš Next steps for API Server:'));
|
|
730
|
+
console.log(chalk.white(' cd packages/' + projectName));
|
|
731
|
+
console.log(chalk.white(' yarn dev # Start development server'));
|
|
732
|
+
console.log(chalk.white(' yarn db:push # Push database schema'));
|
|
733
|
+
console.log(chalk.white(' yarn db:studio # Open Prisma Studio'));
|
|
734
|
+
}
|
|
538
735
|
else {
|
|
539
736
|
console.log(chalk.yellow('\nš¦ Next steps for Shared Library:'));
|
|
540
|
-
console.log(chalk.white(' cd ' + projectName));
|
|
737
|
+
console.log(chalk.white(' cd packages/' + projectName));
|
|
541
738
|
console.log(chalk.white(' yarn build'));
|
|
542
739
|
}
|
|
543
740
|
}
|