@bensandee/tooling 0.40.4 → 0.40.5

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 +81 -14
  2. package/package.json +1 -1
package/dist/bin.mjs CHANGED
@@ -1549,7 +1549,7 @@ async function generatePackageJson(ctx) {
1549
1549
  const devDeps = { ...ROOT_DEV_DEPS };
1550
1550
  if (!isMonorepo) Object.assign(devDeps, PER_PACKAGE_DEV_DEPS);
1551
1551
  devDeps["@bensandee/config"] = isWorkspacePackage(ctx, "@bensandee/config") ? "workspace:*" : "0.10.0";
1552
- devDeps["@bensandee/tooling"] = isWorkspacePackage(ctx, "@bensandee/tooling") ? "workspace:*" : "0.40.4";
1552
+ devDeps["@bensandee/tooling"] = isWorkspacePackage(ctx, "@bensandee/tooling") ? "workspace:*" : "0.40.5";
1553
1553
  if (ctx.config.useEslintPlugin) devDeps["@bensandee/eslint-plugin"] = isWorkspacePackage(ctx, "@bensandee/eslint-plugin") ? "workspace:*" : "0.12.0";
1554
1554
  if (ctx.config.formatter === "oxfmt") devDeps["oxfmt"] = {
1555
1555
  "@changesets/cli": "2.30.0",
@@ -1912,32 +1912,54 @@ async function generateVitest(ctx) {
1912
1912
  }
1913
1913
  //#endregion
1914
1914
  //#region src/generators/oxlint.ts
1915
+ const IGNORE_PATTERNS_SPREAD = "...(recommended.ignorePatterns ?? [])";
1915
1916
  const CONFIG_WITH_LINT_RULES = `import recommended from "@bensandee/config/oxlint/recommended";
1916
1917
  import { defineConfig } from "oxlint";
1917
1918
 
1918
1919
  export default defineConfig({
1919
1920
  extends: [recommended],
1920
- ignorePatterns: [".claude/**"],
1921
+ ignorePatterns: [${IGNORE_PATTERNS_SPREAD}],
1921
1922
  });
1922
1923
  `;
1923
- const CONFIG_PRESET_ONLY = `import { presetRules } from "@bensandee/config/oxlint";
1924
+ const CONFIG_PRESET_ONLY = `import { presetRules, recommended } from "@bensandee/config/oxlint";
1924
1925
  import { defineConfig } from "oxlint";
1925
1926
 
1926
1927
  export default defineConfig({
1927
1928
  rules: presetRules,
1928
- ignorePatterns: [".claude/**"],
1929
+ ignorePatterns: [${IGNORE_PATTERNS_SPREAD}],
1929
1930
  });
1930
1931
  `;
1932
+ function addIgnorePatterns(content) {
1933
+ if (content.includes("ignorePatterns")) return void 0;
1934
+ const match = content.match(/defineConfig\(\{(\r?\n)/);
1935
+ if (!match) return void 0;
1936
+ const insertPos = (match.index ?? 0) + match[0].length;
1937
+ return content.slice(0, insertPos) + ` ignorePatterns: [${IGNORE_PATTERNS_SPREAD}],\n` + content.slice(insertPos);
1938
+ }
1931
1939
  async function generateOxlint(ctx) {
1932
1940
  const filePath = "oxlint.config.ts";
1933
1941
  const content = ctx.config.useEslintPlugin ? CONFIG_WITH_LINT_RULES : CONFIG_PRESET_ONLY;
1934
1942
  const existing = ctx.read(filePath);
1935
1943
  if (existing) {
1936
- if (existing === content || existing.includes("@bensandee/config/oxlint")) return {
1944
+ if (existing === content) return {
1937
1945
  filePath,
1938
1946
  action: "skipped",
1939
1947
  description: "Already configured"
1940
1948
  };
1949
+ if (existing.includes("@bensandee/config/oxlint")) {
1950
+ const updated = addIgnorePatterns(existing);
1951
+ if (!updated) return {
1952
+ filePath,
1953
+ action: "skipped",
1954
+ description: "Already configured"
1955
+ };
1956
+ ctx.write(filePath, updated);
1957
+ return {
1958
+ filePath,
1959
+ action: "updated",
1960
+ description: "Added ignorePatterns"
1961
+ };
1962
+ }
1941
1963
  if (await ctx.confirmOverwrite(filePath) === "skip") return {
1942
1964
  filePath,
1943
1965
  action: "skipped",
@@ -2271,6 +2293,7 @@ export default {
2271
2293
  },
2272
2294
  } satisfies KnipConfig;
2273
2295
  `;
2296
+ const REQUIRED_IGNORE = ".claude/hooks/**";
2274
2297
  /** All known knip config file locations, in priority order. */
2275
2298
  const KNIP_CONFIG_PATHS = [
2276
2299
  "knip.config.ts",
@@ -2280,15 +2303,59 @@ const KNIP_CONFIG_PATHS = [
2280
2303
  "knip.ts",
2281
2304
  "knip.mts"
2282
2305
  ];
2306
+ const JSON_EXTENSIONS = new Set([".json", ".jsonc"]);
2307
+ function isJsonConfig(path) {
2308
+ const dot = path.lastIndexOf(".");
2309
+ return dot !== -1 && JSON_EXTENSIONS.has(path.slice(dot));
2310
+ }
2311
+ /**
2312
+ * Try to add the required ignore pattern to an existing knip config.
2313
+ * Returns the updated content, or undefined if no change was needed.
2314
+ */
2315
+ function ensureIgnorePattern(content, path) {
2316
+ if (content.includes(".claude/hooks")) return void 0;
2317
+ if (isJsonConfig(path)) return ensureIgnoreInJson(content);
2318
+ return ensureIgnoreInTs(content);
2319
+ }
2320
+ const KnipJsonSchema = z.object({ ignore: z.array(z.string()).optional() }).passthrough();
2321
+ function ensureIgnoreInJson(content) {
2322
+ const result = KnipJsonSchema.safeParse(JSON.parse(content));
2323
+ if (!result.success) return void 0;
2324
+ const parsed = result.data;
2325
+ const ignore = parsed.ignore ?? [];
2326
+ ignore.push(REQUIRED_IGNORE);
2327
+ parsed.ignore = ignore;
2328
+ return JSON.stringify(parsed, null, 2) + "\n";
2329
+ }
2330
+ function ensureIgnoreInTs(content) {
2331
+ const ignoreArrayPattern = /(ignore:\s*\[)/;
2332
+ if (ignoreArrayPattern.exec(content)) return content.replace(ignoreArrayPattern, `$1"${REQUIRED_IGNORE}", `);
2333
+ const exportPattern = /(export default\s*\{)\n/;
2334
+ if (exportPattern.exec(content)) return content.replace(exportPattern, `$1\n ignore: ["${REQUIRED_IGNORE}"],\n`);
2335
+ }
2283
2336
  async function generateKnip(ctx) {
2284
2337
  const filePath = "knip.config.ts";
2285
2338
  const isMonorepo = ctx.config.structure === "monorepo";
2286
2339
  const existingPath = KNIP_CONFIG_PATHS.find((p) => ctx.exists(p));
2287
- if (existingPath) return {
2288
- filePath: existingPath,
2289
- action: "skipped",
2290
- description: existingPath === filePath ? "Already configured" : `Existing config found at ${existingPath}`
2291
- };
2340
+ if (existingPath) {
2341
+ const content = ctx.read(existingPath);
2342
+ if (content) {
2343
+ const updated = ensureIgnorePattern(content, existingPath);
2344
+ if (updated) {
2345
+ ctx.write(existingPath, updated);
2346
+ return {
2347
+ filePath: existingPath,
2348
+ action: "updated",
2349
+ description: "Added \".claude/hooks/**\" to ignore"
2350
+ };
2351
+ }
2352
+ }
2353
+ return {
2354
+ filePath: existingPath,
2355
+ action: "skipped",
2356
+ description: existingPath === filePath ? "Already configured" : `Existing config found at ${existingPath}`
2357
+ };
2358
+ }
2292
2359
  const config = isMonorepo ? KNIP_CONFIG_MONOREPO : KNIP_CONFIG_SINGLE;
2293
2360
  ctx.write(filePath, config);
2294
2361
  return {
@@ -3147,7 +3214,7 @@ async function generateVersionrc(ctx) {
3147
3214
  action: "skipped",
3148
3215
  description: "simple release not requested"
3149
3216
  };
3150
- if (ctx.exists(filePath)) return {
3217
+ if (ctx.exists(filePath) || ctx.exists(".versionrc")) return {
3151
3218
  filePath,
3152
3219
  action: "skipped",
3153
3220
  description: "Existing versionrc config preserved"
@@ -3197,7 +3264,7 @@ async function runGenerators(ctx) {
3197
3264
  function generateMigratePrompt(results, config, detected) {
3198
3265
  const sections = [];
3199
3266
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
3200
- sections.push(`# Migration Prompt\n\n_Generated by \`@bensandee/tooling@0.40.4 repo:sync\` on ${timestamp}_\n`);
3267
+ sections.push(`# Migration Prompt\n\n_Generated by \`@bensandee/tooling@0.40.5 repo:sync\` on ${timestamp}_\n`);
3201
3268
  const changed = results.filter((r) => r.action === "created" || r.action === "updated" || r.action === "archived");
3202
3269
  if (changed.length > 0) {
3203
3270
  const items = changed.map((r) => {
@@ -5333,7 +5400,7 @@ const hooksAuditCommand = defineCommand({
5333
5400
  const main = defineCommand({
5334
5401
  meta: {
5335
5402
  name: "bst",
5336
- version: "0.40.4",
5403
+ version: "0.40.5",
5337
5404
  description: "Bootstrap and maintain standardized TypeScript project tooling"
5338
5405
  },
5339
5406
  subCommands: {
@@ -5350,7 +5417,7 @@ const main = defineCommand({
5350
5417
  "hooks:audit": hooksAuditCommand
5351
5418
  }
5352
5419
  });
5353
- console.log(`@bensandee/tooling v0.40.4`);
5420
+ console.log(`@bensandee/tooling v0.40.5`);
5354
5421
  async function run() {
5355
5422
  await runMain(main);
5356
5423
  process.exit(process.exitCode ?? 0);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bensandee/tooling",
3
- "version": "0.40.4",
3
+ "version": "0.40.5",
4
4
  "description": "CLI tool to bootstrap and maintain standardized TypeScript project tooling",
5
5
  "license": "MIT",
6
6
  "repository": {