@rtorcato/repo-tooling 3.8.3 → 3.8.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.
|
@@ -212,6 +212,10 @@ export function computeFileList(config) {
|
|
|
212
212
|
if (config.typescript.enabled) {
|
|
213
213
|
files.push('tsconfig.json', 'reset.d.ts');
|
|
214
214
|
}
|
|
215
|
+
// Libraries get a bundle-size budget plus the `size-limit` script that runs it
|
|
216
|
+
// (#382). The scaffold's exports are root-only, so it's always the static form.
|
|
217
|
+
if (config.projectType === 'library')
|
|
218
|
+
files.push('.size-limit.json');
|
|
215
219
|
if (config.linting.tool === 'biome' || config.linting.tool === 'both') {
|
|
216
220
|
files.push(BIOME_CONFIG);
|
|
217
221
|
}
|
|
@@ -8,7 +8,7 @@ import { ensurePnpmSettings, familyGlob } from './pnpm-workspace.js';
|
|
|
8
8
|
import { generateGitConfigs } from './git.js';
|
|
9
9
|
import { generateGitHubActions } from './github-actions.js';
|
|
10
10
|
import { generateLintingConfigs } from './linting.js';
|
|
11
|
-
import { generateKnipConfig, generateMiscBaseline, generateVscodeExtensions } from './misc.js';
|
|
11
|
+
import { generateKnipConfig, generateMiscBaseline, generateSizeLimitConfig, generateVscodeExtensions, } from './misc.js';
|
|
12
12
|
import { generatePackageJson } from './package-json.js';
|
|
13
13
|
import { generateReadme } from './readme.js';
|
|
14
14
|
import { generateSecurityConfigs } from './security.js';
|
|
@@ -33,6 +33,12 @@ export async function generateConfigs(config, targetDir) {
|
|
|
33
33
|
await generatePackageJson(config, targetDir);
|
|
34
34
|
// Universal baseline: .editorconfig, .nvmrc, engines.node, knip.json
|
|
35
35
|
await generateMiscBaseline(targetDir);
|
|
36
|
+
// Bundle-size budget for publishable libraries. getScripts() emits the
|
|
37
|
+
// matching `size-limit` script, so the budget is runnable from the first
|
|
38
|
+
// commit rather than an inert file implying enforcement (#382).
|
|
39
|
+
if (config.projectType === 'library') {
|
|
40
|
+
await generateSizeLimitConfig(targetDir);
|
|
41
|
+
}
|
|
36
42
|
// Recommend the editor extensions matching the enabled tools
|
|
37
43
|
await generateVscodeExtensions(config, targetDir);
|
|
38
44
|
// Generate TypeScript configuration
|
|
@@ -141,6 +141,10 @@ function getScripts(config, opts = {}) {
|
|
|
141
141
|
// profile fits the dual (cjs+esm) exports the library scaffold emits.
|
|
142
142
|
if (config.projectType === 'library') {
|
|
143
143
|
scripts['attw'] = 'attw --pack';
|
|
144
|
+
// The budget scaffolded alongside it (generateConfigs) is inert without a
|
|
145
|
+
// way to run it — a size budget nothing runs implies an enforcement that
|
|
146
|
+
// isn't there (#382).
|
|
147
|
+
Object.assign(scripts, SIZE_LIMIT_SCRIPTS);
|
|
144
148
|
}
|
|
145
149
|
// Git hooks
|
|
146
150
|
if (config.gitHooks) {
|
|
@@ -169,6 +173,14 @@ function getScripts(config, opts = {}) {
|
|
|
169
173
|
* refused to compose a chain, both because no target ever created that script
|
|
170
174
|
* (#364).
|
|
171
175
|
*/
|
|
176
|
+
/**
|
|
177
|
+
* The one definition of the `size-limit` script, shared by `getScripts()` (setup)
|
|
178
|
+
* and the `size-limit` fixer, so the two paths can't drift (#382 — the divergence
|
|
179
|
+
* behind #371 and #377).
|
|
180
|
+
*/
|
|
181
|
+
export const SIZE_LIMIT_SCRIPTS = { 'size-limit': 'size-limit' };
|
|
182
|
+
/** Shared by the same two paths, for the same reason. */
|
|
183
|
+
export const SIZE_LIMIT_VERSION = '^11.2.0';
|
|
172
184
|
export async function ensureScripts(targetDir, scripts) {
|
|
173
185
|
const pkgPath = path.join(targetDir, 'package.json');
|
|
174
186
|
if (!(await fs.pathExists(pkgPath)))
|
|
@@ -352,8 +364,11 @@ function getDependencies(config) {
|
|
|
352
364
|
deps['lint-staged'] = '^16.0.0';
|
|
353
365
|
}
|
|
354
366
|
// are-the-types-wrong — validate published type resolution for libraries.
|
|
367
|
+
// size-limit enforces the bundle-size budget scaffolded next to it; without
|
|
368
|
+
// the dependency the script dies with "command not found" (#382).
|
|
355
369
|
if (config.projectType === 'library') {
|
|
356
370
|
deps['@arethetypeswrong/cli'] = '^0.18.2';
|
|
371
|
+
deps['size-limit'] = SIZE_LIMIT_VERSION;
|
|
357
372
|
}
|
|
358
373
|
// Commit linting (enforcement) + commitizen (assistance)
|
|
359
374
|
if (config.commitLint) {
|
|
@@ -95,7 +95,9 @@ export const FILE_CHECKS = [
|
|
|
95
95
|
candidates: ['tsconfig.json'],
|
|
96
96
|
expected: `extends "${PACKAGE}/typescript/*"`,
|
|
97
97
|
matcher: /@rtorcato\/(?:js|repo)-tooling\/typescript\//,
|
|
98
|
-
|
|
98
|
+
// `fix tsconfig`, not `copy tsconfig`: copy drops the whole preset inline,
|
|
99
|
+
// which carries no `extends` for the matcher above to find (#381).
|
|
100
|
+
hint: 'Run `npx @rtorcato/repo-tooling fix tsconfig` to scaffold',
|
|
99
101
|
},
|
|
100
102
|
{
|
|
101
103
|
check: 'Biome',
|
|
@@ -11,7 +11,7 @@ import { BIOME_CONFIG, generateBiomeConfig, generateESLintConfig, generatePretti
|
|
|
11
11
|
import { alignNodeVersion, ensureEnginesNode, ensurePackageManager, generateKnipConfig, generateNvmrc, generateSizeLimitConfig, generateVscodeExtensions, } from '../../cli/generators/misc.js';
|
|
12
12
|
import { scriptsOf } from './ci.js';
|
|
13
13
|
import { usesPnpm } from './checks.js';
|
|
14
|
-
import { composeVerifyScriptFromPkg, ensureScripts } from '../../cli/generators/package-json.js';
|
|
14
|
+
import { SIZE_LIMIT_SCRIPTS, SIZE_LIMIT_VERSION, composeVerifyScriptFromPkg, ensureScripts, } from '../../cli/generators/package-json.js';
|
|
15
15
|
/** Kept in step with the biome branch of getScripts() in package-json.ts. */
|
|
16
16
|
const BIOME_SCRIPTS = {
|
|
17
17
|
lint: 'biome lint .',
|
|
@@ -32,6 +32,24 @@ const PRETTIER_SCRIPTS = {
|
|
|
32
32
|
const KNIP_SCRIPTS = {
|
|
33
33
|
knip: 'knip',
|
|
34
34
|
};
|
|
35
|
+
/**
|
|
36
|
+
* Add `size-limit` to devDependencies unless the repo already pins it (either
|
|
37
|
+
* dependency list). Returns true when package.json was written.
|
|
38
|
+
*/
|
|
39
|
+
async function ensureSizeLimitDependency(targetDir) {
|
|
40
|
+
const pkgPath = path.join(targetDir, 'package.json');
|
|
41
|
+
if (!(await fs.pathExists(pkgPath)))
|
|
42
|
+
return false;
|
|
43
|
+
const pkg = (await fs.readJson(pkgPath));
|
|
44
|
+
const deps = pkg.dependencies ?? {};
|
|
45
|
+
const devDeps = { ...(pkg.devDependencies ?? {}) };
|
|
46
|
+
if (devDeps['size-limit'] || deps['size-limit'])
|
|
47
|
+
return false;
|
|
48
|
+
devDeps['size-limit'] = SIZE_LIMIT_VERSION;
|
|
49
|
+
pkg.devDependencies = devDeps;
|
|
50
|
+
await fs.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
35
53
|
/** Kept in step with the typescript branch of getScripts() in package-json.ts. */
|
|
36
54
|
const TSCONFIG_SCRIPTS = {
|
|
37
55
|
typecheck: 'tsc --noEmit',
|
|
@@ -48,6 +66,7 @@ import { WORKSPACE_FILE, dependsOnEsbuild, ensurePnpmSettings, familyGlob, } fro
|
|
|
48
66
|
import { generatePostcss } from '../../cli/generators/postcss.js';
|
|
49
67
|
import { generateCypressConfig, generateVitestConfig } from '../../cli/generators/testing.js';
|
|
50
68
|
import { generateTreeshakeCheck, inferSubpathsFromExports } from '../../cli/generators/treeshake.js';
|
|
69
|
+
import { generateTSConfig } from '../../cli/generators/tsconfig.js';
|
|
51
70
|
import { generateTailwind } from '../../cli/generators/tailwind.js';
|
|
52
71
|
import { generateTurborepo } from '../../cli/generators/turborepo.js';
|
|
53
72
|
import { generateNx } from '../../cli/generators/nx.js';
|
|
@@ -70,7 +89,12 @@ export function inferProjectConfig(pkg) {
|
|
|
70
89
|
return {
|
|
71
90
|
projectName: pkg?.name ?? 'project',
|
|
72
91
|
projectType,
|
|
73
|
-
typescript: {
|
|
92
|
+
typescript: {
|
|
93
|
+
enabled: true,
|
|
94
|
+
// Same mapping the react-app/nextjs-app setup presets use — a react-app on
|
|
95
|
+
// the base preset has no DOM libs, so `document`/`window` don't typecheck.
|
|
96
|
+
config: projectType === 'nextjs-app' ? 'next' : projectType === 'react-app' ? 'react' : 'base',
|
|
97
|
+
},
|
|
74
98
|
linting: {
|
|
75
99
|
tool: 'biome',
|
|
76
100
|
eslintConfig: projectType === 'nextjs-app' ? 'nextjs' : 'base',
|
|
@@ -170,9 +194,18 @@ export const FIXERS = [
|
|
|
170
194
|
appliesTo: ['TypeScript'],
|
|
171
195
|
outputs: ['tsconfig.json', 'package.json (scripts)'],
|
|
172
196
|
canFixDrift: true,
|
|
173
|
-
async run({ targetDir }) {
|
|
174
|
-
|
|
175
|
-
|
|
197
|
+
async run({ targetDir, pkg }) {
|
|
198
|
+
// Shares generateTSConfig with the setup path — copyPreset used to inline
|
|
199
|
+
// the whole base preset, which carries no `extends` for doctor's matcher
|
|
200
|
+
// and threw away the project-type settings setup emits (#381).
|
|
201
|
+
const config = inferProjectConfig(pkg);
|
|
202
|
+
// Bun leaves no package.json trace, so inferProjectConfig can't see it; a
|
|
203
|
+
// bunfig.toml is the signal, and without it this would strip `types: ['bun']`
|
|
204
|
+
// off a Bun repo by dropping it back onto the base preset.
|
|
205
|
+
if (await fs.pathExists(path.join(targetDir, 'bunfig.toml')))
|
|
206
|
+
config.bun = true;
|
|
207
|
+
await generateTSConfig(config, targetDir);
|
|
208
|
+
const filesWritten = ['tsconfig.json'];
|
|
176
209
|
// Without `typecheck` the generated CI drops its typecheck job entirely
|
|
177
210
|
// (#377). Shared with non-JS paths, so this is a no-op when there's no
|
|
178
211
|
// package.json to add it to.
|
|
@@ -540,13 +573,23 @@ export const FIXERS = [
|
|
|
540
573
|
},
|
|
541
574
|
{
|
|
542
575
|
target: 'size-limit',
|
|
543
|
-
description: 'Scaffold a size-limit budget — exports-driven .size-limit.cjs for multi-subpath libraries, else a static .size-limit.json',
|
|
576
|
+
description: 'Scaffold a size-limit budget — exports-driven .size-limit.cjs for multi-subpath libraries, else a static .size-limit.json — plus the `size-limit` script and devDependency',
|
|
544
577
|
appliesTo: ['size-limit'],
|
|
545
|
-
outputs: ['.size-limit.cjs', '.size-limit.json'],
|
|
578
|
+
outputs: ['.size-limit.cjs', '.size-limit.json', 'package.json (devDependencies + scripts)'],
|
|
579
|
+
// safe-merge: installs the CLI and only fills in a missing script.
|
|
580
|
+
riskLevel: 'safe-merge',
|
|
546
581
|
canFixDrift: true,
|
|
547
582
|
async run({ targetDir }) {
|
|
548
583
|
const written = await generateSizeLimitConfig(targetDir);
|
|
549
|
-
|
|
584
|
+
const filesWritten = [written];
|
|
585
|
+
// A budget with nothing to run it is worse than no budget — the file's
|
|
586
|
+
// presence implies an enforcement that isn't there (#382). The script
|
|
587
|
+
// needs the CLI installed too, or it dies with "command not found".
|
|
588
|
+
const installed = await ensureSizeLimitDependency(targetDir);
|
|
589
|
+
const scripted = await ensureScripts(targetDir, SIZE_LIMIT_SCRIPTS);
|
|
590
|
+
if (installed || scripted)
|
|
591
|
+
filesWritten.push('package.json');
|
|
592
|
+
return { filesWritten };
|
|
550
593
|
},
|
|
551
594
|
},
|
|
552
595
|
{
|
package/package.json
CHANGED