@raftlabs/raftstack 1.4.2 → 1.5.0
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/cli.js +334 -196
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -484,35 +484,19 @@ function fileExists(filePath) {
|
|
|
484
484
|
}
|
|
485
485
|
|
|
486
486
|
// src/generators/husky.ts
|
|
487
|
-
function getPreCommitHook(
|
|
488
|
-
|
|
489
|
-
return `#!/usr/bin/env sh
|
|
490
|
-
. "$(dirname -- "$0")/_/husky.sh"
|
|
491
|
-
|
|
492
|
-
${pm.exec} lint-staged
|
|
493
|
-
`;
|
|
494
|
-
}
|
|
495
|
-
return `#!/usr/bin/env sh
|
|
496
|
-
. "$(dirname -- "$0")/_/husky.sh"
|
|
497
|
-
|
|
498
|
-
${pm.exec} lint-staged
|
|
487
|
+
function getPreCommitHook(_projectType) {
|
|
488
|
+
return `lint-staged
|
|
499
489
|
`;
|
|
500
490
|
}
|
|
501
|
-
function getCommitMsgHook(
|
|
502
|
-
return
|
|
503
|
-
. "$(dirname -- "$0")/_/husky.sh"
|
|
504
|
-
|
|
505
|
-
${pm.exec} --no -- commitlint --edit "$1"
|
|
491
|
+
function getCommitMsgHook() {
|
|
492
|
+
return `commitlint --edit "$1"
|
|
506
493
|
`;
|
|
507
494
|
}
|
|
508
|
-
function getPrePushHook(
|
|
509
|
-
return
|
|
510
|
-
. "$(dirname -- "$0")/_/husky.sh"
|
|
511
|
-
|
|
512
|
-
${pm.exec} validate-branch-name
|
|
495
|
+
function getPrePushHook() {
|
|
496
|
+
return `validate-branch-name
|
|
513
497
|
`;
|
|
514
498
|
}
|
|
515
|
-
async function generateHuskyHooks(targetDir, projectType,
|
|
499
|
+
async function generateHuskyHooks(targetDir, projectType, _pm) {
|
|
516
500
|
const result = {
|
|
517
501
|
created: [],
|
|
518
502
|
modified: [],
|
|
@@ -524,7 +508,7 @@ async function generateHuskyHooks(targetDir, projectType, pm) {
|
|
|
524
508
|
const preCommitPath = join4(huskyDir, "pre-commit");
|
|
525
509
|
const preCommitResult = await writeFileSafe(
|
|
526
510
|
preCommitPath,
|
|
527
|
-
getPreCommitHook(projectType
|
|
511
|
+
getPreCommitHook(projectType),
|
|
528
512
|
{ executable: true, backup: true }
|
|
529
513
|
);
|
|
530
514
|
if (preCommitResult.created) {
|
|
@@ -536,7 +520,7 @@ async function generateHuskyHooks(targetDir, projectType, pm) {
|
|
|
536
520
|
const commitMsgPath = join4(huskyDir, "commit-msg");
|
|
537
521
|
const commitMsgResult = await writeFileSafe(
|
|
538
522
|
commitMsgPath,
|
|
539
|
-
getCommitMsgHook(
|
|
523
|
+
getCommitMsgHook(),
|
|
540
524
|
{ executable: true, backup: true }
|
|
541
525
|
);
|
|
542
526
|
if (commitMsgResult.created) {
|
|
@@ -546,7 +530,7 @@ async function generateHuskyHooks(targetDir, projectType, pm) {
|
|
|
546
530
|
}
|
|
547
531
|
}
|
|
548
532
|
const prePushPath = join4(huskyDir, "pre-push");
|
|
549
|
-
const prePushResult = await writeFileSafe(prePushPath, getPrePushHook(
|
|
533
|
+
const prePushResult = await writeFileSafe(prePushPath, getPrePushHook(), {
|
|
550
534
|
executable: true,
|
|
551
535
|
backup: true
|
|
552
536
|
});
|
|
@@ -562,10 +546,8 @@ async function generateHuskyHooks(targetDir, projectType, pm) {
|
|
|
562
546
|
// src/generators/commitlint.ts
|
|
563
547
|
import { join as join5 } from "path";
|
|
564
548
|
function getCommitlintConfig(asanaBaseUrl) {
|
|
565
|
-
const baseConfig =
|
|
566
|
-
|
|
567
|
-
/** @type {import('@commitlint/types').UserConfig} */
|
|
568
|
-
const config = {
|
|
549
|
+
const baseConfig = `/** @type {import('@commitlint/types').UserConfig} */
|
|
550
|
+
export default {
|
|
569
551
|
extends: ['@commitlint/config-conventional'],
|
|
570
552
|
rules: {
|
|
571
553
|
// Type must be one of the conventional types
|
|
@@ -593,10 +575,12 @@ const config = {
|
|
|
593
575
|
// Subject should be lowercase
|
|
594
576
|
'subject-case': [2, 'always', 'lower-case'],
|
|
595
577
|
// Header max length
|
|
596
|
-
'header-max-length': [2, 'always', 100]
|
|
597
|
-
},`;
|
|
578
|
+
'header-max-length': [2, 'always', 100],`;
|
|
598
579
|
if (asanaBaseUrl) {
|
|
599
580
|
return `${baseConfig}
|
|
581
|
+
// Asana task link (warning only - won't block commits)
|
|
582
|
+
'asana-task-link': [1, 'always'],
|
|
583
|
+
},
|
|
600
584
|
plugins: [
|
|
601
585
|
{
|
|
602
586
|
rules: {
|
|
@@ -615,18 +599,11 @@ const config = {
|
|
|
615
599
|
},
|
|
616
600
|
],
|
|
617
601
|
};
|
|
618
|
-
|
|
619
|
-
// Enable the Asana task link rule as a WARNING (level 1)
|
|
620
|
-
// Change to level 2 if you want to BLOCK commits without Asana links
|
|
621
|
-
config.rules['asana-task-link'] = [1, 'always'];
|
|
622
|
-
|
|
623
|
-
module.exports = config;
|
|
624
602
|
`;
|
|
625
603
|
}
|
|
626
604
|
return `${baseConfig}
|
|
605
|
+
},
|
|
627
606
|
};
|
|
628
|
-
|
|
629
|
-
module.exports = config;
|
|
630
607
|
`;
|
|
631
608
|
}
|
|
632
609
|
async function generateCommitlint(targetDir, asanaBaseUrl) {
|
|
@@ -763,92 +740,36 @@ async function generateCzGit(targetDir, asanaBaseUrl) {
|
|
|
763
740
|
}
|
|
764
741
|
|
|
765
742
|
// src/generators/lint-staged.ts
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
const
|
|
743
|
+
function getLintStagedConfig(usesEslint, usesPrettier, usesTypeScript) {
|
|
744
|
+
const config = {};
|
|
745
|
+
const codePatterns = [];
|
|
769
746
|
if (usesTypeScript) {
|
|
770
|
-
|
|
771
|
-
if (usesEslint) {
|
|
772
|
-
tsCommands.push("eslint --fix");
|
|
773
|
-
}
|
|
774
|
-
if (usesPrettier) {
|
|
775
|
-
tsCommands.push("prettier --write");
|
|
776
|
-
}
|
|
777
|
-
if (tsCommands.length > 0) {
|
|
778
|
-
rules["*.{ts,tsx}"] = tsCommands;
|
|
779
|
-
}
|
|
747
|
+
codePatterns.push("ts", "mts", "cts", "tsx");
|
|
780
748
|
}
|
|
781
|
-
|
|
749
|
+
codePatterns.push("js", "mjs", "cjs", "jsx");
|
|
750
|
+
const codeCommands = [];
|
|
782
751
|
if (usesEslint) {
|
|
783
|
-
|
|
752
|
+
codeCommands.push("eslint --fix");
|
|
784
753
|
}
|
|
785
754
|
if (usesPrettier) {
|
|
786
|
-
|
|
755
|
+
codeCommands.push("prettier --write");
|
|
787
756
|
}
|
|
788
|
-
if (
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
if (usesPrettier) {
|
|
792
|
-
rules["*.{json,md,yaml,yml}"] = "prettier --write";
|
|
757
|
+
if (codeCommands.length > 0) {
|
|
758
|
+
const pattern = `*.{${codePatterns.join(",")}}`;
|
|
759
|
+
config[pattern] = codeCommands;
|
|
793
760
|
}
|
|
794
761
|
if (usesPrettier) {
|
|
795
|
-
|
|
762
|
+
config["*.{json,css,md}"] = ["prettier --write"];
|
|
796
763
|
}
|
|
797
|
-
|
|
798
|
-
return `// @ts-check
|
|
799
|
-
|
|
800
|
-
/**
|
|
801
|
-
* @type {import('lint-staged').Config}
|
|
802
|
-
*/
|
|
803
|
-
module.exports = {
|
|
804
|
-
${Object.entries(rules).map(([pattern, commands]) => {
|
|
805
|
-
const cmdStr = Array.isArray(commands) ? JSON.stringify(commands) : JSON.stringify([commands]);
|
|
806
|
-
return ` '${pattern}': ${cmdStr},`;
|
|
807
|
-
}).join("\n")}
|
|
808
|
-
};
|
|
809
|
-
`;
|
|
810
|
-
}
|
|
811
|
-
return `// @ts-check
|
|
812
|
-
|
|
813
|
-
/**
|
|
814
|
-
* @type {import('lint-staged').Config}
|
|
815
|
-
*/
|
|
816
|
-
module.exports = {
|
|
817
|
-
${Object.entries(rules).map(([pattern, commands]) => {
|
|
818
|
-
const cmdStr = Array.isArray(commands) ? JSON.stringify(commands) : JSON.stringify([commands]);
|
|
819
|
-
return ` '${pattern}': ${cmdStr},`;
|
|
820
|
-
}).join("\n")}
|
|
821
|
-
};
|
|
822
|
-
`;
|
|
823
|
-
}
|
|
824
|
-
async function generateLintStaged(targetDir, projectType, usesEslint, usesPrettier, usesTypeScript) {
|
|
825
|
-
const result = {
|
|
826
|
-
created: [],
|
|
827
|
-
modified: [],
|
|
828
|
-
skipped: [],
|
|
829
|
-
backedUp: []
|
|
830
|
-
};
|
|
831
|
-
const configPath = join7(targetDir, ".lintstagedrc.js");
|
|
832
|
-
const writeResult = await writeFileSafe(
|
|
833
|
-
configPath,
|
|
834
|
-
getLintStagedConfig(projectType, usesEslint, usesPrettier, usesTypeScript),
|
|
835
|
-
{ backup: true }
|
|
836
|
-
);
|
|
837
|
-
if (writeResult.created) {
|
|
838
|
-
result.created.push(".lintstagedrc.js");
|
|
839
|
-
if (writeResult.backedUp) {
|
|
840
|
-
result.backedUp.push(writeResult.backedUp);
|
|
841
|
-
}
|
|
842
|
-
}
|
|
843
|
-
return result;
|
|
764
|
+
return config;
|
|
844
765
|
}
|
|
845
766
|
|
|
846
767
|
// src/utils/package-json.ts
|
|
847
768
|
import { readFile as readFile3, writeFile as writeFile2 } from "fs/promises";
|
|
848
769
|
import { existsSync as existsSync4 } from "fs";
|
|
849
|
-
import { join as
|
|
770
|
+
import { join as join7 } from "path";
|
|
850
771
|
async function readPackageJson(targetDir = process.cwd()) {
|
|
851
|
-
const pkgPath =
|
|
772
|
+
const pkgPath = join7(targetDir, "package.json");
|
|
852
773
|
if (!existsSync4(pkgPath)) {
|
|
853
774
|
throw new Error(`No package.json found in ${targetDir}`);
|
|
854
775
|
}
|
|
@@ -856,7 +777,7 @@ async function readPackageJson(targetDir = process.cwd()) {
|
|
|
856
777
|
return JSON.parse(content);
|
|
857
778
|
}
|
|
858
779
|
async function writePackageJson(pkg, targetDir = process.cwd()) {
|
|
859
|
-
const pkgPath =
|
|
780
|
+
const pkgPath = join7(targetDir, "package.json");
|
|
860
781
|
const content = JSON.stringify(pkg, null, 2) + "\n";
|
|
861
782
|
await writeFile2(pkgPath, content, "utf-8");
|
|
862
783
|
}
|
|
@@ -893,13 +814,25 @@ function addPackageJsonConfig(pkg, key, config, overwrite = false) {
|
|
|
893
814
|
};
|
|
894
815
|
}
|
|
895
816
|
var RAFTSTACK_DEV_DEPENDENCIES = {
|
|
896
|
-
|
|
897
|
-
"@commitlint/
|
|
898
|
-
"
|
|
899
|
-
|
|
817
|
+
// Commit tooling
|
|
818
|
+
"@commitlint/cli": "^19.0.0",
|
|
819
|
+
"@commitlint/config-conventional": "^19.0.0",
|
|
820
|
+
"cz-git": "^1.11.0",
|
|
821
|
+
czg: "^1.11.0",
|
|
900
822
|
husky: "^9.0.0",
|
|
901
|
-
"lint-staged": "^
|
|
902
|
-
"validate-branch-name": "^1.3.0"
|
|
823
|
+
"lint-staged": "^16.0.0",
|
|
824
|
+
"validate-branch-name": "^1.3.0",
|
|
825
|
+
// Linting & formatting
|
|
826
|
+
eslint: "^9.0.0",
|
|
827
|
+
"@eslint/js": "^9.0.0",
|
|
828
|
+
"typescript-eslint": "^8.0.0",
|
|
829
|
+
"eslint-config-prettier": "^10.0.0",
|
|
830
|
+
prettier: "^3.0.0",
|
|
831
|
+
globals: "^15.0.0"
|
|
832
|
+
};
|
|
833
|
+
var REACT_ESLINT_DEPS = {
|
|
834
|
+
"eslint-plugin-react": "^7.35.0",
|
|
835
|
+
"eslint-plugin-react-hooks": "^5.0.0"
|
|
903
836
|
};
|
|
904
837
|
|
|
905
838
|
// src/generators/branch-validation.ts
|
|
@@ -939,7 +872,7 @@ async function generateBranchValidation(targetDir) {
|
|
|
939
872
|
}
|
|
940
873
|
|
|
941
874
|
// src/generators/pr-template.ts
|
|
942
|
-
import { join as
|
|
875
|
+
import { join as join8 } from "path";
|
|
943
876
|
function getPRTemplate(hasAsana) {
|
|
944
877
|
const asanaSection = hasAsana ? `## Asana Task
|
|
945
878
|
<!-- Link to the Asana task -->
|
|
@@ -991,9 +924,9 @@ async function generatePRTemplate(targetDir, hasAsana) {
|
|
|
991
924
|
skipped: [],
|
|
992
925
|
backedUp: []
|
|
993
926
|
};
|
|
994
|
-
const githubDir =
|
|
927
|
+
const githubDir = join8(targetDir, ".github");
|
|
995
928
|
await ensureDir(githubDir);
|
|
996
|
-
const templatePath =
|
|
929
|
+
const templatePath = join8(githubDir, "PULL_REQUEST_TEMPLATE.md");
|
|
997
930
|
const writeResult = await writeFileSafe(
|
|
998
931
|
templatePath,
|
|
999
932
|
getPRTemplate(hasAsana),
|
|
@@ -1009,7 +942,7 @@ async function generatePRTemplate(targetDir, hasAsana) {
|
|
|
1009
942
|
}
|
|
1010
943
|
|
|
1011
944
|
// src/generators/github-workflows.ts
|
|
1012
|
-
import { join as
|
|
945
|
+
import { join as join9 } from "path";
|
|
1013
946
|
function getPRChecksWorkflow(projectType, usesTypeScript, usesEslint, pm) {
|
|
1014
947
|
const steps = [];
|
|
1015
948
|
steps.push(` - name: Checkout
|
|
@@ -1090,9 +1023,9 @@ async function generateGitHubWorkflows(targetDir, projectType, usesTypeScript, u
|
|
|
1090
1023
|
skipped: [],
|
|
1091
1024
|
backedUp: []
|
|
1092
1025
|
};
|
|
1093
|
-
const workflowsDir =
|
|
1026
|
+
const workflowsDir = join9(targetDir, ".github", "workflows");
|
|
1094
1027
|
await ensureDir(workflowsDir);
|
|
1095
|
-
const prChecksPath =
|
|
1028
|
+
const prChecksPath = join9(workflowsDir, "pr-checks.yml");
|
|
1096
1029
|
const writeResult = await writeFileSafe(
|
|
1097
1030
|
prChecksPath,
|
|
1098
1031
|
getPRChecksWorkflow(projectType, usesTypeScript, usesEslint, pm),
|
|
@@ -1108,7 +1041,7 @@ async function generateGitHubWorkflows(targetDir, projectType, usesTypeScript, u
|
|
|
1108
1041
|
}
|
|
1109
1042
|
|
|
1110
1043
|
// src/generators/codeowners.ts
|
|
1111
|
-
import { join as
|
|
1044
|
+
import { join as join10 } from "path";
|
|
1112
1045
|
function getCodeownersContent(owners) {
|
|
1113
1046
|
if (owners.length === 0) {
|
|
1114
1047
|
return `# CODEOWNERS file
|
|
@@ -1140,9 +1073,9 @@ async function generateCodeowners(targetDir, owners) {
|
|
|
1140
1073
|
skipped: [],
|
|
1141
1074
|
backedUp: []
|
|
1142
1075
|
};
|
|
1143
|
-
const githubDir =
|
|
1076
|
+
const githubDir = join10(targetDir, ".github");
|
|
1144
1077
|
await ensureDir(githubDir);
|
|
1145
|
-
const codeownersPath =
|
|
1078
|
+
const codeownersPath = join10(githubDir, "CODEOWNERS");
|
|
1146
1079
|
const writeResult = await writeFileSafe(
|
|
1147
1080
|
codeownersPath,
|
|
1148
1081
|
getCodeownersContent(owners),
|
|
@@ -1158,7 +1091,7 @@ async function generateCodeowners(targetDir, owners) {
|
|
|
1158
1091
|
}
|
|
1159
1092
|
|
|
1160
1093
|
// src/generators/ai-review.ts
|
|
1161
|
-
import { join as
|
|
1094
|
+
import { join as join11 } from "path";
|
|
1162
1095
|
function getCodeRabbitConfig() {
|
|
1163
1096
|
return `# CodeRabbit Configuration
|
|
1164
1097
|
# Learn more: https://docs.coderabbit.ai/guides/configure-coderabbit
|
|
@@ -1222,7 +1155,7 @@ async function generateAIReview(targetDir, tool) {
|
|
|
1222
1155
|
return result;
|
|
1223
1156
|
}
|
|
1224
1157
|
if (tool === "coderabbit") {
|
|
1225
|
-
const configPath =
|
|
1158
|
+
const configPath = join11(targetDir, ".coderabbit.yaml");
|
|
1226
1159
|
const writeResult = await writeFileSafe(configPath, getCodeRabbitConfig(), {
|
|
1227
1160
|
backup: true
|
|
1228
1161
|
});
|
|
@@ -1234,9 +1167,9 @@ async function generateAIReview(targetDir, tool) {
|
|
|
1234
1167
|
}
|
|
1235
1168
|
}
|
|
1236
1169
|
if (tool === "copilot") {
|
|
1237
|
-
const workflowsDir =
|
|
1170
|
+
const workflowsDir = join11(targetDir, ".github", "workflows");
|
|
1238
1171
|
await ensureDir(workflowsDir);
|
|
1239
|
-
const workflowPath =
|
|
1172
|
+
const workflowPath = join11(workflowsDir, "copilot-review.yml");
|
|
1240
1173
|
const writeResult = await writeFileSafe(workflowPath, getCopilotWorkflow(), {
|
|
1241
1174
|
backup: true
|
|
1242
1175
|
});
|
|
@@ -1251,7 +1184,7 @@ async function generateAIReview(targetDir, tool) {
|
|
|
1251
1184
|
}
|
|
1252
1185
|
|
|
1253
1186
|
// src/generators/branch-protection.ts
|
|
1254
|
-
import { join as
|
|
1187
|
+
import { join as join12 } from "path";
|
|
1255
1188
|
function getBranchProtectionDocs() {
|
|
1256
1189
|
return `# Branch Protection Setup Guide
|
|
1257
1190
|
|
|
@@ -1368,9 +1301,9 @@ async function generateBranchProtectionDocs(targetDir) {
|
|
|
1368
1301
|
skipped: [],
|
|
1369
1302
|
backedUp: []
|
|
1370
1303
|
};
|
|
1371
|
-
const docsDir =
|
|
1304
|
+
const docsDir = join12(targetDir, ".github");
|
|
1372
1305
|
await ensureDir(docsDir);
|
|
1373
|
-
const docsPath =
|
|
1306
|
+
const docsPath = join12(docsDir, "BRANCH_PROTECTION_SETUP.md");
|
|
1374
1307
|
const writeResult = await writeFileSafe(docsPath, getBranchProtectionDocs(), {
|
|
1375
1308
|
backup: true
|
|
1376
1309
|
});
|
|
@@ -1384,7 +1317,7 @@ async function generateBranchProtectionDocs(targetDir) {
|
|
|
1384
1317
|
}
|
|
1385
1318
|
|
|
1386
1319
|
// src/generators/contributing.ts
|
|
1387
|
-
import { join as
|
|
1320
|
+
import { join as join13 } from "path";
|
|
1388
1321
|
function getContributingContent(hasAsana, pm) {
|
|
1389
1322
|
const asanaSection = hasAsana ? `
|
|
1390
1323
|
## Linking to Asana
|
|
@@ -1523,7 +1456,7 @@ async function generateContributing(targetDir, hasAsana, pm) {
|
|
|
1523
1456
|
skipped: [],
|
|
1524
1457
|
backedUp: []
|
|
1525
1458
|
};
|
|
1526
|
-
const contributingPath =
|
|
1459
|
+
const contributingPath = join13(targetDir, "CONTRIBUTING.md");
|
|
1527
1460
|
const writeResult = await writeFileSafe(
|
|
1528
1461
|
contributingPath,
|
|
1529
1462
|
getContributingContent(hasAsana, pm),
|
|
@@ -1539,16 +1472,16 @@ async function generateContributing(targetDir, hasAsana, pm) {
|
|
|
1539
1472
|
}
|
|
1540
1473
|
|
|
1541
1474
|
// src/generators/prettier.ts
|
|
1542
|
-
import { join as
|
|
1475
|
+
import { join as join14 } from "path";
|
|
1543
1476
|
function getPrettierConfig() {
|
|
1544
1477
|
return JSON.stringify(
|
|
1545
1478
|
{
|
|
1546
1479
|
semi: true,
|
|
1547
|
-
singleQuote: true,
|
|
1548
|
-
tabWidth: 2,
|
|
1549
1480
|
trailingComma: "es5",
|
|
1550
|
-
|
|
1551
|
-
|
|
1481
|
+
singleQuote: false,
|
|
1482
|
+
printWidth: 80,
|
|
1483
|
+
tabWidth: 2,
|
|
1484
|
+
useTabs: false,
|
|
1552
1485
|
arrowParens: "always",
|
|
1553
1486
|
endOfLine: "lf"
|
|
1554
1487
|
},
|
|
@@ -1557,31 +1490,14 @@ function getPrettierConfig() {
|
|
|
1557
1490
|
) + "\n";
|
|
1558
1491
|
}
|
|
1559
1492
|
function getPrettierIgnore() {
|
|
1560
|
-
return
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
.next/
|
|
1567
|
-
out/
|
|
1568
|
-
|
|
1569
|
-
# Coverage
|
|
1570
|
-
coverage/
|
|
1571
|
-
|
|
1572
|
-
# IDE
|
|
1573
|
-
.idea/
|
|
1574
|
-
.vscode/
|
|
1575
|
-
|
|
1576
|
-
# Generated files
|
|
1577
|
-
*.min.js
|
|
1578
|
-
*.min.css
|
|
1579
|
-
package-lock.json
|
|
1493
|
+
return `node_modules
|
|
1494
|
+
dist
|
|
1495
|
+
build
|
|
1496
|
+
.turbo
|
|
1497
|
+
.next
|
|
1498
|
+
*.lock
|
|
1580
1499
|
pnpm-lock.yaml
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
# Other
|
|
1584
|
-
.git/
|
|
1500
|
+
coverage
|
|
1585
1501
|
`;
|
|
1586
1502
|
}
|
|
1587
1503
|
function hasPrettierConfig(targetDir) {
|
|
@@ -1597,7 +1513,7 @@ function hasPrettierConfig(targetDir) {
|
|
|
1597
1513
|
"prettier.config.cjs",
|
|
1598
1514
|
"prettier.config.mjs"
|
|
1599
1515
|
];
|
|
1600
|
-
return prettierFiles.some((file) => fileExists(
|
|
1516
|
+
return prettierFiles.some((file) => fileExists(join14(targetDir, file)));
|
|
1601
1517
|
}
|
|
1602
1518
|
async function generatePrettier(targetDir) {
|
|
1603
1519
|
const result = {
|
|
@@ -1610,7 +1526,7 @@ async function generatePrettier(targetDir) {
|
|
|
1610
1526
|
result.skipped.push(".prettierrc (already exists)");
|
|
1611
1527
|
return result;
|
|
1612
1528
|
}
|
|
1613
|
-
const configPath =
|
|
1529
|
+
const configPath = join14(targetDir, ".prettierrc");
|
|
1614
1530
|
const configResult = await writeFileSafe(configPath, getPrettierConfig(), {
|
|
1615
1531
|
backup: true
|
|
1616
1532
|
});
|
|
@@ -1620,7 +1536,7 @@ async function generatePrettier(targetDir) {
|
|
|
1620
1536
|
result.backedUp.push(configResult.backedUp);
|
|
1621
1537
|
}
|
|
1622
1538
|
}
|
|
1623
|
-
const ignorePath =
|
|
1539
|
+
const ignorePath = join14(targetDir, ".prettierignore");
|
|
1624
1540
|
const ignoreResult = await writeFileSafe(ignorePath, getPrettierIgnore(), {
|
|
1625
1541
|
backup: true,
|
|
1626
1542
|
overwrite: false
|
|
@@ -1640,19 +1556,19 @@ async function generatePrettier(targetDir) {
|
|
|
1640
1556
|
// src/generators/claude-skills.ts
|
|
1641
1557
|
import { existsSync as existsSync5 } from "fs";
|
|
1642
1558
|
import { readdir, copyFile as copyFile2 } from "fs/promises";
|
|
1643
|
-
import { join as
|
|
1559
|
+
import { join as join15, dirname as dirname2 } from "path";
|
|
1644
1560
|
import { fileURLToPath } from "url";
|
|
1645
1561
|
function getPackageSkillsDir() {
|
|
1646
1562
|
const currentFilePath = fileURLToPath(import.meta.url);
|
|
1647
|
-
const packageRoot =
|
|
1648
|
-
return
|
|
1563
|
+
const packageRoot = join15(dirname2(currentFilePath), "..");
|
|
1564
|
+
return join15(packageRoot, ".claude", "skills");
|
|
1649
1565
|
}
|
|
1650
1566
|
async function copyDirectory(srcDir, destDir, result, baseDir) {
|
|
1651
1567
|
await ensureDir(destDir);
|
|
1652
1568
|
const entries = await readdir(srcDir, { withFileTypes: true });
|
|
1653
1569
|
for (const entry of entries) {
|
|
1654
|
-
const srcPath =
|
|
1655
|
-
const destPath =
|
|
1570
|
+
const srcPath = join15(srcDir, entry.name);
|
|
1571
|
+
const destPath = join15(destDir, entry.name);
|
|
1656
1572
|
const relativePath = destPath.replace(baseDir + "/", "");
|
|
1657
1573
|
if (entry.isDirectory()) {
|
|
1658
1574
|
await copyDirectory(srcPath, destPath, result, baseDir);
|
|
@@ -1676,14 +1592,14 @@ async function generateClaudeSkills(targetDir) {
|
|
|
1676
1592
|
backedUp: []
|
|
1677
1593
|
};
|
|
1678
1594
|
const packageSkillsDir = getPackageSkillsDir();
|
|
1679
|
-
const targetSkillsDir =
|
|
1595
|
+
const targetSkillsDir = join15(targetDir, ".claude", "skills");
|
|
1680
1596
|
if (!existsSync5(packageSkillsDir)) {
|
|
1681
1597
|
console.warn(
|
|
1682
1598
|
"Warning: Skills directory not found in package. Skipping skills generation."
|
|
1683
1599
|
);
|
|
1684
1600
|
return result;
|
|
1685
1601
|
}
|
|
1686
|
-
await ensureDir(
|
|
1602
|
+
await ensureDir(join15(targetDir, ".claude"));
|
|
1687
1603
|
await copyDirectory(packageSkillsDir, targetSkillsDir, result, targetDir);
|
|
1688
1604
|
return result;
|
|
1689
1605
|
}
|
|
@@ -1691,10 +1607,229 @@ async function generateClaudeSkills(targetDir) {
|
|
|
1691
1607
|
// src/generators/eslint.ts
|
|
1692
1608
|
import { existsSync as existsSync6 } from "fs";
|
|
1693
1609
|
import { readFile as readFile4 } from "fs/promises";
|
|
1694
|
-
import { join as
|
|
1610
|
+
import { join as join16 } from "path";
|
|
1611
|
+
async function hasReact(targetDir) {
|
|
1612
|
+
try {
|
|
1613
|
+
const pkgPath = join16(targetDir, "package.json");
|
|
1614
|
+
if (existsSync6(pkgPath)) {
|
|
1615
|
+
const content = await readFile4(pkgPath, "utf-8");
|
|
1616
|
+
const pkg = JSON.parse(content);
|
|
1617
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
1618
|
+
return "react" in deps || "react-dom" in deps;
|
|
1619
|
+
}
|
|
1620
|
+
} catch {
|
|
1621
|
+
}
|
|
1622
|
+
return false;
|
|
1623
|
+
}
|
|
1624
|
+
function generateTsConfig(hasReactDep) {
|
|
1625
|
+
if (hasReactDep) {
|
|
1626
|
+
return `import eslint from "@eslint/js";
|
|
1627
|
+
import tseslint from "typescript-eslint";
|
|
1628
|
+
import eslintConfigPrettier from "eslint-config-prettier";
|
|
1629
|
+
import reactPlugin from "eslint-plugin-react";
|
|
1630
|
+
import reactHooksPlugin from "eslint-plugin-react-hooks";
|
|
1631
|
+
import globals from "globals";
|
|
1632
|
+
|
|
1633
|
+
export default tseslint.config(
|
|
1634
|
+
eslint.configs.recommended,
|
|
1635
|
+
...tseslint.configs.strict,
|
|
1636
|
+
eslintConfigPrettier,
|
|
1637
|
+
{
|
|
1638
|
+
files: ["**/*.{ts,tsx}"],
|
|
1639
|
+
languageOptions: {
|
|
1640
|
+
parserOptions: {
|
|
1641
|
+
ecmaFeatures: {
|
|
1642
|
+
jsx: true,
|
|
1643
|
+
},
|
|
1644
|
+
},
|
|
1645
|
+
globals: {
|
|
1646
|
+
...globals.browser,
|
|
1647
|
+
...globals.node,
|
|
1648
|
+
},
|
|
1649
|
+
},
|
|
1650
|
+
plugins: {
|
|
1651
|
+
react: reactPlugin,
|
|
1652
|
+
"react-hooks": reactHooksPlugin,
|
|
1653
|
+
},
|
|
1654
|
+
rules: {
|
|
1655
|
+
// TypeScript rules
|
|
1656
|
+
"@typescript-eslint/no-unused-vars": [
|
|
1657
|
+
"error",
|
|
1658
|
+
{ argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
|
|
1659
|
+
],
|
|
1660
|
+
"@typescript-eslint/no-explicit-any": "warn",
|
|
1661
|
+
"@typescript-eslint/consistent-type-imports": [
|
|
1662
|
+
"warn",
|
|
1663
|
+
{ prefer: "type-imports" },
|
|
1664
|
+
],
|
|
1665
|
+
|
|
1666
|
+
// React rules
|
|
1667
|
+
"react/react-in-jsx-scope": "off",
|
|
1668
|
+
"react/prop-types": "off",
|
|
1669
|
+
"react-hooks/rules-of-hooks": "error",
|
|
1670
|
+
"react-hooks/exhaustive-deps": "warn",
|
|
1671
|
+
|
|
1672
|
+
// General rules
|
|
1673
|
+
"no-console": ["warn", { allow: ["warn", "error"] }],
|
|
1674
|
+
},
|
|
1675
|
+
settings: {
|
|
1676
|
+
react: {
|
|
1677
|
+
version: "detect",
|
|
1678
|
+
},
|
|
1679
|
+
},
|
|
1680
|
+
},
|
|
1681
|
+
{
|
|
1682
|
+
ignores: ["node_modules/", "dist/", "build/", ".next/", "coverage/", ".turbo/"],
|
|
1683
|
+
}
|
|
1684
|
+
);
|
|
1685
|
+
`;
|
|
1686
|
+
}
|
|
1687
|
+
return `import eslint from "@eslint/js";
|
|
1688
|
+
import tseslint from "typescript-eslint";
|
|
1689
|
+
import eslintConfigPrettier from "eslint-config-prettier";
|
|
1690
|
+
import globals from "globals";
|
|
1691
|
+
|
|
1692
|
+
export default tseslint.config(
|
|
1693
|
+
eslint.configs.recommended,
|
|
1694
|
+
...tseslint.configs.strict,
|
|
1695
|
+
eslintConfigPrettier,
|
|
1696
|
+
{
|
|
1697
|
+
files: ["**/*.{ts,tsx}"],
|
|
1698
|
+
languageOptions: {
|
|
1699
|
+
globals: {
|
|
1700
|
+
...globals.node,
|
|
1701
|
+
},
|
|
1702
|
+
},
|
|
1703
|
+
rules: {
|
|
1704
|
+
// TypeScript rules
|
|
1705
|
+
"@typescript-eslint/no-unused-vars": [
|
|
1706
|
+
"error",
|
|
1707
|
+
{ argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
|
|
1708
|
+
],
|
|
1709
|
+
"@typescript-eslint/no-explicit-any": "warn",
|
|
1710
|
+
"@typescript-eslint/consistent-type-imports": [
|
|
1711
|
+
"warn",
|
|
1712
|
+
{ prefer: "type-imports" },
|
|
1713
|
+
],
|
|
1714
|
+
|
|
1715
|
+
// General rules
|
|
1716
|
+
"no-console": ["warn", { allow: ["warn", "error"] }],
|
|
1717
|
+
},
|
|
1718
|
+
},
|
|
1719
|
+
{
|
|
1720
|
+
ignores: ["node_modules/", "dist/", "build/", "coverage/", ".turbo/"],
|
|
1721
|
+
}
|
|
1722
|
+
);
|
|
1723
|
+
`;
|
|
1724
|
+
}
|
|
1725
|
+
function generateJsConfig(hasReactDep) {
|
|
1726
|
+
if (hasReactDep) {
|
|
1727
|
+
return `import eslint from "@eslint/js";
|
|
1728
|
+
import eslintConfigPrettier from "eslint-config-prettier";
|
|
1729
|
+
import reactPlugin from "eslint-plugin-react";
|
|
1730
|
+
import reactHooksPlugin from "eslint-plugin-react-hooks";
|
|
1731
|
+
import globals from "globals";
|
|
1732
|
+
|
|
1733
|
+
export default [
|
|
1734
|
+
eslint.configs.recommended,
|
|
1735
|
+
eslintConfigPrettier,
|
|
1736
|
+
{
|
|
1737
|
+
files: ["**/*.{js,jsx}"],
|
|
1738
|
+
languageOptions: {
|
|
1739
|
+
ecmaVersion: "latest",
|
|
1740
|
+
sourceType: "module",
|
|
1741
|
+
parserOptions: {
|
|
1742
|
+
ecmaFeatures: {
|
|
1743
|
+
jsx: true,
|
|
1744
|
+
},
|
|
1745
|
+
},
|
|
1746
|
+
globals: {
|
|
1747
|
+
...globals.browser,
|
|
1748
|
+
...globals.node,
|
|
1749
|
+
},
|
|
1750
|
+
},
|
|
1751
|
+
plugins: {
|
|
1752
|
+
react: reactPlugin,
|
|
1753
|
+
"react-hooks": reactHooksPlugin,
|
|
1754
|
+
},
|
|
1755
|
+
rules: {
|
|
1756
|
+
// React rules
|
|
1757
|
+
"react/react-in-jsx-scope": "off",
|
|
1758
|
+
"react/prop-types": "warn",
|
|
1759
|
+
"react-hooks/rules-of-hooks": "error",
|
|
1760
|
+
"react-hooks/exhaustive-deps": "warn",
|
|
1761
|
+
|
|
1762
|
+
// General rules
|
|
1763
|
+
"no-console": ["warn", { allow: ["warn", "error"] }],
|
|
1764
|
+
"no-unused-vars": ["error", { argsIgnorePattern: "^_", varsIgnorePattern: "^_" }],
|
|
1765
|
+
},
|
|
1766
|
+
settings: {
|
|
1767
|
+
react: {
|
|
1768
|
+
version: "detect",
|
|
1769
|
+
},
|
|
1770
|
+
},
|
|
1771
|
+
},
|
|
1772
|
+
{
|
|
1773
|
+
ignores: ["node_modules/", "dist/", "build/", ".next/", "coverage/", ".turbo/"],
|
|
1774
|
+
},
|
|
1775
|
+
];
|
|
1776
|
+
`;
|
|
1777
|
+
}
|
|
1778
|
+
return `import eslint from "@eslint/js";
|
|
1779
|
+
import eslintConfigPrettier from "eslint-config-prettier";
|
|
1780
|
+
import globals from "globals";
|
|
1781
|
+
|
|
1782
|
+
export default [
|
|
1783
|
+
eslint.configs.recommended,
|
|
1784
|
+
eslintConfigPrettier,
|
|
1785
|
+
{
|
|
1786
|
+
files: ["**/*.js"],
|
|
1787
|
+
languageOptions: {
|
|
1788
|
+
ecmaVersion: "latest",
|
|
1789
|
+
sourceType: "module",
|
|
1790
|
+
globals: {
|
|
1791
|
+
...globals.node,
|
|
1792
|
+
},
|
|
1793
|
+
},
|
|
1794
|
+
rules: {
|
|
1795
|
+
// General rules
|
|
1796
|
+
"no-console": ["warn", { allow: ["warn", "error"] }],
|
|
1797
|
+
"no-unused-vars": ["error", { argsIgnorePattern: "^_", varsIgnorePattern: "^_" }],
|
|
1798
|
+
},
|
|
1799
|
+
},
|
|
1800
|
+
{
|
|
1801
|
+
ignores: ["node_modules/", "dist/", "build/", "coverage/", ".turbo/"],
|
|
1802
|
+
},
|
|
1803
|
+
];
|
|
1804
|
+
`;
|
|
1805
|
+
}
|
|
1806
|
+
async function detectReact(targetDir) {
|
|
1807
|
+
return hasReact(targetDir);
|
|
1808
|
+
}
|
|
1809
|
+
async function generateEslint(targetDir, usesTypeScript, force = false) {
|
|
1810
|
+
const result = {
|
|
1811
|
+
created: [],
|
|
1812
|
+
modified: [],
|
|
1813
|
+
skipped: [],
|
|
1814
|
+
backedUp: []
|
|
1815
|
+
};
|
|
1816
|
+
if (!force && await hasEslint(targetDir)) {
|
|
1817
|
+
result.skipped.push("eslint.config.js (ESLint already configured)");
|
|
1818
|
+
return result;
|
|
1819
|
+
}
|
|
1820
|
+
const usesReact = await hasReact(targetDir);
|
|
1821
|
+
const config = usesTypeScript ? generateTsConfig(usesReact) : generateJsConfig(usesReact);
|
|
1822
|
+
const configPath = join16(targetDir, "eslint.config.js");
|
|
1823
|
+
const writeResult = await writeFileSafe(configPath, config);
|
|
1824
|
+
if (writeResult.backedUp) {
|
|
1825
|
+
result.backedUp.push("eslint.config.js");
|
|
1826
|
+
}
|
|
1827
|
+
result.created.push("eslint.config.js");
|
|
1828
|
+
return result;
|
|
1829
|
+
}
|
|
1695
1830
|
|
|
1696
1831
|
// src/generators/quick-reference.ts
|
|
1697
|
-
import { join as
|
|
1832
|
+
import { join as join17 } from "path";
|
|
1698
1833
|
async function generateQuickReference(targetDir, pm) {
|
|
1699
1834
|
const result = {
|
|
1700
1835
|
created: [],
|
|
@@ -1702,7 +1837,7 @@ async function generateQuickReference(targetDir, pm) {
|
|
|
1702
1837
|
skipped: [],
|
|
1703
1838
|
backedUp: []
|
|
1704
1839
|
};
|
|
1705
|
-
const quickRefPath =
|
|
1840
|
+
const quickRefPath = join17(targetDir, ".github", "QUICK_REFERENCE.md");
|
|
1706
1841
|
const content = `# RaftStack Quick Reference
|
|
1707
1842
|
|
|
1708
1843
|
> One-page guide for the RaftStack Git workflow
|
|
@@ -1838,9 +1973,9 @@ ${pm.run} test
|
|
|
1838
1973
|
// src/utils/git.ts
|
|
1839
1974
|
import { execa } from "execa";
|
|
1840
1975
|
import { existsSync as existsSync7 } from "fs";
|
|
1841
|
-
import { join as
|
|
1976
|
+
import { join as join18 } from "path";
|
|
1842
1977
|
async function isGitRepo(targetDir = process.cwd()) {
|
|
1843
|
-
if (existsSync7(
|
|
1978
|
+
if (existsSync7(join18(targetDir, ".git"))) {
|
|
1844
1979
|
return true;
|
|
1845
1980
|
}
|
|
1846
1981
|
try {
|
|
@@ -1885,7 +2020,7 @@ function mergeResults(results) {
|
|
|
1885
2020
|
{ created: [], modified: [], skipped: [], backedUp: [] }
|
|
1886
2021
|
);
|
|
1887
2022
|
}
|
|
1888
|
-
async function updateProjectPackageJson(targetDir,
|
|
2023
|
+
async function updateProjectPackageJson(targetDir, config, usesReact) {
|
|
1889
2024
|
const result = {
|
|
1890
2025
|
created: [],
|
|
1891
2026
|
modified: [],
|
|
@@ -1900,6 +2035,17 @@ async function updateProjectPackageJson(targetDir, _config) {
|
|
|
1900
2035
|
};
|
|
1901
2036
|
pkg = mergeScripts(pkg, scripts, false);
|
|
1902
2037
|
pkg = mergeDevDependencies(pkg, RAFTSTACK_DEV_DEPENDENCIES);
|
|
2038
|
+
if (usesReact) {
|
|
2039
|
+
pkg = mergeDevDependencies(pkg, REACT_ESLINT_DEPS);
|
|
2040
|
+
}
|
|
2041
|
+
const lintStagedConfig = getLintStagedConfig(
|
|
2042
|
+
true,
|
|
2043
|
+
// usesEslint - always true now since we install it
|
|
2044
|
+
true,
|
|
2045
|
+
// usesPrettier - always true now since we install it
|
|
2046
|
+
config.usesTypeScript
|
|
2047
|
+
);
|
|
2048
|
+
pkg = addPackageJsonConfig(pkg, "lint-staged", lintStagedConfig, true);
|
|
1903
2049
|
await writePackageJson(pkg, targetDir);
|
|
1904
2050
|
result.modified.push("package.json");
|
|
1905
2051
|
} catch (error) {
|
|
@@ -1932,31 +2078,23 @@ async function runInit(targetDir = process.cwd()) {
|
|
|
1932
2078
|
spinner4.start("Generating configuration files...");
|
|
1933
2079
|
const results = [];
|
|
1934
2080
|
try {
|
|
2081
|
+
const usesReact = await detectReact(targetDir);
|
|
1935
2082
|
results.push(
|
|
1936
2083
|
await generateHuskyHooks(targetDir, config.projectType, config.packageManager)
|
|
1937
2084
|
);
|
|
1938
2085
|
results.push(await generateCommitlint(targetDir, config.asanaBaseUrl));
|
|
1939
2086
|
results.push(await generateCzGit(targetDir, config.asanaBaseUrl));
|
|
1940
|
-
results.push(
|
|
1941
|
-
await generateLintStaged(
|
|
1942
|
-
targetDir,
|
|
1943
|
-
config.projectType,
|
|
1944
|
-
config.usesEslint,
|
|
1945
|
-
config.usesPrettier,
|
|
1946
|
-
config.usesTypeScript
|
|
1947
|
-
)
|
|
1948
|
-
);
|
|
1949
2087
|
results.push(await generateBranchValidation(targetDir));
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
}
|
|
2088
|
+
results.push(await generateEslint(targetDir, config.usesTypeScript, false));
|
|
2089
|
+
results.push(await generatePrettier(targetDir));
|
|
1953
2090
|
results.push(await generatePRTemplate(targetDir, !!config.asanaBaseUrl));
|
|
1954
2091
|
results.push(
|
|
1955
2092
|
await generateGitHubWorkflows(
|
|
1956
2093
|
targetDir,
|
|
1957
2094
|
config.projectType,
|
|
1958
2095
|
config.usesTypeScript,
|
|
1959
|
-
|
|
2096
|
+
true,
|
|
2097
|
+
// usesEslint - always true now
|
|
1960
2098
|
config.packageManager
|
|
1961
2099
|
)
|
|
1962
2100
|
);
|
|
@@ -1968,7 +2106,7 @@ async function runInit(targetDir = process.cwd()) {
|
|
|
1968
2106
|
);
|
|
1969
2107
|
results.push(await generateQuickReference(targetDir, config.packageManager));
|
|
1970
2108
|
results.push(await generateClaudeSkills(targetDir));
|
|
1971
|
-
results.push(await updateProjectPackageJson(targetDir, config));
|
|
2109
|
+
results.push(await updateProjectPackageJson(targetDir, config, usesReact));
|
|
1972
2110
|
spinner4.stop("Configuration files generated!");
|
|
1973
2111
|
} catch (error) {
|
|
1974
2112
|
spinner4.stop("Error generating files");
|
|
@@ -2426,7 +2564,7 @@ ${pc4.bold("Branches")}
|
|
|
2426
2564
|
// package.json
|
|
2427
2565
|
var package_default = {
|
|
2428
2566
|
name: "@raftlabs/raftstack",
|
|
2429
|
-
version: "1.
|
|
2567
|
+
version: "1.5.0",
|
|
2430
2568
|
description: "CLI tool for setting up Git hooks, commit conventions, and GitHub integration",
|
|
2431
2569
|
type: "module",
|
|
2432
2570
|
main: "./dist/index.js",
|