@rtorcato/repo-tooling 3.2.2 → 3.2.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.
@@ -40,7 +40,17 @@ export async function generateBiomeConfig(targetDir) {
40
40
  export async function generateESLintConfig(config, targetDir) {
41
41
  const eslintConfigPath = path.join(targetDir, 'eslint.config.mjs');
42
42
  const configType = config.linting.eslintConfig || 'base';
43
- const eslintConfig = `import { default as config } from '@rtorcato/repo-tooling/eslint/${configType}'
43
+ // eslint/nextjs is a fragment: it registers the @next/next plugin and its
44
+ // rules but sets no parser, so on its own it can't even parse .tsx ("Parsing
45
+ // error: Unexpected token <"). It has to be layered onto the base config,
46
+ // which is what brings typescript-eslint.
47
+ const eslintConfig = configType === 'nextjs'
48
+ ? `import base from '@rtorcato/repo-tooling/eslint/base'
49
+ import nextjs from '@rtorcato/repo-tooling/eslint/nextjs'
50
+
51
+ export default [...base, ...nextjs]
52
+ `
53
+ : `import { default as config } from '@rtorcato/repo-tooling/eslint/${configType}'
44
54
 
45
55
  export default config
46
56
  `;
@@ -237,6 +237,24 @@ function getDependencies(config) {
237
237
  if (config.linting.tool === 'eslint' || config.linting.tool === 'both') {
238
238
  deps['eslint'] = '^9.0.0';
239
239
  deps['prettier'] = '^3.0.0';
240
+ // Everything tooling/eslint/base.mjs imports. All optional peers of
241
+ // repo-tooling, so pnpm skips them and `eslint .` dies on the config
242
+ // import — the scaffold shipped a lint script that could never run.
243
+ deps['@eslint/js'] = '^9.0.0';
244
+ deps['@typescript-eslint/eslint-plugin'] = '^8.0.0';
245
+ deps['typescript-eslint'] = '^8.0.0';
246
+ deps['eslint-plugin-import'] = '^2.0.0';
247
+ deps['eslint-plugin-jest'] = '^29.0.0';
248
+ }
249
+ // The shipped prettier preset lists this in `plugins`, and the nextjs eslint
250
+ // preset imports the Next plugin. Both are only *optional* peers of
251
+ // repo-tooling, so pnpm skips them and the scaffold's first format/lint dies
252
+ // with ERR_MODULE_NOT_FOUND.
253
+ if (config.formatting.tool === 'prettier') {
254
+ deps['@ianvs/prettier-plugin-sort-imports'] = '^4.7.0';
255
+ }
256
+ if (config.linting.eslintConfig === 'nextjs') {
257
+ deps['@next/eslint-plugin-next'] = '^16.2.11';
240
258
  }
241
259
  // Testing frameworks
242
260
  if (config.testing.framework === 'vitest') {
@@ -266,6 +284,10 @@ function getDependencies(config) {
266
284
  }
267
285
  else if (config.bundler === 'esbuild') {
268
286
  deps['esbuild'] = '^0.25.0';
287
+ // The generated build.mjs imports this directly. It's only an *optional*
288
+ // peer of repo-tooling, so pnpm won't pull it in — without it here every
289
+ // esbuild scaffold fails its first `pnpm build` with ERR_MODULE_NOT_FOUND.
290
+ deps['esbuild-node-externals'] = '^1.18.0';
269
291
  }
270
292
  else if (config.bundler === 'rollup') {
271
293
  deps['rollup'] = '^4.0.0';
@@ -278,6 +300,11 @@ function getDependencies(config) {
278
300
  }
279
301
  else if (config.bundler === 'vite') {
280
302
  deps['vite'] = '^6.0.0';
303
+ // generateViteConfig emits `import react from '@vitejs/plugin-react'` for
304
+ // react-app, so the plugin has to be installed or `vite build` can't even
305
+ // load the config. Keep this condition in step with that one.
306
+ if (config.projectType === 'react-app')
307
+ deps['@vitejs/plugin-react'] = '^5.0.0';
281
308
  }
282
309
  // Tailwind CSS v4 — CSS-first, wired via the PostCSS plugin.
283
310
  if (config.tailwind) {
@@ -16,10 +16,21 @@ export async function generateTestingConfigs(config, targetDir) {
16
16
  }
17
17
  export async function generateVitestConfig(config, targetDir) {
18
18
  const vitestConfigPath = path.join(targetDir, 'vitest.config.ts');
19
+ // Vite reads `jsx` from tsconfig, and the next preset sets it to "preserve" so
20
+ // Next's own compiler handles the transform. Vitest has no such compiler, so
21
+ // .tsx tests fail to parse ("Unexpected token <") unless we opt back in here.
22
+ // `oxc` (not `esbuild`) is the Vite 8 spelling — vitest ^4 resolves Vite 8,
23
+ // and Vite 8 silently ignores the old `esbuild` key.
24
+ const jsxOverride = config.projectType === 'nextjs-app'
25
+ ? ` // tsconfig sets jsx: "preserve" for Next's compiler; vitest needs a
26
+ // transform of its own or .tsx tests won't parse.
27
+ oxc: { jsx: { runtime: 'automatic' } },
28
+ `
29
+ : '';
19
30
  const vitestConfig = `import { defineConfig } from 'vitest/config'
20
31
 
21
32
  export default defineConfig({
22
- test: {
33
+ ${jsxOverride} test: {
23
34
  globals: true,
24
35
  environment: '${config.testing.environment === 'browser' ? 'jsdom' : 'node'}',
25
36
  setupFiles: ['./vitest.setup.ts'],
@@ -19,6 +19,12 @@ export async function generateTSConfig(config, targetDir) {
19
19
  tsconfig.compilerOptions.outDir = './dist';
20
20
  tsconfig.compilerOptions.rootDir = './src';
21
21
  }
22
+ // web-app is the only browser target that lands on the `base` preset, whose
23
+ // lib is ES2022 — so `document`/`window` don't typecheck. The react and next
24
+ // presets already add the DOM libs themselves.
25
+ if (config.projectType === 'web-app' && preset === 'base') {
26
+ tsconfig.compilerOptions.lib = ['ES2022', 'DOM', 'DOM.Iterable'];
27
+ }
22
28
  if (config.projectType === 'nextjs-app') {
23
29
  tsconfig.include = ['next-env.d.ts', 'src', 'app', 'pages', 'components', 'reset.d.ts'];
24
30
  tsconfig.exclude.push('.next');
@@ -12,7 +12,7 @@ jobs:
12
12
  steps:
13
13
  - uses: actions/checkout@v7
14
14
  - uses: pnpm/action-setup@v6
15
- - uses: actions/setup-node@v6
15
+ - uses: actions/setup-node@v7
16
16
  with:
17
17
  node-version: 22
18
18
  cache: pnpm
@@ -15,7 +15,7 @@ const SETUP_STEPS = ` - name: 📦 Checkout repository
15
15
  uses: actions/checkout@v7
16
16
 
17
17
  - name: 📦 Setup Node.js
18
- uses: actions/setup-node@v6
18
+ uses: actions/setup-node@v7
19
19
  with:
20
20
  node-version-file: .nvmrc
21
21
 
@@ -23,7 +23,7 @@ const SETUP_STEPS = ` - name: 📦 Checkout repository
23
23
  uses: pnpm/action-setup@v6
24
24
 
25
25
  - name: 📦 Restore dependencies cache
26
- uses: actions/cache@v5
26
+ uses: actions/cache@v6
27
27
  with:
28
28
  path: |
29
29
  ~/.pnpm-store
@@ -38,7 +38,7 @@ const DEPENDENCIES_JOB = {
38
38
  uses: actions/checkout@v7
39
39
 
40
40
  - name: 📦 Setup Node.js
41
- uses: actions/setup-node@v6
41
+ uses: actions/setup-node@v7
42
42
  with:
43
43
  node-version-file: .nvmrc
44
44
 
@@ -50,7 +50,7 @@ const DEPENDENCIES_JOB = {
50
50
  run: echo "key=\${{ runner.os }}-pnpm-\${{ hashFiles('**/pnpm-lock.yaml') }}" >> $GITHUB_OUTPUT
51
51
 
52
52
  - name: 📦 Cache dependencies
53
- uses: actions/cache@v5
53
+ uses: actions/cache@v6
54
54
  with:
55
55
  path: |
56
56
  ~/.pnpm-store
@@ -164,7 +164,7 @@ ${attw}${publint}
164
164
  token: \${{ secrets.RELEASE_TOKEN || secrets.GITHUB_TOKEN }}
165
165
 
166
166
  - name: 📦 Setup Node.js
167
- uses: actions/setup-node@v6
167
+ uses: actions/setup-node@v7
168
168
  with:
169
169
  node-version-file: .nvmrc
170
170
  registry-url: 'https://registry.npmjs.org'
@@ -173,7 +173,7 @@ ${attw}${publint}
173
173
  uses: pnpm/action-setup@v6
174
174
 
175
175
  - name: 📦 Restore dependencies cache
176
- uses: actions/cache@v5
176
+ uses: actions/cache@v6
177
177
  with:
178
178
  path: |
179
179
  ~/.pnpm-store
@@ -45,7 +45,7 @@ const XCODE_SETUP = ` - name: 📦 Checkout repository
45
45
  * to rebuild; key on Package.resolved so the cache invalidates with the graph.
46
46
  */
47
47
  const SPM_CACHE = ` - name: 📦 Cache SwiftPM
48
- uses: actions/cache@v5
48
+ uses: actions/cache@v6
49
49
  with:
50
50
  path: |
51
51
  .build
@@ -118,7 +118,7 @@ ${pkg.platforms.map((p) => ` - ${p}`).join('\n')}`,
118
118
  steps: `${XCODE_SETUP}
119
119
 
120
120
  - name: 📦 Cache DerivedData
121
- uses: actions/cache@v5
121
+ uses: actions/cache@v6
122
122
  with:
123
123
  path: ~/Library/Developer/Xcode/DerivedData
124
124
  key: \${{ runner.os }}-derived-\${{ matrix.platform }}-\${{ hashFiles('**/Package.resolved') }}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rtorcato/repo-tooling",
3
- "version": "3.2.2",
3
+ "version": "3.2.4",
4
4
  "description": "One CLI to scaffold, audit and fix your repo's whole toolchain — linting, tests, commits, releases & CI.",
5
5
  "type": "module",
6
6
  "keywords": [
@@ -1,6 +1,16 @@
1
1
  export default {
2
2
  extends: ["@commitlint/config-conventional"],
3
- ignores: [(commit) => commit.includes("[skip ci]")],
3
+ ignores: [
4
+ (commit) => commit.includes("[skip ci]"),
5
+ // Bot commit bodies are machine-written blocks (dependabot's
6
+ // `- dependency-name: …` YAML) that never wrap at 72, so every bot PR
7
+ // failed body-max-line-length. commitlint can't relax a single rule per
8
+ // commit, so skip bot commits wholesale — squash-merge uses the PR
9
+ // title, which is still linted on the merge commit.
10
+ // ponytail: matches the trailer, not a bare "[bot]", so a human commit
11
+ // that merely mentions a bot is still linted.
12
+ (commit) => /^Signed-off-by: .*\[bot\]/m.test(commit),
13
+ ],
4
14
  rules: {
5
15
  // Enforce strict type validation
6
16
  "type-enum": [
@@ -43,6 +43,14 @@ export default tseslint.config(
43
43
  ignores: [
44
44
  //
45
45
  '**/*.config.js',
46
+ // Root-level TS config files are outside the tsconfig `include` of every
47
+ // app preset, and this config lints type-aware (parserOptions.project),
48
+ // so linting them fails with "file was not found in any of the provided
49
+ // project(s)". The .js forms were already ignored; these are the same
50
+ // thing (the scaffold emits vitest.config.ts / vitest.setup.ts).
51
+ '**/*.config.ts',
52
+ '**/*.config.mts',
53
+ '**/*.setup.ts',
46
54
  '.turbo',
47
55
  'dist',
48
56
  'build',
@@ -18,10 +18,10 @@ jobs:
18
18
  runs-on: ubuntu-latest
19
19
  steps:
20
20
  - name: Checkout
21
- uses: actions/checkout@v4
21
+ uses: actions/checkout@v7
22
22
 
23
23
  - name: Setup Node.js
24
- uses: actions/setup-node@v4
24
+ uses: actions/setup-node@v7
25
25
  with:
26
26
  node-version-file: .nvmrc
27
27
 
@@ -17,7 +17,7 @@ jobs:
17
17
  runs-on: ubuntu-latest
18
18
  steps:
19
19
  - name: Checkout
20
- uses: actions/checkout@v4
20
+ uses: actions/checkout@v7
21
21
 
22
22
  - name: Set up Docker Buildx
23
23
  uses: docker/setup-buildx-action@v3
@@ -20,10 +20,10 @@ jobs:
20
20
  runs-on: ubuntu-latest
21
21
  steps:
22
22
  - name: Checkout
23
- uses: actions/checkout@v4
23
+ uses: actions/checkout@v7
24
24
 
25
25
  - name: Setup Node.js
26
- uses: actions/setup-node@v4
26
+ uses: actions/setup-node@v7
27
27
  with:
28
28
  node-version-file: .nvmrc
29
29
 
@@ -20,10 +20,10 @@ jobs:
20
20
  runs-on: ubuntu-latest
21
21
  steps:
22
22
  - name: Checkout
23
- uses: actions/checkout@v4
23
+ uses: actions/checkout@v7
24
24
 
25
25
  - name: Setup Node.js
26
- uses: actions/setup-node@v4
26
+ uses: actions/setup-node@v7
27
27
  with:
28
28
  node-version-file: .nvmrc
29
29
 
@@ -9,8 +9,12 @@
9
9
  // "moduleResolution": "node", // Prefer "bundler" if you're using Vite, esbuild, etc.
10
10
  // "target": "esnext", //
11
11
  "lib": ["ES2022"], // Specify library files to be included in the compilation
12
- "rootDir": "src",
13
- "outDir": "dist",
12
+ // ${configDir} for the same reason as paths/tsBuildInfoFile below: a bare
13
+ // "src" resolves against THIS file, i.e. inside node_modules, so every
14
+ // consumer that didn't redeclare rootDir got TS6059 "not under rootDir" the
15
+ // moment a file outside the preset's own directory entered the program.
16
+ "rootDir": "${configDir}/src",
17
+ "outDir": "${configDir}/dist",
14
18
 
15
19
 
16
20
  // 🔍 JavaScript Support
@@ -2,12 +2,19 @@
2
2
  "extends": "./tsconfig.base.json",
3
3
  "compilerOptions": {
4
4
  "jsx": "preserve", // Let Next.js handle JSX transformation
5
+ // The base pins rootDir to src/, but `include` below spans app/, pages/ and
6
+ // components/ — all siblings of src/ — so tsc raised TS6059 on any Next repo
7
+ // using the app router. These presets are noEmit, so rootDir buys nothing
8
+ // here beyond that trap; widen it to the project root.
9
+ "rootDir": "${configDir}",
5
10
  "lib": ["DOM", "DOM.Iterable", "ESNext"], // Include DOM types for browser APIs
6
11
  "module": "esnext", // Next.js expects ESNext modules
7
12
  "moduleResolution": "bundler", // Modern module resolution for Next.js
8
13
  "allowJs": true, // Allow JavaScript files
9
14
  "esModuleInterop": true, // Interop for CommonJS/ESM
10
- "types": ["react", "tailwindcss", "vitest"],
15
+ // No "tailwindcss" — see tsconfig.react.json; it broke TS2688 for every
16
+ // project without Tailwind installed.
17
+ "types": ["react", "vitest"],
11
18
  "plugins": [ { "name": "next" } ], // Next.js plugin for TypeScript
12
19
  // ${configDir} anchors paths to the consuming project (drops deprecated baseUrl)
13
20
  "paths": {
@@ -2,8 +2,14 @@
2
2
  "extends": "./tsconfig.base.json",
3
3
  "compilerOptions": {
4
4
  "jsx": "react-jsx", // Use the new JSX transform for React 17+
5
+ // Same TS6059 trap as the next preset: `include` below covers index.d.ts and
6
+ // types/ alongside src/, which a src-rooted rootDir can't contain.
7
+ "rootDir": "${configDir}",
5
8
  "lib": ["DOM", "DOM.Iterable", "ESNext"],// Include DOM types for browser APIs
6
- "types": ["react", "react-dom", "tailwindcss", "vitest"],
9
+ // No "tailwindcss": listing it here made tsc fail with TS2688 on every React
10
+ // project that doesn't install Tailwind. Tailwind v4 is CSS-first and ships
11
+ // no ambient types a project needs, so nothing is lost by dropping it.
12
+ "types": ["react", "react-dom", "vitest"],
7
13
  // ${configDir} anchors paths to the consuming project (drops deprecated baseUrl)
8
14
  "paths": {
9
15
  "~/*": ["${configDir}/src/*"],