create-nxpress-app 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.
Files changed (2) hide show
  1. package/dist/index.js +100 -76
  2. package/package.json +4 -1
package/dist/index.js CHANGED
@@ -12,27 +12,28 @@ const path_1 = __importDefault(require("path"));
12
12
  const child_process_1 = require("child_process");
13
13
  const program = new commander_1.Command();
14
14
  program
15
- .name('create-nxpress-app')
16
- .description('Scaffold a new Nxpress project')
17
- .argument('[project-directory]', 'Directory for the project')
18
- .option('-e, --engine <engine>', 'Template engine (handlebars, ejs, html)')
19
- .option('--tailwind', 'Include Tailwind CSS support', true)
20
- .option('--app-dir <dir>', 'Directory for application routes', 'app')
21
- .option('--components-dir <dir>', 'Directory for components', 'components')
22
- .option('--public-dir <dir>', 'Directory for static assets', 'public')
23
- .option('--skip-install', 'Skip installing dependencies', false)
15
+ .name("create-nxpress-app")
16
+ .description("Scaffold a new Nxpress project")
17
+ .argument("[project-directory]", "Directory for the project")
18
+ .option("-e, --engine <engine>", "Template engine (handlebars, ejs, html)")
19
+ .option("-p, --port <number>", "Port number")
20
+ .option("--tailwind", "Include Tailwind CSS support", true)
21
+ .option("--app-dir <dir>", "Directory for application routes")
22
+ .option("--components-dir <dir>", "Directory for components")
23
+ .option("--public-dir <dir>", "Directory for static assets")
24
+ .option("--skip-install", "Skip installing dependencies", false)
24
25
  .action(async (projectDirArg, options) => {
25
26
  console.log();
26
- (0, prompts_1.intro)(chalk_1.default.bgCyan.black(' create-nxpress-app '));
27
+ (0, prompts_1.intro)(chalk_1.default.bgCyan.black(" Create Nxpress App "));
27
28
  let projectDir = projectDirArg;
28
29
  if (!projectDir) {
29
30
  const res = await (0, prompts_1.text)({
30
- message: 'Where would you like to create your project?',
31
- placeholder: 'my-nxpress-app',
32
- defaultValue: 'my-nxpress-app',
31
+ message: "Where would you like to create your project?",
32
+ placeholder: "my-nxpress-app",
33
+ defaultValue: "my-nxpress-app",
33
34
  });
34
35
  if ((0, prompts_1.isCancel)(res)) {
35
- (0, prompts_1.cancel)('Operation cancelled.');
36
+ (0, prompts_1.cancel)("Operation cancelled.");
36
37
  process.exit(0);
37
38
  }
38
39
  projectDir = res;
@@ -44,66 +45,89 @@ program
44
45
  initialValue: false,
45
46
  });
46
47
  if ((0, prompts_1.isCancel)(overwrite) || !overwrite) {
47
- (0, prompts_1.cancel)('Operation cancelled.');
48
+ (0, prompts_1.cancel)("Operation cancelled.");
48
49
  process.exit(0);
49
50
  }
50
51
  }
51
52
  let engine = options.engine;
