create-what 0.13.5 → 0.13.6

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/index.js +52 -6
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -7,21 +7,46 @@
7
7
  // npx create-what my-app --yes (skip prompts, use defaults)
8
8
 
9
9
  import { mkdirSync, writeFileSync, existsSync, readFileSync } from 'node:fs';
10
- import { basename, resolve } from 'node:path';
10
+ import { basename, isAbsolute, resolve } from 'node:path';
11
11
  import { createInterface } from 'node:readline';
12
12
 
13
13
  // ---------------------------------------------------------------------------
14
14
  // CLI arguments
15
15
  // ---------------------------------------------------------------------------
16
16
  const args = process.argv.slice(2);
17
- const positional = args.filter(a => !a.startsWith('-'));
17
+ const positional = [];
18
+ for (let i = 0; i < args.length; i += 1) {
19
+ const arg = args[i];
20
+ if (arg === '--template') {
21
+ i += 1;
22
+ continue;
23
+ }
24
+ if (!arg.startsWith('-')) positional.push(arg);
25
+ }
18
26
  const flags = new Set(args.filter(a => a.startsWith('-')));
19
27
  const skipPrompts = flags.has('--yes') || flags.has('-y');
20
28
  const showHelp = flags.has('--help') || flags.has('-h');
21
29
  let templateFlag = flags.has('--fullstack') ? 'fullstack' : null;
22
- for (const f of flags) { const m = f.match(/^--template=(.+)$/); if (m) templateFlag = m[1]; }
30
+ for (const f of flags) { const m = f.match(/^--template=(.*)$/); if (m) templateFlag = m[1].trim(); }
31
+ const templateArgIndex = args.findIndex((a) => a === '--template');
32
+ if (templateArgIndex !== -1) {
33
+ const value = args[templateArgIndex + 1];
34
+ templateFlag = value && !value.startsWith('-') ? value.trim() : '';
35
+ }
23
36
  const packageVersion = JSON.parse(readFileSync(new URL('./package.json', import.meta.url), 'utf8')).version;
24
37
  const whatVersionRange = `^${packageVersion}`;
38
+ const validTemplates = new Set(['spa', 'fullstack']);
39
+
40
+ function shellQuotePath(value) {
41
+ if (/^[A-Za-z0-9_./:@%+=,-]+$/.test(value)) return value;
42
+ return `'${value.replace(/'/g, `'\\''`)}'`;
43
+ }
44
+
45
+ function formatCdTarget(inputPath, absoluteRoot) {
46
+ let target = inputPath && !isAbsolute(inputPath) ? inputPath : absoluteRoot;
47
+ if (!isAbsolute(target) && target.startsWith('-')) target = `./${target}`;
48
+ return shellQuotePath(target);
49
+ }
25
50
 
26
51
  if (showHelp) {
27
52
  console.log(`
@@ -40,6 +65,15 @@ if (showHelp) {
40
65
  process.exit(0);
41
66
  }
42
67
 
68
+ if (templateFlag && !validTemplates.has(templateFlag)) {
69
+ console.error(`\nError: unknown template "${templateFlag}". Expected "spa" or "fullstack".`);
70
+ process.exit(1);
71
+ }
72
+ if (templateFlag === '') {
73
+ console.error('\nError: --template requires a value: "spa" or "fullstack".');
74
+ process.exit(1);
75
+ }
76
+
43
77
  // ---------------------------------------------------------------------------
44
78
  // Prompt helpers (zero-dependency, uses Node readline)
45
79
  // ---------------------------------------------------------------------------
@@ -1528,14 +1562,26 @@ function resolveStaticFile(pathname) {
1528
1562
  return file;
1529
1563
  }
1530
1564
 
1565
+ function requestPathname(reqUrl) {
1566
+ try {
1567
+ return decodeURIComponent(new URL(reqUrl || '/', 'http://localhost').pathname);
1568
+ } catch {
1569
+ return null;
1570
+ }
1571
+ }
1572
+
1531
1573
  // --- Start (node server.js / npm run dev), not when imported by tests ---
1532
1574
 
1533
- if (import.meta.url === \`file://\${process.argv[1]}\`) {
1575
+ if (process.argv[1] && fileURLToPath(import.meta.url) === resolve(process.argv[1])) {
1534
1576
  const app = toNodeListener(createHandler());
1535
1577
 
1536
1578
  const server = http.createServer((req, res) => {
1537
1579
  if (req.method === 'GET' || req.method === 'HEAD') {
1538
- const pathname = decodeURIComponent(new URL(req.url, 'http://localhost').pathname);
1580
+ const pathname = requestPathname(req.url);
1581
+ if (!pathname) {
1582
+ res.writeHead(400, { 'content-type': 'text/plain; charset=utf-8' });
1583
+ return res.end('Bad Request');
1584
+ }
1539
1585
  const file = resolveStaticFile(pathname);
1540
1586
  if (file) {
1541
1587
  res.writeHead(200, { 'content-type': MIME[extname(file)] || 'application/octet-stream' });
@@ -1952,7 +1998,7 @@ export default [
1952
1998
  }
1953
1999
 
1954
2000
  console.log('\nNext steps:');
1955
- console.log(` cd ${root}`);
2001
+ console.log(` cd ${formatCdTarget(projectName, root)}`);
1956
2002
  console.log(' npm install');
1957
2003
  if (options.template === 'fullstack') {
1958
2004
  console.log(' npm run dev # SSR + ISR server → http://localhost:3000\n');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-what",
3
- "version": "0.13.5",
3
+ "version": "0.13.6",
4
4
  "description": "Scaffold a new What Framework project",
5
5
  "type": "module",
6
6
  "bin": {