@bensandee/tooling 0.7.0 → 0.7.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.
Files changed (2) hide show
  1. package/dist/bin.mjs +108 -48
  2. package/package.json +2 -2
package/dist/bin.mjs CHANGED
@@ -64,6 +64,16 @@ function parseRenovateJson(raw) {
64
64
  return {};
65
65
  }
66
66
  }
67
+ const ChangesetConfigSchema = z.object({ commit: z.union([z.boolean(), z.string()]).optional() }).loose();
68
+ /** Parse a JSON string as a .changeset/config.json. Returns `undefined` on failure. */
69
+ function parseChangesetConfig(raw) {
70
+ try {
71
+ const result = ChangesetConfigSchema.safeParse(JSON.parse(raw));
72
+ return result.success ? result.data : void 0;
73
+ } catch {
74
+ return;
75
+ }
76
+ }
67
77
  /** Parse a JSON string as a package.json. Returns `undefined` on failure. */
68
78
  function parsePackageJson(raw) {
69
79
  try {
@@ -519,7 +529,6 @@ function addReleaseDeps(deps, config) {
519
529
  case "release-it":
520
530
  deps["release-it"] = "18.1.2";
521
531
  if (config.structure === "monorepo") deps["@release-it/bumper"] = "7.0.2";
522
- if (config.ci === "forgejo") deps["@bensandee/release-it-forgejo"] = "0.1.1";
523
532
  break;
524
533
  case "commit-and-tag-version":
525
534
  deps["commit-and-tag-version"] = "12.5.0";
@@ -582,6 +591,9 @@ async function generatePackageJson(ctx) {
582
591
  for (const [key, value] of Object.entries(devDeps)) if (!(key in existingDevDeps)) {
583
592
  existingDevDeps[key] = value;
584
593
  changes.push(`added devDependency: ${key}`);
594
+ } else if (key.startsWith("@bensandee/") && value === "latest" && existingDevDeps[key] !== "latest" && existingDevDeps[key] !== "workspace:*") {
595
+ existingDevDeps[key] = "latest";
596
+ changes.push(`updated devDependency: ${key} to latest`);
585
597
  }
586
598
  pkg.devDependencies = existingDevDeps;
587
599
  if (!pkg["engines"]) {
@@ -793,47 +805,81 @@ async function generateTsconfig(ctx) {
793
805
  const existing = ctx.read(filePath);
794
806
  if (ctx.config.structure === "monorepo") return [generateMonorepoRootTsconfig(ctx, existing), ...ctx.config.detectPackageTypes ? generateMonorepoPackageTsconfigs(ctx) : []];
795
807
  const extendsValue = `@bensandee/config/tsconfig/${ctx.config.projectType}`;
796
- const config = {
797
- extends: extendsValue,
798
- include: ["src"],
799
- exclude: ["node_modules", "dist"]
800
- };
801
- if (existing) {
802
- if (existing.includes("// @bensandee/tooling:ignore")) return [{
808
+ if (!existing) {
809
+ const config = {
810
+ extends: extendsValue,
811
+ include: ["src"],
812
+ exclude: ["node_modules", "dist"]
813
+ };
814
+ ctx.write(filePath, JSON.stringify(config, null, 2) + "\n");
815
+ return [{
803
816
  filePath,
804
- action: "skipped",
805
- description: "Ignored via tooling:ignore comment"
817
+ action: "created",
818
+ description: `Generated tsconfig.json with ${extendsValue}`
806
819
  }];
807
- const parsed = parseTsconfig(existing);
808
- const changes = [];
809
- if (!parsed.extends) {
810
- parsed.extends = extendsValue;
811
- changes.push(`added extends: ${extendsValue}`);
812
- }
813
- const existingInclude = parsed.include ?? [];
814
- for (const entry of config.include) if (!existingInclude.includes(entry)) {
815
- existingInclude.push(entry);
816
- changes.push(`added "${entry}" to include`);
817
- }
818
- parsed.include = existingInclude;
819
- if (changes.length === 0) return [{
820
+ }
821
+ if (existing.includes("// @bensandee/tooling:ignore")) return [{
822
+ filePath,
823
+ action: "skipped",
824
+ description: "Ignored via tooling:ignore comment"
825
+ }];
826
+ const parsed = parseTsconfig(existing);
827
+ if (isSolutionStyle(parsed)) {
828
+ const results = [{
820
829
  filePath,
821
830
  action: "skipped",
822
- description: "Already up to spec"
823
- }];
824
- ctx.write(filePath, JSON.stringify(parsed, null, 2) + "\n");
825
- return [{
826
- filePath,
827
- action: "updated",
828
- description: changes.join(", ")
831
+ description: "Solution-style tsconfig traversing references"
829
832
  }];
833
+ for (const ref of parsed.references ?? []) {
834
+ const refPath = resolveReferencePath(ref.path);
835
+ results.push(mergeSingleTsconfig(ctx, refPath, extendsValue));
836
+ }
837
+ return results;
830
838
  }
831
- ctx.write(filePath, JSON.stringify(config, null, 2) + "\n");
832
- return [{
839
+ return [mergeSingleTsconfig(ctx, filePath, extendsValue)];
840
+ }
841
+ function isSolutionStyle(parsed) {
842
+ return Array.isArray(parsed.references) && parsed.references.length > 0 && Array.isArray(parsed.files) && parsed.files.length === 0;
843
+ }
844
+ function resolveReferencePath(refPath) {
845
+ const resolved = refPath.endsWith(".json") ? refPath : path.join(refPath, "tsconfig.json");
846
+ return path.normalize(resolved);
847
+ }
848
+ function mergeSingleTsconfig(ctx, filePath, extendsValue) {
849
+ const existing = ctx.read(filePath);
850
+ if (!existing) return {
833
851
  filePath,
834
- action: "created",
835
- description: `Generated tsconfig.json with @bensandee/config/tsconfig/${ctx.config.projectType}`
836
- }];
852
+ action: "skipped",
853
+ description: "File not found"
854
+ };
855
+ if (existing.includes("// @bensandee/tooling:ignore")) return {
856
+ filePath,
857
+ action: "skipped",
858
+ description: "Ignored via tooling:ignore comment"
859
+ };
860
+ const parsed = parseTsconfig(existing);
861
+ const changes = [];
862
+ if (!parsed.extends) {
863
+ parsed.extends = extendsValue;
864
+ changes.push(`added extends: ${extendsValue}`);
865
+ }
866
+ const existingInclude = parsed.include ?? [];
867
+ if (!existingInclude.includes("src")) {
868
+ existingInclude.push("src");
869
+ changes.push("added \"src\" to include");
870
+ }
871
+ parsed.include = existingInclude;
872
+ if (changes.length === 0) return {
873
+ filePath,
874
+ action: "skipped",
875
+ description: "Already up to spec"
876
+ };
877
+ ctx.write(filePath, JSON.stringify(parsed, null, 2) + "\n");
878
+ return {
879
+ filePath,
880
+ action: "updated",
881
+ description: changes.join(", ")
882
+ };
837
883
  }
838
884
  function generateMonorepoRootTsconfig(ctx, existing) {
839
885
  const filePath = "tsconfig.json";
@@ -1542,7 +1588,6 @@ function buildConfig$2(ci, isMonorepo) {
1542
1588
  };
1543
1589
  if (ci === "github") config["github"] = { release: true };
1544
1590
  const plugins = {};
1545
- if (ci === "forgejo") plugins["@bensandee/release-it-forgejo"] = { release: true };
1546
1591
  if (isMonorepo) {
1547
1592
  config["npm"] = {
1548
1593
  publish: true,
@@ -2117,14 +2162,26 @@ async function runInit(config, options = {}) {
2117
2162
  p.log.info(`Migration prompt written to ${promptPath}`);
2118
2163
  p.log.info("Paste its contents into Claude Code to finish the migration.");
2119
2164
  }
2120
- const updateCmd = `pnpm update --latest ${getAddedDevDepNames(config).join(" ")}`;
2165
+ const bensandeeDeps = getAddedDevDepNames(config).filter((name) => name.startsWith("@bensandee/"));
2166
+ const hasLockfile = ctx.exists("pnpm-lock.yaml");
2167
+ if (bensandeeDeps.length > 0 && hasLockfile) {
2168
+ s.start("Updating @bensandee/* packages...");
2169
+ try {
2170
+ execSync(`pnpm update --latest ${bensandeeDeps.join(" ")}`, {
2171
+ cwd: config.targetDir,
2172
+ stdio: "ignore"
2173
+ });
2174
+ s.stop("Updated @bensandee/* packages");
2175
+ } catch (_error) {
2176
+ s.stop("Could not update @bensandee/* packages — run pnpm install first");
2177
+ }
2178
+ }
2121
2179
  p.note([
2122
2180
  "1. Run: pnpm install",
2123
- `2. Run: ${updateCmd}`,
2124
- "3. Run: pnpm typecheck",
2125
- "4. Run: pnpm build",
2126
- "5. Run: pnpm test",
2127
- ...options.noPrompt ? [] : ["6. Paste .tooling-migrate.md into Claude Code for cleanup"]
2181
+ "2. Run: pnpm typecheck",
2182
+ "3. Run: pnpm build",
2183
+ "4. Run: pnpm test",
2184
+ ...options.noPrompt ? [] : ["5. Paste .tooling-migrate.md into Claude Code for cleanup"]
2128
2185
  ].join("\n"), "Next steps");
2129
2186
  return results;
2130
2187
  }
@@ -2513,10 +2570,13 @@ async function runVersionMode(executor, config) {
2513
2570
  const changesetConfigPath = path.join(config.cwd, ".changeset", "config.json");
2514
2571
  const originalConfig = executor.readFile(changesetConfigPath);
2515
2572
  if (originalConfig) {
2516
- const parsed = JSON.parse(originalConfig);
2517
- if (parsed.commit) {
2518
- parsed.commit = false;
2519
- executor.writeFile(changesetConfigPath, JSON.stringify(parsed, null, 2) + "\n");
2573
+ const parsed = parseChangesetConfig(originalConfig);
2574
+ if (parsed?.commit) {
2575
+ const patched = {
2576
+ ...parsed,
2577
+ commit: false
2578
+ };
2579
+ executor.writeFile(changesetConfigPath, JSON.stringify(patched, null, 2) + "\n");
2520
2580
  debug(config, "Temporarily disabled changeset commit:true");
2521
2581
  }
2522
2582
  }
@@ -2903,7 +2963,7 @@ function mergeGitHub(dryRun) {
2903
2963
  const main = defineCommand({
2904
2964
  meta: {
2905
2965
  name: "tooling",
2906
- version: "0.7.0",
2966
+ version: "0.7.1",
2907
2967
  description: "Bootstrap and maintain standardized TypeScript project tooling"
2908
2968
  },
2909
2969
  subCommands: {
@@ -2916,7 +2976,7 @@ const main = defineCommand({
2916
2976
  "release:merge": releaseMergeCommand
2917
2977
  }
2918
2978
  });
2919
- console.log(`@bensandee/tooling v0.7.0`);
2979
+ console.log(`@bensandee/tooling v0.7.1`);
2920
2980
  runMain(main);
2921
2981
 
2922
2982
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bensandee/tooling",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "description": "CLI tool to bootstrap and maintain standardized TypeScript project tooling",
5
5
  "bin": {
6
6
  "tooling": "./dist/bin.mjs"
@@ -33,7 +33,7 @@
33
33
  "tsdown": "0.20.3",
34
34
  "typescript": "5.9.3",
35
35
  "vitest": "4.0.18",
36
- "@bensandee/config": "0.6.2"
36
+ "@bensandee/config": "0.6.3"
37
37
  },
38
38
  "scripts": {
39
39
  "build": "tsdown",