kigumi 0.4.2 → 0.4.4
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/dist/chunk-FG4CIVPT.js +52 -0
- package/dist/chunk-IRCCX2A2.js +72 -0
- package/dist/index.js +113 -0
- package/dist/path-aliases-3OJ2RKTE.js +95 -0
- package/dist/path-aliases-44XMTAAA.js +89 -0
- package/dist/path-aliases-CNBMGBKE.js +98 -0
- package/dist/path-aliases-L6USUZ4R.js +91 -0
- package/dist/path-aliases-NX2TDEHO.js +92 -0
- package/dist/path-aliases-ZRNAAXX2.js +94 -0
- package/dist/project-config-3XEQHIUM.js +115 -0
- package/dist/project-config-YLUSQM7U.js +108 -0
- package/dist/templates/react/KIGUMI_SETUP.md.hbs +52 -0
- package/dist/tier-2ZEZT6E3.js +12 -0
- package/dist/tier-GFXZQZUI.js +12 -0
- package/package.json +1 -1
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// src/utils/tier.ts
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
import path from "path";
|
|
4
|
+
async function detectTier(cwd) {
|
|
5
|
+
const envPath = path.join(cwd, ".env");
|
|
6
|
+
if (!await fs.pathExists(envPath)) {
|
|
7
|
+
return "free";
|
|
8
|
+
}
|
|
9
|
+
const envContent = await fs.readFile(envPath, "utf-8");
|
|
10
|
+
const tokenMatch = envContent.match(
|
|
11
|
+
/^\s*WEBAWESOME_NPM_TOKEN\s*=\s*(.+?)\s*$/m
|
|
12
|
+
);
|
|
13
|
+
if (tokenMatch && tokenMatch[1] && tokenMatch[1].length >= 10) {
|
|
14
|
+
return "pro";
|
|
15
|
+
}
|
|
16
|
+
return "free";
|
|
17
|
+
}
|
|
18
|
+
function detectTierSync(cwd) {
|
|
19
|
+
const envPath = path.join(cwd, ".env");
|
|
20
|
+
if (!fs.existsSync(envPath)) {
|
|
21
|
+
return "free";
|
|
22
|
+
}
|
|
23
|
+
const envContent = fs.readFileSync(envPath, "utf-8");
|
|
24
|
+
const tokenMatch = envContent.match(
|
|
25
|
+
/^\s*WEBAWESOME_NPM_TOKEN\s*=\s*(.+?)\s*$/m
|
|
26
|
+
);
|
|
27
|
+
if (tokenMatch && tokenMatch[1] && tokenMatch[1].length >= 10) {
|
|
28
|
+
return "pro";
|
|
29
|
+
}
|
|
30
|
+
return "free";
|
|
31
|
+
}
|
|
32
|
+
async function getProToken(cwd) {
|
|
33
|
+
const envPath = path.join(cwd, ".env");
|
|
34
|
+
if (!await fs.pathExists(envPath)) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
const envContent = await fs.readFile(envPath, "utf-8");
|
|
38
|
+
const tokenMatch = envContent.match(
|
|
39
|
+
/^\s*WEBAWESOME_NPM_TOKEN\s*=\s*(.+?)\s*$/m
|
|
40
|
+
);
|
|
41
|
+
return tokenMatch && tokenMatch[1] ? tokenMatch[1].trim() : null;
|
|
42
|
+
}
|
|
43
|
+
function getWebAwesomePackage(tier) {
|
|
44
|
+
return tier === "pro" ? "@awesome.me/webawesome-pro" : "@awesome.me/webawesome";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export {
|
|
48
|
+
detectTier,
|
|
49
|
+
detectTierSync,
|
|
50
|
+
getProToken,
|
|
51
|
+
getWebAwesomePackage
|
|
52
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// src/utils/tier.ts
|
|
2
|
+
import fs from "fs-extra";
|
|
3
|
+
import path from "path";
|
|
4
|
+
|
|
5
|
+
// src/constants.ts
|
|
6
|
+
var WEB_AWESOME_FREE_PACKAGE = "@awesome.me/webawesome";
|
|
7
|
+
var WEB_AWESOME_PRO_PACKAGE = "@awesome.me/webawesome-pro";
|
|
8
|
+
var WEB_AWESOME_SCOPE = "@awesome.me";
|
|
9
|
+
var ENV_TOKEN_KEY = "WEBAWESOME_NPM_TOKEN";
|
|
10
|
+
var MIN_TOKEN_LENGTH = 10;
|
|
11
|
+
var ENV_FILE_NAME = ".env";
|
|
12
|
+
var NPM_PUBLIC_REGISTRY = "https://registry.npmjs.org/";
|
|
13
|
+
var NPM_PRO_REGISTRY = "https://npm.cloudsmith.io/fortawesome/webawesome-pro";
|
|
14
|
+
var FREE_PACKAGE_REGEX = /@awesome\.me\/webawesome(?!-pro)/g;
|
|
15
|
+
var PRO_PACKAGE_REGEX = /@awesome\.me\/webawesome-pro/g;
|
|
16
|
+
var ENV_TOKEN_REGEX = /^\s*WEBAWESOME_NPM_TOKEN\s*=\s*(.+?)\s*$/m;
|
|
17
|
+
|
|
18
|
+
// src/utils/tier.ts
|
|
19
|
+
async function detectTier(cwd) {
|
|
20
|
+
const envPath = path.join(cwd, ENV_FILE_NAME);
|
|
21
|
+
if (!await fs.pathExists(envPath)) {
|
|
22
|
+
return "free";
|
|
23
|
+
}
|
|
24
|
+
const envContent = await fs.readFile(envPath, "utf-8");
|
|
25
|
+
const tokenMatch = envContent.match(ENV_TOKEN_REGEX);
|
|
26
|
+
if (tokenMatch && tokenMatch[1] && tokenMatch[1].length >= MIN_TOKEN_LENGTH) {
|
|
27
|
+
return "pro";
|
|
28
|
+
}
|
|
29
|
+
return "free";
|
|
30
|
+
}
|
|
31
|
+
function detectTierSync(cwd) {
|
|
32
|
+
const envPath = path.join(cwd, ENV_FILE_NAME);
|
|
33
|
+
if (!fs.existsSync(envPath)) {
|
|
34
|
+
return "free";
|
|
35
|
+
}
|
|
36
|
+
const envContent = fs.readFileSync(envPath, "utf-8");
|
|
37
|
+
const tokenMatch = envContent.match(ENV_TOKEN_REGEX);
|
|
38
|
+
if (tokenMatch && tokenMatch[1] && tokenMatch[1].length >= MIN_TOKEN_LENGTH) {
|
|
39
|
+
return "pro";
|
|
40
|
+
}
|
|
41
|
+
return "free";
|
|
42
|
+
}
|
|
43
|
+
async function getProToken(cwd) {
|
|
44
|
+
const envPath = path.join(cwd, ENV_FILE_NAME);
|
|
45
|
+
if (!await fs.pathExists(envPath)) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
const envContent = await fs.readFile(envPath, "utf-8");
|
|
49
|
+
const tokenMatch = envContent.match(ENV_TOKEN_REGEX);
|
|
50
|
+
return tokenMatch && tokenMatch[1] ? tokenMatch[1].trim() : null;
|
|
51
|
+
}
|
|
52
|
+
function getWebAwesomePackage(tier) {
|
|
53
|
+
return tier === "pro" ? WEB_AWESOME_PRO_PACKAGE : WEB_AWESOME_FREE_PACKAGE;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export {
|
|
57
|
+
WEB_AWESOME_FREE_PACKAGE,
|
|
58
|
+
WEB_AWESOME_PRO_PACKAGE,
|
|
59
|
+
WEB_AWESOME_SCOPE,
|
|
60
|
+
ENV_TOKEN_KEY,
|
|
61
|
+
MIN_TOKEN_LENGTH,
|
|
62
|
+
ENV_FILE_NAME,
|
|
63
|
+
NPM_PUBLIC_REGISTRY,
|
|
64
|
+
NPM_PRO_REGISTRY,
|
|
65
|
+
FREE_PACKAGE_REGEX,
|
|
66
|
+
PRO_PACKAGE_REGEX,
|
|
67
|
+
ENV_TOKEN_REGEX,
|
|
68
|
+
detectTier,
|
|
69
|
+
detectTierSync,
|
|
70
|
+
getProToken,
|
|
71
|
+
getWebAwesomePackage
|
|
72
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -1371,8 +1371,85 @@ async function buildConfigInteractive(options, projectInfo, cwd, output, existin
|
|
|
1371
1371
|
import { execa } from "execa";
|
|
1372
1372
|
import fs5 from "fs-extra";
|
|
1373
1373
|
import path4 from "path";
|
|
1374
|
+
async function checkLockfileCompatibility(cwd, packageManager) {
|
|
1375
|
+
const lockfiles = {
|
|
1376
|
+
npm: "package-lock.json",
|
|
1377
|
+
pnpm: "pnpm-lock.yaml",
|
|
1378
|
+
yarn: "yarn.lock"
|
|
1379
|
+
};
|
|
1380
|
+
const lockfileName = lockfiles[packageManager];
|
|
1381
|
+
if (!lockfileName) {
|
|
1382
|
+
return { compatible: true, lockfilePath: null };
|
|
1383
|
+
}
|
|
1384
|
+
const lockfilePath = path4.join(cwd, lockfileName);
|
|
1385
|
+
if (!await fs5.pathExists(lockfilePath)) {
|
|
1386
|
+
return { compatible: true, lockfilePath: null };
|
|
1387
|
+
}
|
|
1388
|
+
try {
|
|
1389
|
+
const result = await execa(
|
|
1390
|
+
packageManager,
|
|
1391
|
+
["install", "--frozen-lockfile"],
|
|
1392
|
+
{ cwd, reject: false, timeout: 5e3, stdio: "pipe" }
|
|
1393
|
+
);
|
|
1394
|
+
const incompatiblePatterns = [
|
|
1395
|
+
/not compatible with current/i,
|
|
1396
|
+
/ignoring broken lockfile/i,
|
|
1397
|
+
/lockfile .* version/i
|
|
1398
|
+
];
|
|
1399
|
+
const output = (result.stderr || "") + (result.stdout || "");
|
|
1400
|
+
const hasIncompatibility = incompatiblePatterns.some(
|
|
1401
|
+
(pattern) => pattern.test(output)
|
|
1402
|
+
);
|
|
1403
|
+
return {
|
|
1404
|
+
compatible: !hasIncompatibility,
|
|
1405
|
+
lockfilePath: hasIncompatibility ? lockfilePath : null
|
|
1406
|
+
};
|
|
1407
|
+
} catch {
|
|
1408
|
+
return { compatible: true, lockfilePath: null };
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
function createLockfileErrorMessage(packageManager, lockfilePath) {
|
|
1412
|
+
const commands = {
|
|
1413
|
+
npm: "rm package-lock.json && npm install",
|
|
1414
|
+
pnpm: "rm pnpm-lock.yaml && pnpm install",
|
|
1415
|
+
yarn: "rm yarn.lock && yarn install"
|
|
1416
|
+
};
|
|
1417
|
+
const command = commands[packageManager] || "reinstall";
|
|
1418
|
+
return `Your ${packageManager} lockfile is incompatible with the current ${packageManager} version.
|
|
1419
|
+
|
|
1420
|
+
This can cause authentication failures during installation.
|
|
1421
|
+
|
|
1422
|
+
Quick fix:
|
|
1423
|
+
cd ${path4.dirname(lockfilePath)}
|
|
1424
|
+
${command}
|
|
1425
|
+
|
|
1426
|
+
Then run kigumi init again.`;
|
|
1427
|
+
}
|
|
1428
|
+
function createStoreErrorMessage(cwd) {
|
|
1429
|
+
return `Your node_modules were installed with a different pnpm version.
|
|
1430
|
+
|
|
1431
|
+
The pnpm store version has changed, causing installation failures.
|
|
1432
|
+
|
|
1433
|
+
Quick fix:
|
|
1434
|
+
cd ${cwd}
|
|
1435
|
+
rm -rf node_modules pnpm-lock.yaml
|
|
1436
|
+
pnpm install
|
|
1437
|
+
|
|
1438
|
+
Then run kigumi init again.`;
|
|
1439
|
+
}
|
|
1374
1440
|
async function installDependencies(options) {
|
|
1375
1441
|
const { cwd, config, tier, packageManager, output } = options;
|
|
1442
|
+
const lockfileCheck = await checkLockfileCompatibility(cwd, packageManager);
|
|
1443
|
+
if (!lockfileCheck.compatible && lockfileCheck.lockfilePath) {
|
|
1444
|
+
output.warn("Incompatible lockfile detected");
|
|
1445
|
+
output.note(
|
|
1446
|
+
"Lockfile compatibility issue",
|
|
1447
|
+
createLockfileErrorMessage(packageManager, lockfileCheck.lockfilePath)
|
|
1448
|
+
);
|
|
1449
|
+
throw new Error(
|
|
1450
|
+
`Incompatible ${packageManager} lockfile - please delete and reinstall`
|
|
1451
|
+
);
|
|
1452
|
+
}
|
|
1376
1453
|
const spinner2 = output.spinner("Installing dependencies...");
|
|
1377
1454
|
const waPackage = getWebAwesomePackage(tier);
|
|
1378
1455
|
const dependencies = [waPackage];
|
|
@@ -1416,6 +1493,42 @@ async function installDependencies(options) {
|
|
|
1416
1493
|
if (error && typeof error === "object" && "exitCode" in error && "stderr" in error) {
|
|
1417
1494
|
const execaError = error;
|
|
1418
1495
|
const stderr = execaError.stderr || "";
|
|
1496
|
+
const stdout = execaError.stdout || "";
|
|
1497
|
+
const errorOutput = stderr + stdout;
|
|
1498
|
+
const isStoreIssue = /ERR_PNPM_UNEXPECTED_STORE/i.test(errorOutput) || /Unexpected store location/i.test(errorOutput) || /currently linked from the store/i.test(errorOutput);
|
|
1499
|
+
if (isStoreIssue && packageManager === "pnpm") {
|
|
1500
|
+
output.error("Installation failed due to pnpm store version mismatch");
|
|
1501
|
+
output.note("Store compatibility issue", createStoreErrorMessage(cwd));
|
|
1502
|
+
throw new DependencyInstallError(
|
|
1503
|
+
dependencies.join(" "),
|
|
1504
|
+
packageManager,
|
|
1505
|
+
execaError,
|
|
1506
|
+
execaError.exitCode
|
|
1507
|
+
);
|
|
1508
|
+
}
|
|
1509
|
+
const isLockfileIssue = /not compatible with current/i.test(errorOutput) || /ignoring broken lockfile/i.test(errorOutput) || /lockfile .* version/i.test(errorOutput);
|
|
1510
|
+
if (isLockfileIssue) {
|
|
1511
|
+
output.error("Installation failed due to incompatible lockfile");
|
|
1512
|
+
const lockfiles = {
|
|
1513
|
+
npm: "package-lock.json",
|
|
1514
|
+
pnpm: "pnpm-lock.yaml",
|
|
1515
|
+
yarn: "yarn.lock"
|
|
1516
|
+
};
|
|
1517
|
+
const lockfileName = lockfiles[packageManager];
|
|
1518
|
+
const lockfilePath = lockfileName ? path4.join(cwd, lockfileName) : null;
|
|
1519
|
+
if (lockfilePath) {
|
|
1520
|
+
output.note(
|
|
1521
|
+
"Lockfile compatibility issue",
|
|
1522
|
+
createLockfileErrorMessage(packageManager, lockfilePath)
|
|
1523
|
+
);
|
|
1524
|
+
}
|
|
1525
|
+
throw new DependencyInstallError(
|
|
1526
|
+
dependencies.join(" "),
|
|
1527
|
+
packageManager,
|
|
1528
|
+
execaError,
|
|
1529
|
+
execaError.exitCode
|
|
1530
|
+
);
|
|
1531
|
+
}
|
|
1419
1532
|
const is401Error = stderr.includes("401") || stderr.includes("Unauthorized");
|
|
1420
1533
|
if (is401Error && tier === "pro") {
|
|
1421
1534
|
output.error("Authentication failed for Pro package");
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// src/utils/path-aliases.ts
|
|
2
|
+
import fs2 from "fs-extra";
|
|
3
|
+
import path from "path";
|
|
4
|
+
|
|
5
|
+
// src/utils/json.ts
|
|
6
|
+
import fs from "fs-extra";
|
|
7
|
+
async function readJSONWithComments(filePath) {
|
|
8
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
9
|
+
const stripped = stripJSONComments(content);
|
|
10
|
+
return JSON.parse(stripped);
|
|
11
|
+
}
|
|
12
|
+
function stripJSONComments(content) {
|
|
13
|
+
return content.replace(/\/\/.*/g, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// src/utils/path-aliases.ts
|
|
17
|
+
async function configureVitePathAliases(cwd, output) {
|
|
18
|
+
const viteConfigTs = path.join(cwd, "vite.config.ts");
|
|
19
|
+
const viteConfigJs = path.join(cwd, "vite.config.js");
|
|
20
|
+
let configPath = null;
|
|
21
|
+
if (await fs2.pathExists(viteConfigTs)) {
|
|
22
|
+
configPath = viteConfigTs;
|
|
23
|
+
} else if (await fs2.pathExists(viteConfigJs)) {
|
|
24
|
+
configPath = viteConfigJs;
|
|
25
|
+
}
|
|
26
|
+
if (!configPath) {
|
|
27
|
+
output.log("[DEBUG] No vite.config found, skipping");
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
let content = await fs2.readFile(configPath, "utf-8");
|
|
31
|
+
if (content.includes("alias:") && content.includes("'@'")) {
|
|
32
|
+
output.log("[DEBUG] Path aliases already configured in vite.config");
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
if (!content.includes("import path from 'path'") && !content.includes('import path from "path"')) {
|
|
36
|
+
const lastImportMatch = content.match(/(import .+;)\n*(?!import)/s);
|
|
37
|
+
if (lastImportMatch) {
|
|
38
|
+
content = content.replace(
|
|
39
|
+
lastImportMatch[1],
|
|
40
|
+
`${lastImportMatch[1]}
|
|
41
|
+
import path from 'path';`
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const configMatch = content.match(
|
|
46
|
+
/export default defineConfig\(\{([^}]*?)\}\)/s
|
|
47
|
+
);
|
|
48
|
+
if (!configMatch) {
|
|
49
|
+
output.warn("Could not parse vite.config, skipping path alias config");
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
const configContent = configMatch[1];
|
|
53
|
+
const hasResolve = configContent.includes("resolve:");
|
|
54
|
+
if (hasResolve) {
|
|
55
|
+
output.log("[DEBUG] resolve config exists, skipping");
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
const resolveConfig = `
|
|
59
|
+
resolve: {
|
|
60
|
+
alias: {
|
|
61
|
+
'@': path.resolve(__dirname, './src'),
|
|
62
|
+
},
|
|
63
|
+
},`;
|
|
64
|
+
content = content.replace(
|
|
65
|
+
/export default defineConfig\(\{/,
|
|
66
|
+
`export default defineConfig({${resolveConfig}`
|
|
67
|
+
);
|
|
68
|
+
await fs2.writeFile(configPath, content);
|
|
69
|
+
output.log("[DEBUG] \u2713 vite.config updated with path aliases");
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
async function configureTSConfigPathAliases(cwd, output) {
|
|
73
|
+
const tsconfigAppPath = path.join(cwd, "tsconfig.app.json");
|
|
74
|
+
if (!await fs2.pathExists(tsconfigAppPath)) {
|
|
75
|
+
output.log("[DEBUG] No tsconfig.app.json found, skipping");
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
const tsconfig = await readJSONWithComments(tsconfigAppPath);
|
|
79
|
+
if (tsconfig.compilerOptions?.paths?.["@/*"]) {
|
|
80
|
+
output.log("[DEBUG] Path aliases already in tsconfig.app.json");
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
tsconfig.compilerOptions = tsconfig.compilerOptions || {};
|
|
84
|
+
tsconfig.compilerOptions.baseUrl = ".";
|
|
85
|
+
tsconfig.compilerOptions.paths = {
|
|
86
|
+
"@/*": ["./src/*"]
|
|
87
|
+
};
|
|
88
|
+
await fs2.writeJSON(tsconfigAppPath, tsconfig, { spaces: 2 });
|
|
89
|
+
output.log("[DEBUG] \u2713 tsconfig.app.json updated with path aliases");
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
export {
|
|
93
|
+
configureTSConfigPathAliases,
|
|
94
|
+
configureVitePathAliases
|
|
95
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// src/utils/path-aliases.ts
|
|
2
|
+
import fs2 from "fs-extra";
|
|
3
|
+
import path from "path";
|
|
4
|
+
|
|
5
|
+
// src/utils/json.ts
|
|
6
|
+
import fs from "fs-extra";
|
|
7
|
+
async function readJSONWithComments(filePath) {
|
|
8
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
9
|
+
const stripped = stripJSONComments(content);
|
|
10
|
+
return JSON.parse(stripped);
|
|
11
|
+
}
|
|
12
|
+
function stripJSONComments(content) {
|
|
13
|
+
return content.replace(/\/\/.*/g, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// src/utils/path-aliases.ts
|
|
17
|
+
async function configureVitePathAliases(cwd, output) {
|
|
18
|
+
const viteConfigTs = path.join(cwd, "vite.config.ts");
|
|
19
|
+
const viteConfigJs = path.join(cwd, "vite.config.js");
|
|
20
|
+
let configPath = null;
|
|
21
|
+
if (await fs2.pathExists(viteConfigTs)) {
|
|
22
|
+
configPath = viteConfigTs;
|
|
23
|
+
} else if (await fs2.pathExists(viteConfigJs)) {
|
|
24
|
+
configPath = viteConfigJs;
|
|
25
|
+
}
|
|
26
|
+
if (!configPath) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
let content = await fs2.readFile(configPath, "utf-8");
|
|
30
|
+
if (content.includes("alias:") && content.includes("'@'")) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
if (!content.includes("import path from 'path'") && !content.includes('import path from "path"')) {
|
|
34
|
+
const lines = content.split("\n");
|
|
35
|
+
let lastImportIndex = -1;
|
|
36
|
+
for (let i = 0; i < lines.length; i++) {
|
|
37
|
+
if (lines[i].trim().startsWith("import ")) {
|
|
38
|
+
lastImportIndex = i;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (lastImportIndex >= 0) {
|
|
42
|
+
lines.splice(lastImportIndex + 1, 0, "import path from 'path';");
|
|
43
|
+
content = lines.join("\n");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (content.includes("resolve:")) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
const resolveConfig = `
|
|
50
|
+
resolve: {
|
|
51
|
+
alias: {
|
|
52
|
+
'@': path.resolve(__dirname, './src'),
|
|
53
|
+
},
|
|
54
|
+
},`;
|
|
55
|
+
const defineConfigMatch = content.match(/export default defineConfig\(\{/);
|
|
56
|
+
if (!defineConfigMatch) {
|
|
57
|
+
output.warn("Could not parse vite.config, skipping path alias config");
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
content = content.replace(
|
|
61
|
+
/export default defineConfig\(\{/,
|
|
62
|
+
`export default defineConfig({${resolveConfig}`
|
|
63
|
+
);
|
|
64
|
+
await fs2.writeFile(configPath, content);
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
async function configureTSConfigPathAliases(cwd, _output) {
|
|
68
|
+
const tsconfigAppPath = path.join(cwd, "tsconfig.app.json");
|
|
69
|
+
if (!await fs2.pathExists(tsconfigAppPath)) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
const tsconfig = await readJSONWithComments(tsconfigAppPath);
|
|
73
|
+
if (tsconfig.compilerOptions?.paths?.["@/*"]) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
tsconfig.compilerOptions = tsconfig.compilerOptions || {};
|
|
77
|
+
tsconfig.compilerOptions.baseUrl = tsconfig.compilerOptions.baseUrl || ".";
|
|
78
|
+
tsconfig.compilerOptions.paths = {
|
|
79
|
+
...tsconfig.compilerOptions.paths,
|
|
80
|
+
// Preserve existing paths
|
|
81
|
+
"@/*": ["./src/*"]
|
|
82
|
+
};
|
|
83
|
+
await fs2.writeJSON(tsconfigAppPath, tsconfig, { spaces: 2 });
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
export {
|
|
87
|
+
configureTSConfigPathAliases,
|
|
88
|
+
configureVitePathAliases
|
|
89
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// src/utils/path-aliases.ts
|
|
2
|
+
import fs2 from "fs-extra";
|
|
3
|
+
import path from "path";
|
|
4
|
+
|
|
5
|
+
// src/utils/json.ts
|
|
6
|
+
import fs from "fs-extra";
|
|
7
|
+
async function readJSONWithComments(filePath) {
|
|
8
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
9
|
+
const stripped = stripJSONComments(content);
|
|
10
|
+
return JSON.parse(stripped);
|
|
11
|
+
}
|
|
12
|
+
function stripJSONComments(content) {
|
|
13
|
+
return content.replace(/\/\/.*/g, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// src/utils/path-aliases.ts
|
|
17
|
+
async function configureVitePathAliases(cwd, output) {
|
|
18
|
+
const viteConfigTs = path.join(cwd, "vite.config.ts");
|
|
19
|
+
const viteConfigJs = path.join(cwd, "vite.config.js");
|
|
20
|
+
let configPath = null;
|
|
21
|
+
if (await fs2.pathExists(viteConfigTs)) {
|
|
22
|
+
configPath = viteConfigTs;
|
|
23
|
+
} else if (await fs2.pathExists(viteConfigJs)) {
|
|
24
|
+
configPath = viteConfigJs;
|
|
25
|
+
}
|
|
26
|
+
if (!configPath) {
|
|
27
|
+
output.log("[DEBUG] No vite.config found, skipping");
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
let content = await fs2.readFile(configPath, "utf-8");
|
|
31
|
+
if (content.includes("alias:") && content.includes("'@'")) {
|
|
32
|
+
output.log("[DEBUG] Path aliases already configured in vite.config");
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
if (!content.includes("import path from 'path'") && !content.includes('import path from "path"')) {
|
|
36
|
+
const lines = content.split("\n");
|
|
37
|
+
let lastImportIndex = -1;
|
|
38
|
+
for (let i = 0; i < lines.length; i++) {
|
|
39
|
+
if (lines[i].trim().startsWith("import ")) {
|
|
40
|
+
lastImportIndex = i;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (lastImportIndex >= 0) {
|
|
44
|
+
lines.splice(lastImportIndex + 1, 0, "import path from 'path';");
|
|
45
|
+
content = lines.join("\n");
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const configMatch = content.match(
|
|
49
|
+
/export default defineConfig\(\{([^}]*?)\}\)/s
|
|
50
|
+
);
|
|
51
|
+
if (!configMatch) {
|
|
52
|
+
output.warn("Could not parse vite.config, skipping path alias config");
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
const configContent = configMatch[1];
|
|
56
|
+
const hasResolve = configContent.includes("resolve:");
|
|
57
|
+
if (hasResolve) {
|
|
58
|
+
output.log("[DEBUG] resolve config exists, skipping");
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
const resolveConfig = `
|
|
62
|
+
resolve: {
|
|
63
|
+
alias: {
|
|
64
|
+
'@': path.resolve(__dirname, './src'),
|
|
65
|
+
},
|
|
66
|
+
},`;
|
|
67
|
+
content = content.replace(
|
|
68
|
+
/export default defineConfig\(\{/,
|
|
69
|
+
`export default defineConfig({${resolveConfig}`
|
|
70
|
+
);
|
|
71
|
+
await fs2.writeFile(configPath, content);
|
|
72
|
+
output.log("[DEBUG] \u2713 vite.config updated with path aliases");
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
async function configureTSConfigPathAliases(cwd, output) {
|
|
76
|
+
const tsconfigAppPath = path.join(cwd, "tsconfig.app.json");
|
|
77
|
+
if (!await fs2.pathExists(tsconfigAppPath)) {
|
|
78
|
+
output.log("[DEBUG] No tsconfig.app.json found, skipping");
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
const tsconfig = await readJSONWithComments(tsconfigAppPath);
|
|
82
|
+
if (tsconfig.compilerOptions?.paths?.["@/*"]) {
|
|
83
|
+
output.log("[DEBUG] Path aliases already in tsconfig.app.json");
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
tsconfig.compilerOptions = tsconfig.compilerOptions || {};
|
|
87
|
+
tsconfig.compilerOptions.baseUrl = ".";
|
|
88
|
+
tsconfig.compilerOptions.paths = {
|
|
89
|
+
"@/*": ["./src/*"]
|
|
90
|
+
};
|
|
91
|
+
await fs2.writeJSON(tsconfigAppPath, tsconfig, { spaces: 2 });
|
|
92
|
+
output.log("[DEBUG] \u2713 tsconfig.app.json updated with path aliases");
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
export {
|
|
96
|
+
configureTSConfigPathAliases,
|
|
97
|
+
configureVitePathAliases
|
|
98
|
+
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// src/utils/path-aliases.ts
|
|
2
|
+
import fs2 from "fs-extra";
|
|
3
|
+
import path from "path";
|
|
4
|
+
|
|
5
|
+
// src/utils/json.ts
|
|
6
|
+
import fs from "fs-extra";
|
|
7
|
+
async function readJSONWithComments(filePath) {
|
|
8
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
9
|
+
const stripped = stripJSONComments(content);
|
|
10
|
+
return JSON.parse(stripped);
|
|
11
|
+
}
|
|
12
|
+
function stripJSONComments(content) {
|
|
13
|
+
return content.replace(/\/\/.*/g, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// src/utils/path-aliases.ts
|
|
17
|
+
async function configureVitePathAliases(cwd, output) {
|
|
18
|
+
const viteConfigTs = path.join(cwd, "vite.config.ts");
|
|
19
|
+
const viteConfigJs = path.join(cwd, "vite.config.js");
|
|
20
|
+
let configPath = null;
|
|
21
|
+
if (await fs2.pathExists(viteConfigTs)) {
|
|
22
|
+
configPath = viteConfigTs;
|
|
23
|
+
} else if (await fs2.pathExists(viteConfigJs)) {
|
|
24
|
+
configPath = viteConfigJs;
|
|
25
|
+
}
|
|
26
|
+
if (!configPath) {
|
|
27
|
+
output.log("[DEBUG] No vite.config found, skipping");
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
let content = await fs2.readFile(configPath, "utf-8");
|
|
31
|
+
if (content.includes("alias:") && content.includes("'@'")) {
|
|
32
|
+
output.log("[DEBUG] Path aliases already configured in vite.config");
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
if (!content.includes("import path from 'path'") && !content.includes('import path from "path"')) {
|
|
36
|
+
content = content.replace(
|
|
37
|
+
/(import .+ from ['"]vite['"][^;]*;)/,
|
|
38
|
+
"$1\nimport path from 'path';"
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
const configMatch = content.match(
|
|
42
|
+
/export default defineConfig\(\{([^}]*?)\}\)/s
|
|
43
|
+
);
|
|
44
|
+
if (!configMatch) {
|
|
45
|
+
output.warn("Could not parse vite.config, skipping path alias config");
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
const configContent = configMatch[1];
|
|
49
|
+
const hasResolve = configContent.includes("resolve:");
|
|
50
|
+
if (hasResolve) {
|
|
51
|
+
output.log("[DEBUG] resolve config exists, skipping");
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
const resolveConfig = `
|
|
55
|
+
resolve: {
|
|
56
|
+
alias: {
|
|
57
|
+
'@': path.resolve(__dirname, './src'),
|
|
58
|
+
},
|
|
59
|
+
},`;
|
|
60
|
+
content = content.replace(
|
|
61
|
+
/export default defineConfig\(\{/,
|
|
62
|
+
`export default defineConfig({${resolveConfig}`
|
|
63
|
+
);
|
|
64
|
+
await fs2.writeFile(configPath, content);
|
|
65
|
+
output.log("[DEBUG] \u2713 vite.config updated with path aliases");
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
async function configureTSConfigPathAliases(cwd, output) {
|
|
69
|
+
const tsconfigAppPath = path.join(cwd, "tsconfig.app.json");
|
|
70
|
+
if (!await fs2.pathExists(tsconfigAppPath)) {
|
|
71
|
+
output.log("[DEBUG] No tsconfig.app.json found, skipping");
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
const tsconfig = await readJSONWithComments(tsconfigAppPath);
|
|
75
|
+
if (tsconfig.compilerOptions?.paths?.["@/*"]) {
|
|
76
|
+
output.log("[DEBUG] Path aliases already in tsconfig.app.json");
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
tsconfig.compilerOptions = tsconfig.compilerOptions || {};
|
|
80
|
+
tsconfig.compilerOptions.baseUrl = ".";
|
|
81
|
+
tsconfig.compilerOptions.paths = {
|
|
82
|
+
"@/*": ["./src/*"]
|
|
83
|
+
};
|
|
84
|
+
await fs2.writeJSON(tsconfigAppPath, tsconfig, { spaces: 2 });
|
|
85
|
+
output.log("[DEBUG] \u2713 tsconfig.app.json updated with path aliases");
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
export {
|
|
89
|
+
configureTSConfigPathAliases,
|
|
90
|
+
configureVitePathAliases
|
|
91
|
+
};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// src/utils/path-aliases.ts
|
|
2
|
+
import fs2 from "fs-extra";
|
|
3
|
+
import path from "path";
|
|
4
|
+
|
|
5
|
+
// src/utils/json.ts
|
|
6
|
+
import fs from "fs-extra";
|
|
7
|
+
async function readJSONWithComments(filePath) {
|
|
8
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
9
|
+
const stripped = stripJSONComments(content);
|
|
10
|
+
return JSON.parse(stripped);
|
|
11
|
+
}
|
|
12
|
+
function stripJSONComments(content) {
|
|
13
|
+
return content.replace(/\/\/.*/g, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// src/utils/path-aliases.ts
|
|
17
|
+
async function configureVitePathAliases(cwd, output) {
|
|
18
|
+
const viteConfigTs = path.join(cwd, "vite.config.ts");
|
|
19
|
+
const viteConfigJs = path.join(cwd, "vite.config.js");
|
|
20
|
+
let configPath = null;
|
|
21
|
+
if (await fs2.pathExists(viteConfigTs)) {
|
|
22
|
+
configPath = viteConfigTs;
|
|
23
|
+
} else if (await fs2.pathExists(viteConfigJs)) {
|
|
24
|
+
configPath = viteConfigJs;
|
|
25
|
+
}
|
|
26
|
+
if (!configPath) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
let content = await fs2.readFile(configPath, "utf-8");
|
|
30
|
+
if (content.includes("alias:") && content.includes("'@'")) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
if (!content.includes("import path from 'path'") && !content.includes('import path from "path"')) {
|
|
34
|
+
const lines = content.split("\n");
|
|
35
|
+
let lastImportIndex = -1;
|
|
36
|
+
for (let i = 0; i < lines.length; i++) {
|
|
37
|
+
if (lines[i].trim().startsWith("import ")) {
|
|
38
|
+
lastImportIndex = i;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (lastImportIndex >= 0) {
|
|
42
|
+
lines.splice(lastImportIndex + 1, 0, "import path from 'path';");
|
|
43
|
+
content = lines.join("\n");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (content.includes("resolve:")) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
const resolveConfig = `
|
|
50
|
+
resolve: {
|
|
51
|
+
alias: {
|
|
52
|
+
'@': path.resolve(__dirname, './src'),
|
|
53
|
+
},
|
|
54
|
+
},`;
|
|
55
|
+
const defineConfigMatch = content.match(/export default defineConfig\(\{/);
|
|
56
|
+
if (!defineConfigMatch) {
|
|
57
|
+
output.warn("Could not parse vite.config, skipping path alias config");
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
content = content.replace(
|
|
61
|
+
/export default defineConfig\(\{/,
|
|
62
|
+
`export default defineConfig({${resolveConfig}`
|
|
63
|
+
);
|
|
64
|
+
await fs2.writeFile(configPath, content);
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
async function configureTSConfigPathAliases(cwd, _output) {
|
|
68
|
+
const tsconfigAppPath = path.join(cwd, "tsconfig.app.json");
|
|
69
|
+
if (!await fs2.pathExists(tsconfigAppPath)) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
const tsconfig = await readJSONWithComments(tsconfigAppPath);
|
|
73
|
+
if (tsconfig.compilerOptions?.paths?.["@/*"]) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
tsconfig.compilerOptions = tsconfig.compilerOptions || {};
|
|
77
|
+
tsconfig.compilerOptions.baseUrl = tsconfig.compilerOptions.baseUrl || ".";
|
|
78
|
+
tsconfig.compilerOptions.paths = {
|
|
79
|
+
...tsconfig.compilerOptions.paths,
|
|
80
|
+
// Preserve existing paths
|
|
81
|
+
"@/*": ["./src/*"]
|
|
82
|
+
};
|
|
83
|
+
if (Array.isArray(tsconfig.compilerOptions.types) && tsconfig.compilerOptions.types.length === 1 && tsconfig.compilerOptions.types[0] === "vite/client") {
|
|
84
|
+
delete tsconfig.compilerOptions.types;
|
|
85
|
+
}
|
|
86
|
+
await fs2.writeJSON(tsconfigAppPath, tsconfig, { spaces: 2 });
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
export {
|
|
90
|
+
configureTSConfigPathAliases,
|
|
91
|
+
configureVitePathAliases
|
|
92
|
+
};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// src/utils/path-aliases.ts
|
|
2
|
+
import fs2 from "fs-extra";
|
|
3
|
+
import path from "path";
|
|
4
|
+
|
|
5
|
+
// src/utils/json.ts
|
|
6
|
+
import fs from "fs-extra";
|
|
7
|
+
async function readJSONWithComments(filePath) {
|
|
8
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
9
|
+
const stripped = stripJSONComments(content);
|
|
10
|
+
return JSON.parse(stripped);
|
|
11
|
+
}
|
|
12
|
+
function stripJSONComments(content) {
|
|
13
|
+
return content.replace(/\/\/.*/g, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// src/utils/path-aliases.ts
|
|
17
|
+
async function configureVitePathAliases(cwd, output) {
|
|
18
|
+
const viteConfigTs = path.join(cwd, "vite.config.ts");
|
|
19
|
+
const viteConfigJs = path.join(cwd, "vite.config.js");
|
|
20
|
+
let configPath = null;
|
|
21
|
+
if (await fs2.pathExists(viteConfigTs)) {
|
|
22
|
+
configPath = viteConfigTs;
|
|
23
|
+
} else if (await fs2.pathExists(viteConfigJs)) {
|
|
24
|
+
configPath = viteConfigJs;
|
|
25
|
+
}
|
|
26
|
+
if (!configPath) {
|
|
27
|
+
output.log("[DEBUG] No vite.config found, skipping");
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
let content = await fs2.readFile(configPath, "utf-8");
|
|
31
|
+
if (content.includes("alias:") && content.includes("'@'")) {
|
|
32
|
+
output.log("[DEBUG] Path aliases already configured in vite.config");
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
if (!content.includes("import path from 'path'") && !content.includes('import path from "path"')) {
|
|
36
|
+
const lines = content.split("\n");
|
|
37
|
+
let lastImportIndex = -1;
|
|
38
|
+
for (let i = 0; i < lines.length; i++) {
|
|
39
|
+
if (lines[i].trim().startsWith("import ")) {
|
|
40
|
+
lastImportIndex = i;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (lastImportIndex >= 0) {
|
|
44
|
+
lines.splice(lastImportIndex + 1, 0, "import path from 'path';");
|
|
45
|
+
content = lines.join("\n");
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (content.includes("resolve:")) {
|
|
49
|
+
output.log("[DEBUG] resolve config exists, skipping");
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
const resolveConfig = `
|
|
53
|
+
resolve: {
|
|
54
|
+
alias: {
|
|
55
|
+
'@': path.resolve(__dirname, './src'),
|
|
56
|
+
},
|
|
57
|
+
},`;
|
|
58
|
+
const defineConfigMatch = content.match(/export default defineConfig\(\{/);
|
|
59
|
+
if (!defineConfigMatch) {
|
|
60
|
+
output.warn("Could not parse vite.config, skipping path alias config");
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
content = content.replace(
|
|
64
|
+
/export default defineConfig\(\{/,
|
|
65
|
+
`export default defineConfig({${resolveConfig}`
|
|
66
|
+
);
|
|
67
|
+
await fs2.writeFile(configPath, content);
|
|
68
|
+
output.log("[DEBUG] \u2713 vite.config updated with path aliases");
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
async function configureTSConfigPathAliases(cwd, output) {
|
|
72
|
+
const tsconfigAppPath = path.join(cwd, "tsconfig.app.json");
|
|
73
|
+
if (!await fs2.pathExists(tsconfigAppPath)) {
|
|
74
|
+
output.log("[DEBUG] No tsconfig.app.json found, skipping");
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
const tsconfig = await readJSONWithComments(tsconfigAppPath);
|
|
78
|
+
if (tsconfig.compilerOptions?.paths?.["@/*"]) {
|
|
79
|
+
output.log("[DEBUG] Path aliases already in tsconfig.app.json");
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
tsconfig.compilerOptions = tsconfig.compilerOptions || {};
|
|
83
|
+
tsconfig.compilerOptions.baseUrl = ".";
|
|
84
|
+
tsconfig.compilerOptions.paths = {
|
|
85
|
+
"@/*": ["./src/*"]
|
|
86
|
+
};
|
|
87
|
+
await fs2.writeJSON(tsconfigAppPath, tsconfig, { spaces: 2 });
|
|
88
|
+
output.log("[DEBUG] \u2713 tsconfig.app.json updated with path aliases");
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
export {
|
|
92
|
+
configureTSConfigPathAliases,
|
|
93
|
+
configureVitePathAliases
|
|
94
|
+
};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// src/utils/project-config.ts
|
|
2
|
+
import fs2 from "fs-extra";
|
|
3
|
+
import path from "path";
|
|
4
|
+
|
|
5
|
+
// src/utils/json.ts
|
|
6
|
+
import fs from "fs-extra";
|
|
7
|
+
async function readJSONWithComments(filePath) {
|
|
8
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
9
|
+
const stripped = stripJSONComments(content);
|
|
10
|
+
return JSON.parse(stripped);
|
|
11
|
+
}
|
|
12
|
+
function stripJSONComments(content) {
|
|
13
|
+
return content.replace(/\/\/.*/g, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// src/utils/project-config.ts
|
|
17
|
+
async function configureVitePathAliases(cwd, output) {
|
|
18
|
+
const viteConfigTs = path.join(cwd, "vite.config.ts");
|
|
19
|
+
const viteConfigJs = path.join(cwd, "vite.config.js");
|
|
20
|
+
let configPath = null;
|
|
21
|
+
if (await fs2.pathExists(viteConfigTs)) {
|
|
22
|
+
configPath = viteConfigTs;
|
|
23
|
+
} else if (await fs2.pathExists(viteConfigJs)) {
|
|
24
|
+
configPath = viteConfigJs;
|
|
25
|
+
}
|
|
26
|
+
if (!configPath) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
let content = await fs2.readFile(configPath, "utf-8");
|
|
30
|
+
if (content.includes("alias:") && content.includes("'@'")) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
if (!content.includes("import path from 'path'") && !content.includes('import path from "path"')) {
|
|
34
|
+
const lines = content.split("\n");
|
|
35
|
+
let lastImportIndex = -1;
|
|
36
|
+
for (let i = 0; i < lines.length; i++) {
|
|
37
|
+
if (lines[i].trim().startsWith("import ")) {
|
|
38
|
+
lastImportIndex = i;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (lastImportIndex >= 0) {
|
|
42
|
+
lines.splice(lastImportIndex + 1, 0, "import path from 'path';");
|
|
43
|
+
content = lines.join("\n");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (content.includes("resolve:")) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
const resolveConfig = `
|
|
50
|
+
resolve: {
|
|
51
|
+
alias: {
|
|
52
|
+
'@': path.resolve(__dirname, './src'),
|
|
53
|
+
},
|
|
54
|
+
},`;
|
|
55
|
+
const defineConfigMatch = content.match(/export default defineConfig\(\{/);
|
|
56
|
+
if (!defineConfigMatch) {
|
|
57
|
+
output.warn("Could not parse vite.config, skipping path alias config");
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
content = content.replace(
|
|
61
|
+
/export default defineConfig\(\{/,
|
|
62
|
+
`export default defineConfig({${resolveConfig}`
|
|
63
|
+
);
|
|
64
|
+
await fs2.writeFile(configPath, content);
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
async function configureTSConfig(cwd, _output) {
|
|
68
|
+
const tsconfigAppPath = path.join(cwd, "tsconfig.app.json");
|
|
69
|
+
if (!await fs2.pathExists(tsconfigAppPath)) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
const tsconfig = await readJSONWithComments(tsconfigAppPath);
|
|
73
|
+
let modified = false;
|
|
74
|
+
tsconfig.compilerOptions = tsconfig.compilerOptions || {};
|
|
75
|
+
if (!tsconfig.compilerOptions.paths?.["@/*"]) {
|
|
76
|
+
tsconfig.compilerOptions.baseUrl = tsconfig.compilerOptions.baseUrl || ".";
|
|
77
|
+
tsconfig.compilerOptions.paths = {
|
|
78
|
+
...tsconfig.compilerOptions.paths,
|
|
79
|
+
"@/*": ["./src/*"]
|
|
80
|
+
};
|
|
81
|
+
modified = true;
|
|
82
|
+
}
|
|
83
|
+
if (tsconfig.compilerOptions.esModuleInterop !== true) {
|
|
84
|
+
tsconfig.compilerOptions.esModuleInterop = true;
|
|
85
|
+
modified = true;
|
|
86
|
+
}
|
|
87
|
+
if (tsconfig.compilerOptions.allowSyntheticDefaultImports !== true) {
|
|
88
|
+
tsconfig.compilerOptions.allowSyntheticDefaultImports = true;
|
|
89
|
+
modified = true;
|
|
90
|
+
}
|
|
91
|
+
if (tsconfig.compilerOptions.verbatimModuleSyntax === true) {
|
|
92
|
+
delete tsconfig.compilerOptions.verbatimModuleSyntax;
|
|
93
|
+
modified = true;
|
|
94
|
+
}
|
|
95
|
+
if (Array.isArray(tsconfig.compilerOptions.types)) {
|
|
96
|
+
if (tsconfig.compilerOptions.types.length === 1 && tsconfig.compilerOptions.types[0] === "vite/client") {
|
|
97
|
+
delete tsconfig.compilerOptions.types;
|
|
98
|
+
modified = true;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (tsconfig.compilerOptions.moduleResolution === "bundler" || tsconfig.compilerOptions.moduleResolution === "Bundler") {
|
|
102
|
+
} else if (!tsconfig.compilerOptions.moduleResolution) {
|
|
103
|
+
tsconfig.compilerOptions.moduleResolution = "bundler";
|
|
104
|
+
modified = true;
|
|
105
|
+
}
|
|
106
|
+
if (modified) {
|
|
107
|
+
await fs2.writeJSON(tsconfigAppPath, tsconfig, { spaces: 2 });
|
|
108
|
+
}
|
|
109
|
+
return modified;
|
|
110
|
+
}
|
|
111
|
+
export {
|
|
112
|
+
configureTSConfig,
|
|
113
|
+
configureTSConfig as configureTSConfigPathAliases,
|
|
114
|
+
configureVitePathAliases
|
|
115
|
+
};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// src/utils/project-config.ts
|
|
2
|
+
import fs2 from "fs-extra";
|
|
3
|
+
import path from "path";
|
|
4
|
+
|
|
5
|
+
// src/utils/json.ts
|
|
6
|
+
import fs from "fs-extra";
|
|
7
|
+
async function readJSONWithComments(filePath) {
|
|
8
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
9
|
+
const stripped = stripJSONComments(content);
|
|
10
|
+
return JSON.parse(stripped);
|
|
11
|
+
}
|
|
12
|
+
function stripJSONComments(content) {
|
|
13
|
+
return content.replace(/\/\/.*/g, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// src/utils/project-config.ts
|
|
17
|
+
async function configureVitePathAliases(cwd, output) {
|
|
18
|
+
const viteConfigTs = path.join(cwd, "vite.config.ts");
|
|
19
|
+
const viteConfigJs = path.join(cwd, "vite.config.js");
|
|
20
|
+
let configPath = null;
|
|
21
|
+
if (await fs2.pathExists(viteConfigTs)) {
|
|
22
|
+
configPath = viteConfigTs;
|
|
23
|
+
} else if (await fs2.pathExists(viteConfigJs)) {
|
|
24
|
+
configPath = viteConfigJs;
|
|
25
|
+
}
|
|
26
|
+
if (!configPath) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
let content = await fs2.readFile(configPath, "utf-8");
|
|
30
|
+
if (content.includes("alias:") && content.includes("'@'")) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
if (!content.includes("import path from 'path'") && !content.includes('import path from "path"')) {
|
|
34
|
+
const lines = content.split("\n");
|
|
35
|
+
let lastImportIndex = -1;
|
|
36
|
+
for (let i = 0; i < lines.length; i++) {
|
|
37
|
+
if (lines[i].trim().startsWith("import ")) {
|
|
38
|
+
lastImportIndex = i;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (lastImportIndex >= 0) {
|
|
42
|
+
lines.splice(lastImportIndex + 1, 0, "import path from 'path';");
|
|
43
|
+
content = lines.join("\n");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (content.includes("resolve:")) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
const resolveConfig = `
|
|
50
|
+
resolve: {
|
|
51
|
+
alias: {
|
|
52
|
+
'@': path.resolve(__dirname, './src'),
|
|
53
|
+
},
|
|
54
|
+
},`;
|
|
55
|
+
const defineConfigMatch = content.match(/export default defineConfig\(\{/);
|
|
56
|
+
if (!defineConfigMatch) {
|
|
57
|
+
output.warn("Could not parse vite.config, skipping path alias config");
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
content = content.replace(
|
|
61
|
+
/export default defineConfig\(\{/,
|
|
62
|
+
`export default defineConfig({${resolveConfig}`
|
|
63
|
+
);
|
|
64
|
+
await fs2.writeFile(configPath, content);
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
async function configureTSConfig(cwd, _output) {
|
|
68
|
+
const tsconfigAppPath = path.join(cwd, "tsconfig.app.json");
|
|
69
|
+
if (!await fs2.pathExists(tsconfigAppPath)) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
const tsconfig = await readJSONWithComments(tsconfigAppPath);
|
|
73
|
+
let modified = false;
|
|
74
|
+
tsconfig.compilerOptions = tsconfig.compilerOptions || {};
|
|
75
|
+
if (!tsconfig.compilerOptions.paths?.["@/*"]) {
|
|
76
|
+
tsconfig.compilerOptions.baseUrl = tsconfig.compilerOptions.baseUrl || ".";
|
|
77
|
+
tsconfig.compilerOptions.paths = {
|
|
78
|
+
...tsconfig.compilerOptions.paths,
|
|
79
|
+
"@/*": ["./src/*"]
|
|
80
|
+
};
|
|
81
|
+
modified = true;
|
|
82
|
+
}
|
|
83
|
+
if (tsconfig.compilerOptions.esModuleInterop !== true) {
|
|
84
|
+
tsconfig.compilerOptions.esModuleInterop = true;
|
|
85
|
+
modified = true;
|
|
86
|
+
}
|
|
87
|
+
if (tsconfig.compilerOptions.allowSyntheticDefaultImports !== true) {
|
|
88
|
+
tsconfig.compilerOptions.allowSyntheticDefaultImports = true;
|
|
89
|
+
modified = true;
|
|
90
|
+
}
|
|
91
|
+
if (tsconfig.compilerOptions.verbatimModuleSyntax === true) {
|
|
92
|
+
delete tsconfig.compilerOptions.verbatimModuleSyntax;
|
|
93
|
+
modified = true;
|
|
94
|
+
}
|
|
95
|
+
if (Array.isArray(tsconfig.compilerOptions.types) && tsconfig.compilerOptions.types.length === 1 && tsconfig.compilerOptions.types[0] === "vite/client") {
|
|
96
|
+
delete tsconfig.compilerOptions.types;
|
|
97
|
+
modified = true;
|
|
98
|
+
}
|
|
99
|
+
if (modified) {
|
|
100
|
+
await fs2.writeJSON(tsconfigAppPath, tsconfig, { spaces: 2 });
|
|
101
|
+
}
|
|
102
|
+
return modified;
|
|
103
|
+
}
|
|
104
|
+
export {
|
|
105
|
+
configureTSConfig,
|
|
106
|
+
configureTSConfig as configureTSConfigPathAliases,
|
|
107
|
+
configureVitePathAliases
|
|
108
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Kigumi Setup Instructions
|
|
2
|
+
|
|
3
|
+
Welcome to Kigumi! Your setup is complete.
|
|
4
|
+
|
|
5
|
+
## ✅ Completed by CLI
|
|
6
|
+
|
|
7
|
+
- ✓ Installed `{{{waPackage}}}` and dependencies
|
|
8
|
+
- ✓ Created `kigumi.config.json` (theme: {{theme}})
|
|
9
|
+
- ✓ Generated `src/lib/webawesome.ts` (Web Awesome imports)
|
|
10
|
+
- ✓ Generated `src/styles/theme.css` ({{theme}} theme)
|
|
11
|
+
- ✓ Configured path aliases (`@/*` → `./src/*`)
|
|
12
|
+
- ✓ Created `src/vite-env.d.ts` for TypeScript support
|
|
13
|
+
{{#if componentsDir}}
|
|
14
|
+
- ✓ Created components directory: `{{componentsDir}}`
|
|
15
|
+
{{/if}}
|
|
16
|
+
|
|
17
|
+
## 📦 Adding Components
|
|
18
|
+
|
|
19
|
+
Add components with:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx kigumi add button card dialog input
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The CLI will:
|
|
26
|
+
- Generate React component wrappers
|
|
27
|
+
- Update `src/lib/webawesome.ts` with imports
|
|
28
|
+
- Update `src/vite-env.d.ts` with TypeScript types
|
|
29
|
+
|
|
30
|
+
## 🎨 Changing Themes
|
|
31
|
+
|
|
32
|
+
Available themes: `awesome`, `brutal`, `brutalist`, `camp`, `glossy`, `hacker`, `retro`, `tech`, `terminal`, `tropical`, `vintage`
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npx kigumi theme set brutalist
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## 🚀 Development
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm run dev
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## 📚 Need Help?
|
|
45
|
+
|
|
46
|
+
- **Documentation**: https://kigumi.dev/docs
|
|
47
|
+
- **Web Awesome Docs**: https://webawesome.com/docs
|
|
48
|
+
- **GitHub Issues**: https://github.com/kigumi/cli/issues
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
Generated by Kigumi CLI v{{version}}
|