@lark-apaas/fullstack-cli 1.1.36 → 1.1.37-alpha.1
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/index.js +133 -174
- package/package.json +1 -1
- package/templates/scripts/build.sh +44 -8
- package/templates/scripts/lint.js +0 -150
package/dist/index.js
CHANGED
|
@@ -2363,8 +2363,8 @@ var genDbSchemaCommand = {
|
|
|
2363
2363
|
};
|
|
2364
2364
|
|
|
2365
2365
|
// src/commands/sync/run.handler.ts
|
|
2366
|
-
import
|
|
2367
|
-
import
|
|
2366
|
+
import path4 from "path";
|
|
2367
|
+
import fs6 from "fs";
|
|
2368
2368
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
2369
2369
|
|
|
2370
2370
|
// src/config/sync.ts
|
|
@@ -2525,93 +2525,18 @@ function deepMergeJson(user, template, arrayMerge = {}, currentPath = "") {
|
|
|
2525
2525
|
return result;
|
|
2526
2526
|
}
|
|
2527
2527
|
|
|
2528
|
-
// src/utils/package-json.ts
|
|
2529
|
-
import fs6 from "fs";
|
|
2530
|
-
import path4 from "path";
|
|
2531
|
-
var LEGACY_LINT_SCRIPT = 'concurrently "npm run eslint" "npm run type:check" "npm run stylelint"';
|
|
2532
|
-
var PATCHED_LINT_SCRIPT = "node ./scripts/lint.js";
|
|
2533
|
-
function readPackageJson(cwd = process.cwd()) {
|
|
2534
|
-
const pkgPath = path4.join(cwd, "package.json");
|
|
2535
|
-
if (!fs6.existsSync(pkgPath)) {
|
|
2536
|
-
throw new Error(`package.json not found at ${pkgPath}`);
|
|
2537
|
-
}
|
|
2538
|
-
const content = fs6.readFileSync(pkgPath, "utf-8");
|
|
2539
|
-
return JSON.parse(content);
|
|
2540
|
-
}
|
|
2541
|
-
function writePackageJson(pkg2, cwd = process.cwd()) {
|
|
2542
|
-
const pkgPath = path4.join(cwd, "package.json");
|
|
2543
|
-
const content = JSON.stringify(pkg2, null, 2) + "\n";
|
|
2544
|
-
fs6.writeFileSync(pkgPath, content, "utf-8");
|
|
2545
|
-
}
|
|
2546
|
-
function patchLintScriptForFilesSupport(pkg2) {
|
|
2547
|
-
const currentLint = pkg2.scripts?.lint;
|
|
2548
|
-
if (!currentLint) {
|
|
2549
|
-
return "skipped-missing";
|
|
2550
|
-
}
|
|
2551
|
-
if (currentLint === PATCHED_LINT_SCRIPT || currentLint === "node scripts/lint.js") {
|
|
2552
|
-
return "already-patched";
|
|
2553
|
-
}
|
|
2554
|
-
if (currentLint !== LEGACY_LINT_SCRIPT) {
|
|
2555
|
-
return "skipped-custom";
|
|
2556
|
-
}
|
|
2557
|
-
pkg2.scripts = pkg2.scripts || {};
|
|
2558
|
-
pkg2.scripts.lint = PATCHED_LINT_SCRIPT;
|
|
2559
|
-
return "patched";
|
|
2560
|
-
}
|
|
2561
|
-
function removeUpgradeScript(pkg2) {
|
|
2562
|
-
if (!pkg2.scripts?.upgrade) {
|
|
2563
|
-
return false;
|
|
2564
|
-
}
|
|
2565
|
-
delete pkg2.scripts.upgrade;
|
|
2566
|
-
return true;
|
|
2567
|
-
}
|
|
2568
|
-
function cleanDevScript(pkg2) {
|
|
2569
|
-
if (!pkg2.scripts?.dev) {
|
|
2570
|
-
return false;
|
|
2571
|
-
}
|
|
2572
|
-
const originalDev = pkg2.scripts.dev;
|
|
2573
|
-
const cleanedDev = originalDev.replace(/npm\s+run\s+upgrade\s*&&\s*/g, "").replace(/npm\s+run\s+upgrade\s*$/g, "").trim();
|
|
2574
|
-
if (cleanedDev !== originalDev) {
|
|
2575
|
-
pkg2.scripts.dev = cleanedDev;
|
|
2576
|
-
return true;
|
|
2577
|
-
}
|
|
2578
|
-
return false;
|
|
2579
|
-
}
|
|
2580
|
-
function cleanupPackageJson(cwd = process.cwd()) {
|
|
2581
|
-
try {
|
|
2582
|
-
const pkg2 = readPackageJson(cwd);
|
|
2583
|
-
let changed = false;
|
|
2584
|
-
if (removeUpgradeScript(pkg2)) {
|
|
2585
|
-
console.log("[fullstack-cli] \u2713 Removed scripts.upgrade");
|
|
2586
|
-
changed = true;
|
|
2587
|
-
}
|
|
2588
|
-
if (cleanDevScript(pkg2)) {
|
|
2589
|
-
console.log("[fullstack-cli] \u2713 Cleaned scripts.dev (removed npm run upgrade)");
|
|
2590
|
-
changed = true;
|
|
2591
|
-
}
|
|
2592
|
-
if (changed) {
|
|
2593
|
-
writePackageJson(pkg2, cwd);
|
|
2594
|
-
}
|
|
2595
|
-
return changed;
|
|
2596
|
-
} catch (error) {
|
|
2597
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
2598
|
-
console.log(`[fullstack-cli] \u26A0 Could not cleanup package.json: ${message}`);
|
|
2599
|
-
return false;
|
|
2600
|
-
}
|
|
2601
|
-
}
|
|
2602
|
-
|
|
2603
2528
|
// src/commands/sync/run.handler.ts
|
|
2604
2529
|
async function run2(options) {
|
|
2605
2530
|
const userProjectRoot = process.env.INIT_CWD || process.cwd();
|
|
2606
2531
|
const __filename = fileURLToPath3(import.meta.url);
|
|
2607
|
-
const __dirname2 =
|
|
2608
|
-
const pluginRoot =
|
|
2532
|
+
const __dirname2 = path4.dirname(__filename);
|
|
2533
|
+
const pluginRoot = path4.resolve(__dirname2, "..");
|
|
2609
2534
|
if (userProjectRoot === pluginRoot) {
|
|
2610
2535
|
console.log("[fullstack-cli] Skip syncing (installing plugin itself)");
|
|
2611
2536
|
process.exit(0);
|
|
2612
2537
|
}
|
|
2613
|
-
const userPackageJson =
|
|
2614
|
-
if (!
|
|
2538
|
+
const userPackageJson = path4.join(userProjectRoot, "package.json");
|
|
2539
|
+
if (!fs6.existsSync(userPackageJson)) {
|
|
2615
2540
|
console.log("[fullstack-cli] Skip syncing (not a valid npm project)");
|
|
2616
2541
|
process.exit(0);
|
|
2617
2542
|
}
|
|
@@ -2627,7 +2552,6 @@ async function run2(options) {
|
|
|
2627
2552
|
for (const rule of config.sync) {
|
|
2628
2553
|
await syncRule(rule, pluginRoot, userProjectRoot);
|
|
2629
2554
|
}
|
|
2630
|
-
patchUserPackageJson(userProjectRoot);
|
|
2631
2555
|
if (config.permissions) {
|
|
2632
2556
|
setPermissions(config.permissions, userProjectRoot);
|
|
2633
2557
|
}
|
|
@@ -2638,32 +2562,9 @@ async function run2(options) {
|
|
|
2638
2562
|
process.exit(1);
|
|
2639
2563
|
}
|
|
2640
2564
|
}
|
|
2641
|
-
function patchUserPackageJson(userProjectRoot) {
|
|
2642
|
-
try {
|
|
2643
|
-
const pkg2 = readPackageJson(userProjectRoot);
|
|
2644
|
-
const lintPatchResult = patchLintScriptForFilesSupport(pkg2);
|
|
2645
|
-
if (lintPatchResult === "patched") {
|
|
2646
|
-
writePackageJson(pkg2, userProjectRoot);
|
|
2647
|
-
console.log("[fullstack-cli] \u2713 Patched scripts.lint to support --files");
|
|
2648
|
-
return;
|
|
2649
|
-
}
|
|
2650
|
-
if (lintPatchResult === "already-patched") {
|
|
2651
|
-
console.log("[fullstack-cli] \u25CB scripts.lint already supports --files");
|
|
2652
|
-
return;
|
|
2653
|
-
}
|
|
2654
|
-
if (lintPatchResult === "skipped-custom") {
|
|
2655
|
-
console.warn(
|
|
2656
|
-
"[fullstack-cli] \u26A0 Skipped patching scripts.lint because it has been customized"
|
|
2657
|
-
);
|
|
2658
|
-
}
|
|
2659
|
-
} catch (error) {
|
|
2660
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
2661
|
-
console.warn(`[fullstack-cli] \u26A0 Could not patch package.json: ${message}`);
|
|
2662
|
-
}
|
|
2663
|
-
}
|
|
2664
2565
|
async function syncRule(rule, pluginRoot, userProjectRoot) {
|
|
2665
2566
|
if (rule.type === "delete-file" || rule.type === "delete-directory") {
|
|
2666
|
-
const destPath2 =
|
|
2567
|
+
const destPath2 = path4.join(userProjectRoot, rule.to);
|
|
2667
2568
|
if (rule.type === "delete-file") {
|
|
2668
2569
|
deleteFile(destPath2);
|
|
2669
2570
|
} else {
|
|
@@ -2672,32 +2573,32 @@ async function syncRule(rule, pluginRoot, userProjectRoot) {
|
|
|
2672
2573
|
return;
|
|
2673
2574
|
}
|
|
2674
2575
|
if (rule.type === "remove-line") {
|
|
2675
|
-
const destPath2 =
|
|
2576
|
+
const destPath2 = path4.join(userProjectRoot, rule.to);
|
|
2676
2577
|
removeLineFromFile(destPath2, rule.pattern);
|
|
2677
2578
|
return;
|
|
2678
2579
|
}
|
|
2679
2580
|
if (rule.type === "add-script") {
|
|
2680
|
-
const packageJsonPath =
|
|
2581
|
+
const packageJsonPath = path4.join(userProjectRoot, "package.json");
|
|
2681
2582
|
addScript(packageJsonPath, rule.name, rule.command, rule.overwrite ?? false);
|
|
2682
2583
|
return;
|
|
2683
2584
|
}
|
|
2684
2585
|
if (rule.type === "add-line") {
|
|
2685
|
-
const destPath2 =
|
|
2586
|
+
const destPath2 = path4.join(userProjectRoot, rule.to);
|
|
2686
2587
|
addLineToFile(destPath2, rule.line);
|
|
2687
2588
|
return;
|
|
2688
2589
|
}
|
|
2689
2590
|
if (rule.type === "merge-json") {
|
|
2690
|
-
const srcPath2 =
|
|
2691
|
-
const destPath2 =
|
|
2591
|
+
const srcPath2 = path4.join(pluginRoot, rule.from);
|
|
2592
|
+
const destPath2 = path4.join(userProjectRoot, rule.to);
|
|
2692
2593
|
mergeJsonFile(srcPath2, destPath2, rule.arrayMerge);
|
|
2693
2594
|
return;
|
|
2694
2595
|
}
|
|
2695
2596
|
if (!("from" in rule)) {
|
|
2696
2597
|
return;
|
|
2697
2598
|
}
|
|
2698
|
-
const srcPath =
|
|
2699
|
-
const destPath =
|
|
2700
|
-
if (!
|
|
2599
|
+
const srcPath = path4.join(pluginRoot, rule.from);
|
|
2600
|
+
const destPath = path4.join(userProjectRoot, rule.to);
|
|
2601
|
+
if (!fs6.existsSync(srcPath)) {
|
|
2701
2602
|
console.warn(`[fullstack-cli] Source not found: ${rule.from}`);
|
|
2702
2603
|
return;
|
|
2703
2604
|
}
|
|
@@ -2714,68 +2615,68 @@ async function syncRule(rule, pluginRoot, userProjectRoot) {
|
|
|
2714
2615
|
}
|
|
2715
2616
|
}
|
|
2716
2617
|
function syncFile(src, dest, overwrite = true, onlyIfExists = false) {
|
|
2717
|
-
if (onlyIfExists && !
|
|
2718
|
-
console.log(`[fullstack-cli] \u25CB ${
|
|
2618
|
+
if (onlyIfExists && !fs6.existsSync(dest)) {
|
|
2619
|
+
console.log(`[fullstack-cli] \u25CB ${path4.basename(dest)} (skipped, target not exists)`);
|
|
2719
2620
|
return;
|
|
2720
2621
|
}
|
|
2721
|
-
const destDir =
|
|
2722
|
-
if (!
|
|
2723
|
-
|
|
2622
|
+
const destDir = path4.dirname(dest);
|
|
2623
|
+
if (!fs6.existsSync(destDir)) {
|
|
2624
|
+
fs6.mkdirSync(destDir, { recursive: true });
|
|
2724
2625
|
}
|
|
2725
|
-
if (
|
|
2726
|
-
console.log(`[fullstack-cli] \u25CB ${
|
|
2626
|
+
if (fs6.existsSync(dest) && !overwrite) {
|
|
2627
|
+
console.log(`[fullstack-cli] \u25CB ${path4.basename(dest)} (skipped, already exists)`);
|
|
2727
2628
|
return;
|
|
2728
2629
|
}
|
|
2729
|
-
|
|
2730
|
-
console.log(`[fullstack-cli] \u2713 ${
|
|
2630
|
+
fs6.copyFileSync(src, dest);
|
|
2631
|
+
console.log(`[fullstack-cli] \u2713 ${path4.basename(dest)}`);
|
|
2731
2632
|
}
|
|
2732
2633
|
function syncDirectory(src, dest, overwrite = true) {
|
|
2733
|
-
if (!
|
|
2734
|
-
|
|
2634
|
+
if (!fs6.existsSync(dest)) {
|
|
2635
|
+
fs6.mkdirSync(dest, { recursive: true });
|
|
2735
2636
|
}
|
|
2736
|
-
const files =
|
|
2637
|
+
const files = fs6.readdirSync(src);
|
|
2737
2638
|
let count = 0;
|
|
2738
2639
|
files.forEach((file) => {
|
|
2739
|
-
const srcFile =
|
|
2740
|
-
const destFile =
|
|
2741
|
-
const stats =
|
|
2640
|
+
const srcFile = path4.join(src, file);
|
|
2641
|
+
const destFile = path4.join(dest, file);
|
|
2642
|
+
const stats = fs6.statSync(srcFile);
|
|
2742
2643
|
if (stats.isDirectory()) {
|
|
2743
2644
|
syncDirectory(srcFile, destFile, overwrite);
|
|
2744
2645
|
} else {
|
|
2745
|
-
if (overwrite || !
|
|
2746
|
-
|
|
2747
|
-
console.log(`[fullstack-cli] \u2713 ${
|
|
2646
|
+
if (overwrite || !fs6.existsSync(destFile)) {
|
|
2647
|
+
fs6.copyFileSync(srcFile, destFile);
|
|
2648
|
+
console.log(`[fullstack-cli] \u2713 ${path4.relative(dest, destFile)}`);
|
|
2748
2649
|
count++;
|
|
2749
2650
|
}
|
|
2750
2651
|
}
|
|
2751
2652
|
});
|
|
2752
2653
|
if (count > 0) {
|
|
2753
|
-
console.log(`[fullstack-cli] Synced ${count} files to ${
|
|
2654
|
+
console.log(`[fullstack-cli] Synced ${count} files to ${path4.basename(dest)}/`);
|
|
2754
2655
|
}
|
|
2755
2656
|
}
|
|
2756
2657
|
function appendToFile(src, dest) {
|
|
2757
|
-
const content =
|
|
2658
|
+
const content = fs6.readFileSync(src, "utf-8");
|
|
2758
2659
|
let existingContent = "";
|
|
2759
|
-
if (
|
|
2760
|
-
existingContent =
|
|
2660
|
+
if (fs6.existsSync(dest)) {
|
|
2661
|
+
existingContent = fs6.readFileSync(dest, "utf-8");
|
|
2761
2662
|
}
|
|
2762
2663
|
if (existingContent.includes(content.trim())) {
|
|
2763
|
-
console.log(`[fullstack-cli] \u25CB ${
|
|
2664
|
+
console.log(`[fullstack-cli] \u25CB ${path4.basename(dest)} (already contains content)`);
|
|
2764
2665
|
return;
|
|
2765
2666
|
}
|
|
2766
|
-
|
|
2767
|
-
console.log(`[fullstack-cli] \u2713 ${
|
|
2667
|
+
fs6.appendFileSync(dest, content);
|
|
2668
|
+
console.log(`[fullstack-cli] \u2713 ${path4.basename(dest)} (appended)`);
|
|
2768
2669
|
}
|
|
2769
2670
|
function setPermissions(permissions, projectRoot) {
|
|
2770
2671
|
for (const [pattern, mode] of Object.entries(permissions)) {
|
|
2771
2672
|
if (pattern === "**/*.sh") {
|
|
2772
|
-
const scriptsDir =
|
|
2773
|
-
if (
|
|
2774
|
-
const files =
|
|
2673
|
+
const scriptsDir = path4.join(projectRoot, "scripts");
|
|
2674
|
+
if (fs6.existsSync(scriptsDir)) {
|
|
2675
|
+
const files = fs6.readdirSync(scriptsDir);
|
|
2775
2676
|
files.forEach((file) => {
|
|
2776
2677
|
if (file.endsWith(".sh")) {
|
|
2777
|
-
const filePath =
|
|
2778
|
-
|
|
2678
|
+
const filePath = path4.join(scriptsDir, file);
|
|
2679
|
+
fs6.chmodSync(filePath, mode);
|
|
2779
2680
|
}
|
|
2780
2681
|
});
|
|
2781
2682
|
}
|
|
@@ -2783,27 +2684,27 @@ function setPermissions(permissions, projectRoot) {
|
|
|
2783
2684
|
}
|
|
2784
2685
|
}
|
|
2785
2686
|
function deleteFile(filePath) {
|
|
2786
|
-
if (
|
|
2787
|
-
|
|
2788
|
-
console.log(`[fullstack-cli] \u2713 ${
|
|
2687
|
+
if (fs6.existsSync(filePath)) {
|
|
2688
|
+
fs6.unlinkSync(filePath);
|
|
2689
|
+
console.log(`[fullstack-cli] \u2713 ${path4.basename(filePath)} (deleted)`);
|
|
2789
2690
|
} else {
|
|
2790
|
-
console.log(`[fullstack-cli] \u25CB ${
|
|
2691
|
+
console.log(`[fullstack-cli] \u25CB ${path4.basename(filePath)} (not found)`);
|
|
2791
2692
|
}
|
|
2792
2693
|
}
|
|
2793
2694
|
function deleteDirectory(dirPath) {
|
|
2794
|
-
if (
|
|
2795
|
-
|
|
2796
|
-
console.log(`[fullstack-cli] \u2713 ${
|
|
2695
|
+
if (fs6.existsSync(dirPath)) {
|
|
2696
|
+
fs6.rmSync(dirPath, { recursive: true });
|
|
2697
|
+
console.log(`[fullstack-cli] \u2713 ${path4.basename(dirPath)} (deleted)`);
|
|
2797
2698
|
} else {
|
|
2798
|
-
console.log(`[fullstack-cli] \u25CB ${
|
|
2699
|
+
console.log(`[fullstack-cli] \u25CB ${path4.basename(dirPath)} (not found)`);
|
|
2799
2700
|
}
|
|
2800
2701
|
}
|
|
2801
2702
|
function addScript(packageJsonPath, name, command, overwrite) {
|
|
2802
|
-
if (!
|
|
2703
|
+
if (!fs6.existsSync(packageJsonPath)) {
|
|
2803
2704
|
console.log(`[fullstack-cli] \u25CB package.json (not found)`);
|
|
2804
2705
|
return;
|
|
2805
2706
|
}
|
|
2806
|
-
const content =
|
|
2707
|
+
const content = fs6.readFileSync(packageJsonPath, "utf-8");
|
|
2807
2708
|
const pkg2 = JSON.parse(content);
|
|
2808
2709
|
if (!pkg2.scripts) {
|
|
2809
2710
|
pkg2.scripts = {};
|
|
@@ -2815,42 +2716,42 @@ function addScript(packageJsonPath, name, command, overwrite) {
|
|
|
2815
2716
|
}
|
|
2816
2717
|
}
|
|
2817
2718
|
pkg2.scripts[name] = command;
|
|
2818
|
-
|
|
2719
|
+
fs6.writeFileSync(packageJsonPath, JSON.stringify(pkg2, null, 2) + "\n");
|
|
2819
2720
|
console.log(`[fullstack-cli] \u2713 scripts.${name}`);
|
|
2820
2721
|
}
|
|
2821
2722
|
function addLineToFile(filePath, line) {
|
|
2822
|
-
const fileName =
|
|
2823
|
-
if (!
|
|
2723
|
+
const fileName = path4.basename(filePath);
|
|
2724
|
+
if (!fs6.existsSync(filePath)) {
|
|
2824
2725
|
console.log(`[fullstack-cli] \u25CB ${fileName} (not found, skipped)`);
|
|
2825
2726
|
return;
|
|
2826
2727
|
}
|
|
2827
|
-
const content =
|
|
2728
|
+
const content = fs6.readFileSync(filePath, "utf-8");
|
|
2828
2729
|
const lines = content.split("\n").map((l) => l.trim());
|
|
2829
2730
|
if (lines.includes(line)) {
|
|
2830
2731
|
console.log(`[fullstack-cli] \u25CB ${fileName} (line already exists: ${line})`);
|
|
2831
2732
|
return;
|
|
2832
2733
|
}
|
|
2833
2734
|
const appendContent = (content.endsWith("\n") ? "" : "\n") + line + "\n";
|
|
2834
|
-
|
|
2735
|
+
fs6.appendFileSync(filePath, appendContent);
|
|
2835
2736
|
console.log(`[fullstack-cli] \u2713 ${fileName} (added: ${line})`);
|
|
2836
2737
|
}
|
|
2837
2738
|
function mergeJsonFile(src, dest, arrayMerge) {
|
|
2838
|
-
const fileName =
|
|
2839
|
-
if (!
|
|
2739
|
+
const fileName = path4.basename(dest);
|
|
2740
|
+
if (!fs6.existsSync(src)) {
|
|
2840
2741
|
console.warn(`[fullstack-cli] Source not found: ${src}`);
|
|
2841
2742
|
return;
|
|
2842
2743
|
}
|
|
2843
|
-
const templateContent = JSON.parse(
|
|
2844
|
-
if (!
|
|
2845
|
-
const destDir =
|
|
2846
|
-
if (!
|
|
2847
|
-
|
|
2744
|
+
const templateContent = JSON.parse(fs6.readFileSync(src, "utf-8"));
|
|
2745
|
+
if (!fs6.existsSync(dest)) {
|
|
2746
|
+
const destDir = path4.dirname(dest);
|
|
2747
|
+
if (!fs6.existsSync(destDir)) {
|
|
2748
|
+
fs6.mkdirSync(destDir, { recursive: true });
|
|
2848
2749
|
}
|
|
2849
|
-
|
|
2750
|
+
fs6.writeFileSync(dest, JSON.stringify(templateContent, null, 2) + "\n");
|
|
2850
2751
|
console.log(`[fullstack-cli] \u2713 ${fileName} (created)`);
|
|
2851
2752
|
return;
|
|
2852
2753
|
}
|
|
2853
|
-
const userContent = JSON.parse(
|
|
2754
|
+
const userContent = JSON.parse(fs6.readFileSync(dest, "utf-8"));
|
|
2854
2755
|
const merged = deepMergeJson(userContent, templateContent, arrayMerge ?? {});
|
|
2855
2756
|
const userStr = JSON.stringify(userContent, null, 2);
|
|
2856
2757
|
const mergedStr = JSON.stringify(merged, null, 2);
|
|
@@ -2858,7 +2759,7 @@ function mergeJsonFile(src, dest, arrayMerge) {
|
|
|
2858
2759
|
console.log(`[fullstack-cli] \u25CB ${fileName} (already up to date)`);
|
|
2859
2760
|
return;
|
|
2860
2761
|
}
|
|
2861
|
-
|
|
2762
|
+
fs6.writeFileSync(dest, mergedStr + "\n");
|
|
2862
2763
|
console.log(`[fullstack-cli] \u2713 ${fileName} (merged)`);
|
|
2863
2764
|
}
|
|
2864
2765
|
|
|
@@ -2919,12 +2820,12 @@ async function reportCreateInstanceEvent(pluginKey, version) {
|
|
|
2919
2820
|
|
|
2920
2821
|
// src/utils/git.ts
|
|
2921
2822
|
import { execSync, spawnSync as spawnSync2 } from "child_process";
|
|
2922
|
-
import
|
|
2923
|
-
import
|
|
2823
|
+
import fs7 from "fs";
|
|
2824
|
+
import path5 from "path";
|
|
2924
2825
|
function isGitRepository(cwd = process.cwd()) {
|
|
2925
2826
|
try {
|
|
2926
|
-
const gitDir =
|
|
2927
|
-
if (
|
|
2827
|
+
const gitDir = path5.join(cwd, ".git");
|
|
2828
|
+
if (fs7.existsSync(gitDir)) {
|
|
2928
2829
|
return true;
|
|
2929
2830
|
}
|
|
2930
2831
|
const result = spawnSync2("git", ["rev-parse", "--git-dir"], {
|
|
@@ -2953,7 +2854,7 @@ function getChangedFiles(cwd = process.cwd()) {
|
|
|
2953
2854
|
function gitAddUpgradeFiles(cwd = process.cwd(), filesToStage) {
|
|
2954
2855
|
const filteredFiles = [];
|
|
2955
2856
|
for (const filePath of filesToStage) {
|
|
2956
|
-
if (
|
|
2857
|
+
if (fs7.existsSync(path5.join(cwd, filePath))) {
|
|
2957
2858
|
filteredFiles.push(filePath);
|
|
2958
2859
|
continue;
|
|
2959
2860
|
}
|
|
@@ -3037,6 +2938,64 @@ Auto-committed by fullstack-cli`;
|
|
|
3037
2938
|
}
|
|
3038
2939
|
}
|
|
3039
2940
|
|
|
2941
|
+
// src/utils/package-json.ts
|
|
2942
|
+
import fs8 from "fs";
|
|
2943
|
+
import path6 from "path";
|
|
2944
|
+
function readPackageJson(cwd = process.cwd()) {
|
|
2945
|
+
const pkgPath = path6.join(cwd, "package.json");
|
|
2946
|
+
if (!fs8.existsSync(pkgPath)) {
|
|
2947
|
+
throw new Error(`package.json not found at ${pkgPath}`);
|
|
2948
|
+
}
|
|
2949
|
+
const content = fs8.readFileSync(pkgPath, "utf-8");
|
|
2950
|
+
return JSON.parse(content);
|
|
2951
|
+
}
|
|
2952
|
+
function writePackageJson(pkg2, cwd = process.cwd()) {
|
|
2953
|
+
const pkgPath = path6.join(cwd, "package.json");
|
|
2954
|
+
const content = JSON.stringify(pkg2, null, 2) + "\n";
|
|
2955
|
+
fs8.writeFileSync(pkgPath, content, "utf-8");
|
|
2956
|
+
}
|
|
2957
|
+
function removeUpgradeScript(pkg2) {
|
|
2958
|
+
if (!pkg2.scripts?.upgrade) {
|
|
2959
|
+
return false;
|
|
2960
|
+
}
|
|
2961
|
+
delete pkg2.scripts.upgrade;
|
|
2962
|
+
return true;
|
|
2963
|
+
}
|
|
2964
|
+
function cleanDevScript(pkg2) {
|
|
2965
|
+
if (!pkg2.scripts?.dev) {
|
|
2966
|
+
return false;
|
|
2967
|
+
}
|
|
2968
|
+
const originalDev = pkg2.scripts.dev;
|
|
2969
|
+
const cleanedDev = originalDev.replace(/npm\s+run\s+upgrade\s*&&\s*/g, "").replace(/npm\s+run\s+upgrade\s*$/g, "").trim();
|
|
2970
|
+
if (cleanedDev !== originalDev) {
|
|
2971
|
+
pkg2.scripts.dev = cleanedDev;
|
|
2972
|
+
return true;
|
|
2973
|
+
}
|
|
2974
|
+
return false;
|
|
2975
|
+
}
|
|
2976
|
+
function cleanupPackageJson(cwd = process.cwd()) {
|
|
2977
|
+
try {
|
|
2978
|
+
const pkg2 = readPackageJson(cwd);
|
|
2979
|
+
let changed = false;
|
|
2980
|
+
if (removeUpgradeScript(pkg2)) {
|
|
2981
|
+
console.log("[fullstack-cli] \u2713 Removed scripts.upgrade");
|
|
2982
|
+
changed = true;
|
|
2983
|
+
}
|
|
2984
|
+
if (cleanDevScript(pkg2)) {
|
|
2985
|
+
console.log("[fullstack-cli] \u2713 Cleaned scripts.dev (removed npm run upgrade)");
|
|
2986
|
+
changed = true;
|
|
2987
|
+
}
|
|
2988
|
+
if (changed) {
|
|
2989
|
+
writePackageJson(pkg2, cwd);
|
|
2990
|
+
}
|
|
2991
|
+
return changed;
|
|
2992
|
+
} catch (error) {
|
|
2993
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2994
|
+
console.log(`[fullstack-cli] \u26A0 Could not cleanup package.json: ${message}`);
|
|
2995
|
+
return false;
|
|
2996
|
+
}
|
|
2997
|
+
}
|
|
2998
|
+
|
|
3040
2999
|
// src/commands/upgrade/shared/utils.ts
|
|
3041
3000
|
import path7 from "path";
|
|
3042
3001
|
import fs9 from "fs";
|
package/package.json
CHANGED
|
@@ -19,28 +19,64 @@ print_time() {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
# ==================== 步骤 0 ====================
|
|
22
|
-
echo "🗑️ [0/
|
|
22
|
+
echo "🗑️ [0/7] 安装插件"
|
|
23
23
|
STEP_START=$(node -e "console.log(Date.now())")
|
|
24
24
|
npx fullstack-cli action-plugin init
|
|
25
25
|
print_time $STEP_START
|
|
26
26
|
echo ""
|
|
27
27
|
|
|
28
28
|
# ==================== 步骤 1 ====================
|
|
29
|
-
echo "📝 [1/
|
|
29
|
+
echo "📝 [1/7] 更新 openapi 代码"
|
|
30
30
|
STEP_START=$(node -e "console.log(Date.now())")
|
|
31
31
|
npm run gen:openapi
|
|
32
32
|
print_time $STEP_START
|
|
33
33
|
echo ""
|
|
34
34
|
|
|
35
35
|
# ==================== 步骤 2 ====================
|
|
36
|
-
echo "🗑️ [2/
|
|
36
|
+
echo "🗑️ [2/7] 清理 dist 目录"
|
|
37
37
|
STEP_START=$(node -e "console.log(Date.now())")
|
|
38
38
|
rm -rf "$ROOT_DIR/dist"
|
|
39
39
|
print_time $STEP_START
|
|
40
40
|
echo ""
|
|
41
41
|
|
|
42
42
|
# ==================== 步骤 3 ====================
|
|
43
|
-
echo "
|
|
43
|
+
echo "🗺️ [3/7] 生成路由定义"
|
|
44
|
+
STEP_START=$(node -e "console.log(Date.now())")
|
|
45
|
+
|
|
46
|
+
# 在 client/server 构建之前生成到 dist/,供 DefinePlugin 注入前端 bundle
|
|
47
|
+
# 注意:nest-cli.json 中 deleteOutDir 必须为 false(模板默认值),否则 nest build 会清掉 dist/
|
|
48
|
+
echo " ├─ 生成 API 路由定义..."
|
|
49
|
+
npx generate-api-routes --server-dir ./server --out-dir ./dist > /tmp/gen-api-routes.log 2>&1 &
|
|
50
|
+
API_ROUTES_PID=$!
|
|
51
|
+
|
|
52
|
+
echo " ├─ 生成页面路由定义..."
|
|
53
|
+
npx generate-page-routes --app-path ./client/src/app.tsx --out-dir ./dist > /tmp/gen-page-routes.log 2>&1 &
|
|
54
|
+
PAGE_ROUTES_PID=$!
|
|
55
|
+
|
|
56
|
+
API_ROUTES_EXIT=0
|
|
57
|
+
PAGE_ROUTES_EXIT=0
|
|
58
|
+
|
|
59
|
+
wait $API_ROUTES_PID || API_ROUTES_EXIT=$?
|
|
60
|
+
wait $PAGE_ROUTES_PID || PAGE_ROUTES_EXIT=$?
|
|
61
|
+
|
|
62
|
+
if [ $API_ROUTES_EXIT -ne 0 ]; then
|
|
63
|
+
echo " ⚠️ API 路由生成失败(不影响构建)"
|
|
64
|
+
cat /tmp/gen-api-routes.log
|
|
65
|
+
else
|
|
66
|
+
echo " ✅ API 路由生成完成"
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
if [ $PAGE_ROUTES_EXIT -ne 0 ]; then
|
|
70
|
+
echo " ⚠️ 页面路由生成失败(不影响构建)"
|
|
71
|
+
cat /tmp/gen-page-routes.log
|
|
72
|
+
else
|
|
73
|
+
echo " ✅ 页面路由生成完成"
|
|
74
|
+
fi
|
|
75
|
+
print_time $STEP_START
|
|
76
|
+
echo ""
|
|
77
|
+
|
|
78
|
+
# ==================== 步骤 4 ====================
|
|
79
|
+
echo "🔨 [4/7] 并行构建 server 和 client"
|
|
44
80
|
STEP_START=$(node -e "console.log(Date.now())")
|
|
45
81
|
|
|
46
82
|
# 并行构建
|
|
@@ -77,8 +113,8 @@ echo " ✅ Client 构建完成"
|
|
|
77
113
|
print_time $STEP_START
|
|
78
114
|
echo ""
|
|
79
115
|
|
|
80
|
-
# ==================== 步骤
|
|
81
|
-
echo "📦 [
|
|
116
|
+
# ==================== 步骤 5 ====================
|
|
117
|
+
echo "📦 [5/7] 准备产物"
|
|
82
118
|
STEP_START=$(node -e "console.log(Date.now())")
|
|
83
119
|
|
|
84
120
|
# 拷贝 run.sh 到 dist/(prod 从 dist/ 启动,确保 cwd 一致性)
|
|
@@ -102,8 +138,8 @@ rm -rf "$DIST_DIR/tsconfig.node.tsbuildinfo"
|
|
|
102
138
|
print_time $STEP_START
|
|
103
139
|
echo ""
|
|
104
140
|
|
|
105
|
-
# ==================== 步骤
|
|
106
|
-
echo "✂️ [
|
|
141
|
+
# ==================== 步骤 6 ====================
|
|
142
|
+
echo "✂️ [6/7] 智能依赖裁剪"
|
|
107
143
|
STEP_START=$(node -e "console.log(Date.now())")
|
|
108
144
|
|
|
109
145
|
# 分析实际依赖、复制并裁剪 node_modules、生成精简的 package.json
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const path = require('node:path');
|
|
4
|
-
const { spawn } = require('node:child_process');
|
|
5
|
-
const fs = require('node:fs');
|
|
6
|
-
|
|
7
|
-
const cwd = process.cwd();
|
|
8
|
-
|
|
9
|
-
function getBinName(name) {
|
|
10
|
-
return process.platform === 'win32' ? `${name}.cmd` : name;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function runCommand(command, args) {
|
|
14
|
-
return new Promise((resolve) => {
|
|
15
|
-
const child = spawn(command, args, {
|
|
16
|
-
cwd,
|
|
17
|
-
stdio: 'inherit',
|
|
18
|
-
shell: false,
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
child.on('close', (code) => resolve(code || 0));
|
|
22
|
-
child.on('error', () => resolve(1));
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function normalizeProjectFile(filePath) {
|
|
27
|
-
const absolutePath = path.isAbsolute(filePath)
|
|
28
|
-
? filePath
|
|
29
|
-
: path.resolve(cwd, filePath);
|
|
30
|
-
|
|
31
|
-
if (!fs.existsSync(absolutePath)) {
|
|
32
|
-
console.warn(`[lint] Skip missing file: ${filePath}`);
|
|
33
|
-
return null;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const relativePath = path.relative(cwd, absolutePath);
|
|
37
|
-
if (relativePath.startsWith('..')) {
|
|
38
|
-
console.warn(`[lint] Skip file outside project: ${filePath}`);
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return relativePath.split(path.sep).join('/');
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function parseFilesArg(argv) {
|
|
46
|
-
const filesIndex = argv.indexOf('--files');
|
|
47
|
-
if (filesIndex === -1) {
|
|
48
|
-
return null;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return argv.slice(filesIndex + 1).filter(Boolean);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function isEslintTarget(filePath) {
|
|
55
|
-
return /\.(c|m)?(j|t)sx?$/.test(filePath);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function isTypeCheckTarget(filePath) {
|
|
59
|
-
return /\.(ts|tsx|mts|cts)$/.test(filePath);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function isStylelintTarget(filePath) {
|
|
63
|
-
return filePath.endsWith('.css');
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
async function runDefaultLint() {
|
|
67
|
-
const code = await runCommand(getBinName('npx'), [
|
|
68
|
-
'concurrently',
|
|
69
|
-
'npm run eslint',
|
|
70
|
-
'npm run type:check',
|
|
71
|
-
'npm run stylelint',
|
|
72
|
-
]);
|
|
73
|
-
process.exit(code);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
async function runSelectiveLint(inputFiles) {
|
|
77
|
-
const normalizedFiles = Array.from(
|
|
78
|
-
new Set(inputFiles.map(normalizeProjectFile).filter(Boolean)),
|
|
79
|
-
);
|
|
80
|
-
|
|
81
|
-
if (normalizedFiles.length === 0) {
|
|
82
|
-
console.log('[lint] No supported project files found');
|
|
83
|
-
process.exit(0);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const eslintFiles = normalizedFiles.filter(isEslintTarget);
|
|
87
|
-
const stylelintFiles = normalizedFiles.filter(isStylelintTarget);
|
|
88
|
-
const typeCheckFiles = normalizedFiles.filter(isTypeCheckTarget);
|
|
89
|
-
|
|
90
|
-
const clientTypeFiles = [];
|
|
91
|
-
const serverTypeFiles = [];
|
|
92
|
-
|
|
93
|
-
for (const filePath of typeCheckFiles) {
|
|
94
|
-
if (filePath.startsWith('client/')) {
|
|
95
|
-
clientTypeFiles.push(filePath);
|
|
96
|
-
} else if (filePath.startsWith('server/')) {
|
|
97
|
-
serverTypeFiles.push(filePath);
|
|
98
|
-
} else if (filePath.startsWith('shared/')) {
|
|
99
|
-
clientTypeFiles.push(filePath);
|
|
100
|
-
serverTypeFiles.push(filePath);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const tasks = [];
|
|
105
|
-
|
|
106
|
-
if (eslintFiles.length > 0) {
|
|
107
|
-
tasks.push(runCommand(getBinName('npx'), ['eslint', '--quiet', ...eslintFiles]));
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
if (stylelintFiles.length > 0) {
|
|
111
|
-
tasks.push(runCommand(getBinName('npx'), ['stylelint', '--quiet', ...stylelintFiles]));
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (clientTypeFiles.length > 0) {
|
|
115
|
-
tasks.push(runCommand(getBinName('npm'), ['run', 'type:check:client']));
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if (serverTypeFiles.length > 0) {
|
|
119
|
-
tasks.push(runCommand(getBinName('npm'), ['run', 'type:check:server']));
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
if (tasks.length === 0) {
|
|
123
|
-
console.log('[lint] No supported files matched for lint');
|
|
124
|
-
process.exit(0);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const results = await Promise.all(tasks);
|
|
128
|
-
process.exit(results.some(code => code !== 0) ? 1 : 0);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
async function main() {
|
|
132
|
-
const files = parseFilesArg(process.argv.slice(2));
|
|
133
|
-
if (files === null) {
|
|
134
|
-
await runDefaultLint();
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
if (files.length === 0) {
|
|
139
|
-
console.error('[lint] --files requires at least one file path');
|
|
140
|
-
process.exit(1);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
await runSelectiveLint(files);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
main().catch((error) => {
|
|
147
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
148
|
-
console.error(`[lint] Failed to run lint: ${message}`);
|
|
149
|
-
process.exit(1);
|
|
150
|
-
});
|