@flowdevcli/flowdev 1.0.1 → 1.0.3

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/package.json CHANGED
@@ -1,12 +1,11 @@
1
1
  {
2
2
  "name": "@flowdevcli/flowdev",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "AI-powered CLI tool",
5
- "main": "bin/flowdev.js",
6
5
  "type": "module",
7
6
  "bin": {
8
- "flowdev": "./bin/flowdev.js",
9
- "fd": "./bin/flowdev.js"
7
+ "flowdev": "bin/flowdev.js",
8
+ "fd": "bin/flowdev.js"
10
9
  },
11
10
  "scripts": {
12
11
  "start": "node bin/flowdev.js",
@@ -44,8 +43,7 @@
44
43
  "eslint": "^8.52.0",
45
44
  "mocha": "^10.2.0"
46
45
  },
47
-
48
46
  "publishConfig": {
49
- "access": "public"
50
- }
51
- }
47
+ "access": "public"
48
+ }
49
+ }
@@ -10,7 +10,6 @@ const pythonCmd = process.platform === 'win32' ? 'python' : 'python3';
10
10
  const npmCmd = process.platform === 'win32' ? 'npm.cmd' : 'npm';
11
11
  const npxCmd = process.platform === 'win32' ? 'npx.cmd' : 'npx';
12
12
 
13
-
14
13
  const PYTHON_REGEX = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
15
14
  const GENERAL_REGEX = /^[a-zA-Z][a-zA-Z0-9-_]*$/;
16
15
 
@@ -36,44 +35,25 @@ export async function generateCommand() {
36
35
  validate: (input, currentAnswers) => {
37
36
  const name = input.trim();
38
37
  if (!name) return 'A name is required.';
39
-
40
- if (/^\d/.test(name)) {
41
- return ' Name cannot start with a number. Please use a letter.';
42
- }
43
-
44
-
38
+ if (/^\d/.test(name)) return 'Name cannot start with a number.';
39
+
45
40
  if (currentAnswers.type === 'django') {
46
- if (!PYTHON_REGEX.test(name)) {
47
- return ' Django projects cannot contain dashes (-) or spaces. Use underscores (_) instead.';
48
- }
49
- }
50
-
51
- else {
52
- if (!GENERAL_REGEX.test(name)) {
53
- return ' Invalid name. Use letters, numbers, dashes (-) or underscores (_).';
54
- }
41
+ if (!PYTHON_REGEX.test(name)) return 'Use underscores (_) for Django projects.';
42
+ } else {
43
+ if (!GENERAL_REGEX.test(name)) return 'Invalid characters used.';
55
44
  }
56
-
57
45
  return true;
58
46
  }
59
47
  }
60
48
  ]);
61
49
 
62
-
63
50
  if (answers.type === 'django') {
64
51
  const djangoSub = await inquirer.prompt([{
65
52
  type: 'input',
66
53
  name: 'appName',
67
54
  message: 'Initial app name:',
68
55
  default: 'core',
69
- validate: (input) => {
70
- const name = input.trim();
71
-
72
- if (!PYTHON_REGEX.test(name)) {
73
- return ' Invalid Python App name. Must start with a letter and contain no dashes.';
74
- }
75
- return true;
76
- }
56
+ validate: (input) => PYTHON_REGEX.test(input) || 'Invalid Python App name.'
77
57
  }]);
78
58
  answers.appName = djangoSub.appName;
79
59
  }
@@ -97,18 +77,15 @@ export async function generateCommand() {
97
77
  }
98
78
 
99
79
  await initGit(projectDir, spinner);
100
-
101
- spinner.succeed(chalk.green(`Project "${answers.projectName}" is ready and configured!`));
80
+ spinner.succeed(chalk.green(`Project "${answers.projectName}" is ready!`));
102
81
  showSuccessTips(answers);
103
82
 
104
83
  } catch (error) {
105
84
  spinner.fail(chalk.red('Generation failed.'));
106
- console.error(chalk.red(`\nDetailed Error: ${error.message}`));
85
+ console.error(chalk.red(`\nError: ${error.message}`));
107
86
  }
108
87
  }
109
88
 
