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.
- package/index.js +52 -6
- 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 =
|
|
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=(
|
|
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 ===
|
|
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 =
|
|
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');
|