52
- if (!engine || !['handlebars', 'ejs', 'html'].includes(engine)) {
53
+ if (!engine || !["handlebars", "ejs", "html"].includes(engine)) {
53
54
  const selectedEngine = await (0, prompts_1.select)({
54
- message: 'Which template engine do you want to use?',
55
+ message: "Which template engine do you want to use?",
55
56
  options: [
56
- { value: 'handlebars', label: 'Handlebars (Recommended)', hint: 'Clean syntax & partials' },
57
- { value: 'ejs', label: 'EJS', hint: 'Embedded JavaScript templates' },
58
- { value: 'html', label: 'HTML', hint: 'Plain HTML templates' },
57
+ {
58
+ value: "handlebars",
59
+ label: "Handlebars (Recommended)",
60
+ hint: "Clean syntax & partials",
61
+ },
62
+ { value: "ejs", label: "EJS", hint: "Embedded JavaScript templates" },
63
+ { value: "html", label: "HTML", hint: "Plain HTML templates" },
59
64
  ],
60
65
  });
61
66
  if ((0, prompts_1.isCancel)(selectedEngine)) {
62
- (0, prompts_1.cancel)('Operation cancelled.');
67
+ (0, prompts_1.cancel)("Operation cancelled.");
63
68
  process.exit(0);
64
69
  }
65
70
  engine = selectedEngine;
66
71
  }
72
+ let port = options.port ? parseInt(options.port, 10) : 3000;
73
+ if (process.stdin.isTTY && !options.port) {
74
+ const portRes = await (0, prompts_1.text)({
75
+ message: "Port number:",
76
+ placeholder: "3000",
77
+ defaultValue: "3000",
78
+ validate: (val) => !!val && (isNaN(Number(val)) || Number(val) <= 0)
79
+ ? "Port must be a valid positive number"
80
+ : undefined,
81
+ });
82
+ if ((0, prompts_1.isCancel)(portRes)) {
83
+ (0, prompts_1.cancel)("Operation cancelled.");
84
+ process.exit(0);
85
+ }
86
+ port = parseInt(portRes, 10);
87
+ }
67
88
  let appDirName = options.appDir;
68
89
  let componentsDirName = options.componentsDir;
69
90
  let publicDirName = options.publicDir;
70
- if (process.stdin.isTTY && !options.appDir && !options.componentsDir && !options.publicDir) {
91
+ if (process.stdin.isTTY &&
92
+ !options.appDir &&
93
+ !options.componentsDir &&
94
+ !options.publicDir) {
71
95
  const customizeDirs = await (0, prompts_1.confirm)({
72
- message: 'Do you want to customize directory names?',
96
+ message: "Do you want to customize directory names?",
73
97
  initialValue: false,
74
98
  });
75
99
  if ((0, prompts_1.isCancel)(customizeDirs)) {
76
- (0, prompts_1.cancel)('Operation cancelled.');
100
+ (0, prompts_1.cancel)("Operation cancelled.");
77
101
  process.exit(0);
78
102
  }
79
103
  if (customizeDirs) {
80
104
  const appRes = await (0, prompts_1.text)({
81
- message: 'Routes directory name:',
82
- placeholder: 'app',
83
- defaultValue: 'app',
105
+ message: "Routes directory name:",
106
+ placeholder: "app",
107
+ defaultValue: "app",
84
108
  });
85
109
  if ((0, prompts_1.isCancel)(appRes)) {
86
- (0, prompts_1.cancel)('Operation cancelled.');
110
+ (0, prompts_1.cancel)("Operation cancelled.");
87
111
  process.exit(0);
88
112
  }
89
113
  appDirName = appRes;
90
114
  const compRes = await (0, prompts_1.text)({
91
- message: 'Components directory name:',
92
- placeholder: 'components',
93
- defaultValue: 'components',
115
+ message: "Components directory name:",
116
+ placeholder: "components",
117
+ defaultValue: "components",
94
118
  });
95
119
  if ((0, prompts_1.isCancel)(compRes)) {
96
- (0, prompts_1.cancel)('Operation cancelled.');
120
+ (0, prompts_1.cancel)("Operation cancelled.");
97
121
  process.exit(0);
98
122
  }
99
123
  componentsDirName = compRes;
100
124
  const pubRes = await (0, prompts_1.text)({
101
- message: 'Public directory name:',
102
- placeholder: 'public',
103
- defaultValue: 'public',
125
+ message: "Public directory name:",
126
+ placeholder: "public",
127
+ defaultValue: "public",
104
128
  });
105
129
  if ((0, prompts_1.isCancel)(pubRes)) {
106
- (0, prompts_1.cancel)('Operation cancelled.');
130
+ (0, prompts_1.cancel)("Operation cancelled.");
107
131
  process.exit(0);
108
132
  }
109
133
  publicDirName = pubRes;
@@ -112,17 +136,17 @@ program
112
136
  let shouldInstall = !options.skipInstall;
113
137
  if (!options.skipInstall && process.stdin.isTTY) {
114
138
  const res = await (0, prompts_1.confirm)({
115
- message: 'Install dependencies using pnpm?',
139
+ message: "Install dependencies using pnpm?",
116
140
  initialValue: true,
117
141
  });
118
142
  if ((0, prompts_1.isCancel)(res)) {
119
- (0, prompts_1.cancel)('Operation cancelled.');
143
+ (0, prompts_1.cancel)("Operation cancelled.");
120
144
  process.exit(0);
121
145
  }
122
146
  shouldInstall = res;
123
147
  }
124
148
  const s = (0, prompts_1.spinner)();
125
- s.start('Scaffolding project...');
149
+ s.start("Scaffolding project...");
126
150
  fs_extra_1.default.ensureDirSync(targetPath);
127
151
  // Create app structure with chosen directories
128
152
  const appDir = path_1.default.join(targetPath, appDirName);
@@ -131,9 +155,9 @@ program
131
155
  fs_extra_1.default.ensureDirSync(appDir);
132
156
  fs_extra_1.default.ensureDirSync(componentsDir);
133
157
  fs_extra_1.default.ensureDirSync(publicDir);
134
- const ext = engine === 'handlebars' ? 'hbs' : engine;
158
+ const ext = engine === "handlebars" ? "hbs" : engine;
135
159
  // Root layout
136
- const layoutContent = engine === 'handlebars'
160
+ const layoutContent = engine === "handlebars"
137
161
  ? `<!DOCTYPE html>
138
162
  <html lang="en">
139
163
  <head>
@@ -146,7 +170,7 @@ program
146
170
  {{{body}}}
147
171
  </body>
148
172
  </html>`
149
- : engine === 'ejs'
173
+ : engine === "ejs"
150
174
  ? `<!DOCTYPE html>
151
175
  <html lang="en">
152
176
  <head>
@@ -173,7 +197,7 @@ program
173
197
  </html>`;
174
198
  fs_extra_1.default.writeFileSync(path_1.default.join(appDir, `layout.${ext}`), layoutContent);
175
199
  // Index page
176
- const indexPageContent = engine === 'handlebars'
200
+ const indexPageContent = engine === "handlebars"
177
201
  ? `<div class="max-w-4xl mx-auto px-4 py-16 text-center">
178
202
  <h1 class="text-5xl font-bold mb-4 bg-gradient-to-r from-blue-400 to-indigo-500 bg-clip-text text-transparent">
179
203
  Welcome to {{title}}
@@ -183,7 +207,7 @@ program
183
207
  <p class="text-sm font-mono text-cyan-400">Edit <span class="text-amber-300">${appDirName}/index.${ext}</span> to get started.</p>
184
208
  </div>
185
209
  </div>`
186
- : engine === 'ejs'
210
+ : engine === "ejs"
187
211
  ? `<div class="max-w-4xl mx-auto px-4 py-16 text-center">
188
212
  <h1 class="text-5xl font-bold mb-4 bg-gradient-to-r from-blue-400 to-indigo-500 bg-clip-text text-transparent">
189
213
  Welcome to <%= title %>
@@ -210,90 +234,90 @@ export async function props(req: Request, res: Response) {
210
234
  };
211
235
  }
212
236
  `;
213
- fs_extra_1.default.writeFileSync(path_1.default.join(appDir, 'index.ts'), indexTsContent);
237
+ fs_extra_1.default.writeFileSync(path_1.default.join(appDir, "index.ts"), indexTsContent);
214
238
  // App CSS for Tailwind v4
215
- fs_extra_1.default.writeFileSync(path_1.default.join(targetPath, 'app.css'), `@import "tailwindcss";\n`);
239
+ fs_extra_1.default.writeFileSync(path_1.default.join(targetPath, "app.css"), `@import "tailwindcss";\n`);
216
240
  // Server file
217
241
  const serverTsContent = `import { nxpress } from '@nxpress/core';
218
242
 
219
243
  const app = nxpress({
220
- engine: '${engine === 'handlebars' ? 'hbs' : engine}',
244
+ engine: '${engine === "handlebars" ? "hbs" : engine}',
221
245
  });
222
246
 
223
- const PORT = process.env.PORT || 3000;
247
+ const PORT = process.env.PORT || ${port};
224
248
  app.listen(PORT, () => {
225
249
  console.log(\`Nxpress server running on http://localhost:\${PORT}\`);
226
250
  });
227
251
  `;
228
- fs_extra_1.default.writeFileSync(path_1.default.join(targetPath, 'server.ts'), serverTsContent);
229
- const pkgVersion = '1.0.1';
252
+ fs_extra_1.default.writeFileSync(path_1.default.join(targetPath, "server.ts"), serverTsContent);
253
+ const pkgVersion = "1.0.1";
230
254
  // nxpress.config.json
231
255
  const nxConfig = {
232
256
  $schema: `https://unpkg.com/@nxpress/core@${pkgVersion}/schema.json`,
233
- port: 3000,
234
- engine: engine === 'handlebars' ? 'hbs' : engine,
257
+ port,
258
+ engine: engine === "handlebars" ? "hbs" : engine,
235
259
  appDir: appDirName,
236
260
  componentsDir: componentsDirName,
237
261
  publicDir: publicDirName,
238
262
  };
239
- fs_extra_1.default.writeFileSync(path_1.default.join(targetPath, 'nxpress.config.json'), JSON.stringify(nxConfig, null, 2));
263
+ fs_extra_1.default.writeFileSync(path_1.default.join(targetPath, "nxpress.config.json"), JSON.stringify(nxConfig, null, 2));
240
264
  // package.json for target project
241
265
  const projectPkgJson = {
242
266
  name: path_1.default.basename(targetPath),
243
- version: '0.1.0',
267
+ version: "0.1.0",
244
268
  private: true,
245
269
  scripts: {
246
- dev: 'nxpress dev',
247
- build: 'tsc',
248
- start: 'nxpress start',
270
+ dev: "nxpress dev",
271
+ build: "tsc",
272
+ start: "nxpress start",
249
273
  },
250
274
  dependencies: {
251
- '@nxpress/core': `^${pkgVersion}`,
252
- ...(engine === 'handlebars' ? { hbs: '^4.2.0' } : {}),
253
- ...(engine === 'ejs' ? { ejs: '^3.1.10' } : {}),
275
+ "@nxpress/core": `^${pkgVersion}`,
276
+ ...(engine === "handlebars" ? { hbs: "^4.2.0" } : {}),
277
+ ...(engine === "ejs" ? { ejs: "^3.1.10" } : {}),
254
278
  },
255
279
  devDependencies: {
256
- typescript: '^5.3.3',
257
- '@types/node': '^20.11.24',
258
- '@types/express': '^4.17.21',
280
+ typescript: "^5.3.3",
281
+ "@types/node": "^20.11.24",
282
+ "@types/express": "^4.17.21",
259
283
  },
260
284
  };
261
- fs_extra_1.default.writeFileSync(path_1.default.join(targetPath, 'package.json'), JSON.stringify(projectPkgJson, null, 2));
285
+ fs_extra_1.default.writeFileSync(path_1.default.join(targetPath, "package.json"), JSON.stringify(projectPkgJson, null, 2));
262
286
  // tsconfig.json for target project
263
287
  const projectTsConfig = {
264
288
  compilerOptions: {
265
- target: 'ES2022',
266
- module: 'CommonJS',
267
- moduleResolution: 'node',
289
+ target: "ES2022",
290
+ module: "CommonJS",
291
+ moduleResolution: "node",
268
292
  strict: true,
269
293
  esModuleInterop: true,
270
294
  skipLibCheck: true,
271
295
  },
272
- include: ['**/*'],
296
+ include: ["**/*"],
273
297
  };
274
- fs_extra_1.default.writeFileSync(path_1.default.join(targetPath, 'tsconfig.json'), JSON.stringify(projectTsConfig, null, 2));
298
+ fs_extra_1.default.writeFileSync(path_1.default.join(targetPath, "tsconfig.json"), JSON.stringify(projectTsConfig, null, 2));
275
299
  // .gitignore
276
300
  const gitignoreContent = `node_modules
277
301
  dist
278
302
  .env
279
303
  *.log
280
304
  `;
281
- fs_extra_1.default.writeFileSync(path_1.default.join(targetPath, '.gitignore'), gitignoreContent);
282
- s.stop('Project structure created successfully.');
305
+ fs_extra_1.default.writeFileSync(path_1.default.join(targetPath, ".gitignore"), gitignoreContent);
306
+ s.stop("Project structure created successfully.");
283
307
  if (shouldInstall) {
284
308
  const instSpinner = (0, prompts_1.spinner)();
285
- instSpinner.start('Installing dependencies with pnpm...');
309
+ instSpinner.start("Installing dependencies with pnpm...");
286
310
  try {
287
- (0, child_process_1.execSync)('pnpm install', { cwd: targetPath, stdio: 'ignore' });
288
- instSpinner.stop('Dependencies installed successfully.');
311
+ (0, child_process_1.execSync)("pnpm install", { cwd: targetPath, stdio: "ignore" });
312
+ instSpinner.stop("Dependencies installed successfully.");
289
313
  }
290
314
  catch (err) {
291
- instSpinner.stop('Failed to install dependencies automatically.');
315
+ instSpinner.stop("Failed to install dependencies automatically.");
292
316
  }
293
317
  }
294
318
  (0, prompts_1.outro)(`Project created in ${chalk_1.default.cyan(projectDir)}!\n\n` +
295
319
  `Next steps:\n` +
296
320
  ` ${chalk_1.default.cyan(`cd ${projectDir}`)}\n` +
297
- ` ${chalk_1.default.cyan('pnpm dev')}`);
321
+ ` ${chalk_1.default.cyan("pnpm dev")}`);
298
322
  });
299
323
  program.parse(process.argv);
package/package.json CHANGED
@@ -1,11 +1,14 @@
1
1
  {
2
2
  "name": "create-nxpress-app",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "CLI tool to create Nxpress applications",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
7
7
  "create-nxpress-app": "./dist/index.js"
8
8
  },
9
+ "repository": {
10
+ "url": "https://github.com/D3R50N/create-nxpress-app.git"
11
+ },
9
12
  "files": [
10
13
  "dist",
11
14
  "templates"