110
-
111
-
112
89
  async function setupVite(dir, name, framework, withTailwind, spinner) {
113
90
  spinner.text = `Scaffolding ${framework} with Vite...`;
114
91
  execSync(`${npmCmd} create vite@latest "${name}" -- --template ${framework}`, { stdio: 'ignore' });
@@ -119,13 +96,17 @@ async function setupVite(dir, name, framework, withTailwind, spinner) {
119
96
  spinner.text = 'Installing core dependencies...';
120
97
  execSync(`${npmCmd} install`, { stdio: 'ignore' });
121
98
 
99
+
122
100
  const folders = ['components', 'services', 'utils', 'hooks', 'assets'];
123
101
  for (const f of folders) await fs.ensureDir(path.join(dir, 'src', f));
124
102
 
125
103
  if (withTailwind) {
126
- spinner.text = 'Installing & Configuring Tailwind CSS (Manual Setup)...';
127
- execSync(`${npmCmd} install -D tailwindcss postcss autoprefixer`, { stdio: 'ignore' });
104
+ spinner.text = 'Configuring Tailwind CSS v3...';
105
+
106
+
107
+ execSync(`${npmCmd} install -D tailwindcss@3 postcss@8 autoprefixer@10`, { stdio: 'ignore' });
128
108
 
109
+
129
110
  const tailwindConfig = `/** @type {import('tailwindcss').Config} */
130
111
  export default {
131
112
  content: [
@@ -139,6 +120,7 @@ export default {
139
120
  }`;
140
121
  await fs.writeFile(path.join(dir, 'tailwind.config.js'), tailwindConfig);
141
122
 
123
+
142
124
  const postcssConfig = `export default {
143
125
  plugins: {
144
126
  tailwindcss: {},
@@ -147,7 +129,18 @@ export default {
147
129
  }`;
148
130
  await fs.writeFile(path.join(dir, 'postcss.config.js'), postcssConfig);
149
131
 
150
- const cssPath = path.join(dir, 'src', 'index.css');
132
+
133
+ const possibleCssFiles = ['index.css', 'style.css', 'App.css'];
134
+ let targetCssFile = 'index.css';
135
+
136
+ for (const file of possibleCssFiles) {
137
+ if (await fs.pathExists(path.join(dir, 'src', file))) {
138
+ targetCssFile = file;
139
+ break;
140
+ }
141
+ }
142
+
143
+ const cssPath = path.join(dir, 'src', targetCssFile);
151
144
  const tailwindDirectives = `@tailwind base;\n@tailwind components;\n@tailwind utilities;\n\n`;
152
145
 
153
146
  let currentCss = "";
@@ -163,35 +156,18 @@ export default {
163
156
  async function setupDjango(dir, data, spinner) {
164
157
  const { projectName, appName } = data;
165
158
  const isWin = process.platform === 'win32';
166
-
167
159
  await fs.ensureDir(dir);
168
160
  const originalDir = process.cwd();
169
161
  process.chdir(dir);
170
-
171
162
  try {
172
- spinner.text = 'Creating virtual environment...';
163
+ spinner.text = 'Setting up Django environment...';
173
164
  execSync(`${pythonCmd} -m venv venv`, { stdio: 'ignore' });
174
-
175
- const venvPython = isWin
176
- ? path.join(dir, 'venv', 'Scripts', 'python.exe')
177
- : path.join(dir, 'venv', 'bin', 'python');
178
-
179
- spinner.text = 'Installing Django...';
165
+ const venvPython = isWin ? path.join(dir, 'venv', 'Scripts', 'python.exe') : path.join(dir, 'venv', 'bin', 'python');
180
166
  execSync(`"${venvPython}" -m pip install django`, { stdio: 'ignore' });
181
-
182
- spinner.text = 'Initializing Django project...';
183
-
184
167
  execSync(`"${venvPython}" -m django startproject config .`, { stdio: 'ignore' });
185
-
186
- spinner.text = `Creating app: ${appName}...`;
187
168
  execSync(`"${venvPython}" manage.py startapp ${appName}`, { stdio: 'ignore' });
188
-
189
- await fs.writeFile(path.join(dir, appName, 'urls.py'),
190
- `from django.urls import path\nfrom . import views\n\nurlpatterns = [ path('', views.index, name='index'), ]`);
191
-
192
- await fs.writeFile(path.join(dir, appName, 'views.py'),
193
- `from django.http import HttpResponse\n\ndef index(request):\n return HttpResponse("<h1>${projectName} is live!</h1>")`);
194
-
169
+ await fs.writeFile(path.join(dir, appName, 'urls.py'), `from django.urls import path\nfrom . import views\n\nurlpatterns = [ path('', views.index, name='index'), ]`);
170
+ await fs.writeFile(path.join(dir, appName, 'views.py'), `from django.http import HttpResponse\n\ndef index(request):\n return HttpResponse("<h1>${projectName} is live!</h1>")`);
195
171
  } finally {
196
172
  process.chdir(originalDir);
197
173
  }
@@ -202,14 +178,13 @@ async function initGit(dir, spinner) {
202
178
  spinner.text = 'Initializing Git...';
203
179
  const ignorePath = path.join(dir, '.gitignore');
204
180
  if (!(await fs.pathExists(ignorePath))) {
205
- const defaultIgnore = 'node_modules\n.env\ndist\nbuild\n__pycache__\n*.log\nvenv\n.venv\n';
206
- await fs.writeFile(ignorePath, defaultIgnore);
181
+ await fs.writeFile(ignorePath, 'node_modules\n.env\ndist\nbuild\n__pycache__\n*.log\nvenv\n');
207
182
  }
208
183
  const originalDir = process.cwd();
209
184
  process.chdir(dir);
210
185
  execSync('git init', { stdio: 'ignore' });
211
186
  execSync('git add .', { stdio: 'ignore' });
212
- execSync('git commit -m "Initial commit by FlowDev 🚀"', { stdio: 'ignore' });
187
+ execSync('git commit -m "Initial commit by FlowDev "', { stdio: 'ignore' });
213
188
  process.chdir(originalDir);
214
189
  } catch (err) {
215
190
  spinner.warn(chalk.yellow('Git initialization skipped.'));
@@ -218,26 +193,27 @@ async function initGit(dir, spinner) {
218
193
 
219
194
  async function setupAngular(dir, name, spinner) {
220
195
  spinner.text = 'Generating Angular Workspace...';
221
-
222
196
  execSync(`${npxCmd} --yes -p @angular/cli ng new "${name}" --defaults --skip-git`, { stdio: 'ignore' });
223
197
  }
224
198
 
225
199
  async function setupExpress(dir, name, spinner) {
226
200
  spinner.text = 'Setting up Express...';
227
201
  await fs.ensureDir(dir);
228
- const pkg = { name, version: '1.0.0', scripts: { start: 'node src/index.js' }, dependencies: { express: '^4.18.2', cors: '^2.8.5' }};
202
+ const pkg = { name, version: '1.0.0', type: 'module', scripts: { start: 'node src/index.js' }, dependencies: { express: '^4.18.2', cors: '^2.8.5' }};
229
203
  await fs.writeJson(path.join(dir, 'package.json'), pkg, { spaces: 2 });
230
204
  await fs.ensureDir(path.join(dir, 'src'));
231
- await fs.writeFile(path.join(dir, 'src', 'index.js'), `const express = require('express');\nconst app = express();\napp.get('/', (req, res) => res.send('API OK'));\napp.listen(3000);`);
205
+ await fs.writeFile(path.join(dir, 'src', 'index.js'), `import express from 'express';\nconst app = express();\napp.get('/', (req, res) => res.send('API OK'));\napp.listen(3000, () => console.log('Server on 3000'));`);
206
+ const originalDir = process.cwd();
232
207
  process.chdir(dir);
233
208
  execSync(`${npmCmd} install`, { stdio: 'ignore' });
209
+ process.chdir(originalDir);
234
210
  }
235
211
 
236
212
  function showSuccessTips(data) {
237
213
  console.log(chalk.yellow('\n Tips :'));
238
214
  console.log(`${chalk.white('*')} cd ${chalk.bold(data.projectName)}`);
239
215
  if (data.type.includes('tailwind')) {
240
- console.log(`${chalk.green('*')} Tailwind & PostCSS are manually configured.`);
216
+ console.log(`${chalk.green('*')} Tailwind CSS v3 successfully configured.`);
241
217
  console.log(`${chalk.white('*')} Run: ${chalk.bold('npm run dev')}`);
242
218
  } else if (data.type === 'django') {
243
219
  console.log(`${chalk.white('*')} Run: ${chalk.bold('python manage.py runserver')}`);