Check tsconfig "references" arrays (#2891)
Closes #2800 This PR makes it so that `check-scripts` will error out if you forget to add a "references" entry to a tsconfig file when adding an internal dependency in our monorepo. If these project references are missed it can prevent TS from building/rebuilding things when they need to be built/rebuilt. ### Change Type - [x] `internal` — Any other changes that don't affect the published package[^2]
This commit is contained in:
parent
5fd6b4dca7
commit
987a576423
18 changed files with 228 additions and 34 deletions
3
.github/workflows/checks.yml
vendored
3
.github/workflows/checks.yml
vendored
|
@ -44,6 +44,9 @@ jobs:
|
|||
- name: Check scripts
|
||||
run: yarn check-scripts
|
||||
|
||||
- name: Check tsconfigs
|
||||
run: yarn check-tsconfigs
|
||||
|
||||
- name: Lint
|
||||
run: yarn lint
|
||||
|
||||
|
|
|
@ -7,10 +7,17 @@
|
|||
"emitDeclarationOnly": false
|
||||
},
|
||||
"references": [
|
||||
{ "path": "../../packages/tlsync" },
|
||||
{ "path": "../../packages/tlschema" },
|
||||
{ "path": "../../packages/validate" },
|
||||
{ "path": "../../packages/store" },
|
||||
{ "path": "../../packages/utils" }
|
||||
{
|
||||
"path": "../../packages/store"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/tlschema"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/tlsync"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/utils"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -25,8 +25,14 @@
|
|||
"include": ["**/*.ts", "**/*.tsx"],
|
||||
"exclude": ["node_modules", "_archive"],
|
||||
"references": [
|
||||
{ "path": "../../packages/tlsync" },
|
||||
{ "path": "../../packages/tldraw" },
|
||||
{ "path": "../../packages/assets" }
|
||||
{
|
||||
"path": "../../packages/assets"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/tldraw"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/tlsync"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -6,9 +6,11 @@
|
|||
"outDir": "./.tsbuild"
|
||||
},
|
||||
"references": [
|
||||
{ "path": "../../packages/tldraw" },
|
||||
{ "path": "../../packages/utils" },
|
||||
{ "path": "../../packages/assets" },
|
||||
{ "path": "../../packages/validate" }
|
||||
{
|
||||
"path": "../../packages/assets"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/tldraw"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -7,5 +7,9 @@
|
|||
"emitDeclarationOnly": false,
|
||||
"types": ["@cloudflare/workers-types", "@types/node"]
|
||||
},
|
||||
"references": []
|
||||
"references": [
|
||||
{
|
||||
"path": "../../packages/utils"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -19,5 +19,12 @@
|
|||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||
"exclude": ["node_modules", "_archive"],
|
||||
"references": [{ "path": "../../packages/utils" }, { "path": "../../packages/validate" }]
|
||||
"references": [
|
||||
{
|
||||
"path": "../../packages/utils"
|
||||
},
|
||||
{
|
||||
"path": "../../packages/validate"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -23,5 +23,12 @@
|
|||
"experimentalDecorators": true
|
||||
},
|
||||
"include": ["src", "../messages", "scripts"],
|
||||
"references": [{ "path": "../../../packages/tldraw" }]
|
||||
"references": [
|
||||
{
|
||||
"path": "../../../packages/assets"
|
||||
},
|
||||
{
|
||||
"path": "../../../packages/tldraw"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -23,5 +23,12 @@
|
|||
"experimentalDecorators": true
|
||||
},
|
||||
"include": ["src", "../messages", "scripts"],
|
||||
"references": [{ "path": "../../../packages/tldraw" }]
|
||||
"references": [
|
||||
{
|
||||
"path": "../../../packages/editor"
|
||||
},
|
||||
{
|
||||
"path": "../../../packages/tldraw"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
"format": "prettier --write --cache \"**/*.{ts,tsx,js,jsx,json}\"",
|
||||
"typecheck": "yarn refresh-assets && tsx scripts/typecheck.ts",
|
||||
"check-scripts": "tsx scripts/check-scripts.ts",
|
||||
"check-tsconfigs": "tsx scripts/check-tsconfigs.ts",
|
||||
"api-check": "lazy api-check",
|
||||
"test-ci": "lazy test-ci",
|
||||
"test": "lazy test",
|
||||
|
|
|
@ -14,5 +14,9 @@
|
|||
"rootDir": "src",
|
||||
"resolveJsonModule": false
|
||||
},
|
||||
"references": [{ "path": "../utils" }]
|
||||
"references": [
|
||||
{
|
||||
"path": "../utils"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -11,10 +11,20 @@
|
|||
"types": ["node", "@types/jest"]
|
||||
},
|
||||
"references": [
|
||||
{ "path": "../tlschema" },
|
||||
{ "path": "../store" },
|
||||
{ "path": "../validate" },
|
||||
{ "path": "../utils" },
|
||||
{ "path": "../state" }
|
||||
{
|
||||
"path": "../state"
|
||||
},
|
||||
{
|
||||
"path": "../store"
|
||||
},
|
||||
{
|
||||
"path": "../tlschema"
|
||||
},
|
||||
{
|
||||
"path": "../utils"
|
||||
},
|
||||
{
|
||||
"path": "../validate"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -5,6 +5,5 @@
|
|||
"compilerOptions": {
|
||||
"outDir": "./.tsbuild",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"references": [{ "path": "../utils" }]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,5 +6,12 @@
|
|||
"outDir": "./.tsbuild",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"references": [{ "path": "../utils" }, { "path": "../state" }]
|
||||
"references": [
|
||||
{
|
||||
"path": "../state"
|
||||
},
|
||||
{
|
||||
"path": "../utils"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -4,9 +4,12 @@
|
|||
"exclude": ["node_modules", "dist", "**/*.css", ".tsbuild*", "./scripts/legacy-translations"],
|
||||
"compilerOptions": {
|
||||
"outDir": "./.tsbuild",
|
||||
// TODO: Enable noImplicitReturns
|
||||
"noImplicitReturns": false,
|
||||
"rootDir": "src"
|
||||
},
|
||||
"references": [{ "path": "../editor" }]
|
||||
"references": [
|
||||
{
|
||||
"path": "../editor"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -6,5 +6,18 @@
|
|||
"outDir": "./.tsbuild",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"references": [{ "path": "../store" }, { "path": "../validate" }, { "path": "../utils" }]
|
||||
"references": [
|
||||
{
|
||||
"path": "../state"
|
||||
},
|
||||
{
|
||||
"path": "../store"
|
||||
},
|
||||
{
|
||||
"path": "../utils"
|
||||
},
|
||||
{
|
||||
"path": "../validate"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -7,10 +7,20 @@
|
|||
"rootDir": "src"
|
||||
},
|
||||
"references": [
|
||||
{ "path": "../tldraw" },
|
||||
{ "path": "../tlschema" },
|
||||
{ "path": "../state" },
|
||||
{ "path": "../store" },
|
||||
{ "path": "../utils" }
|
||||
{
|
||||
"path": "../state"
|
||||
},
|
||||
{
|
||||
"path": "../store"
|
||||
},
|
||||
{
|
||||
"path": "../tldraw"
|
||||
},
|
||||
{
|
||||
"path": "../tlschema"
|
||||
},
|
||||
{
|
||||
"path": "../utils"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -6,5 +6,9 @@
|
|||
"outDir": "./.tsbuild",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"references": [{ "path": "../utils" }]
|
||||
"references": [
|
||||
{
|
||||
"path": "../utils"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
100
scripts/check-tsconfigs.ts
Normal file
100
scripts/check-tsconfigs.ts
Normal file
|
@ -0,0 +1,100 @@
|
|||
import kleur from 'kleur'
|
||||
import { join, relative } from 'path'
|
||||
import { readJsonIfExists, writeJsonFile } from './lib/file'
|
||||
import { nicelog } from './lib/nicelog'
|
||||
import { Package, getAllWorkspacePackages } from './lib/workspace'
|
||||
|
||||
const packagesWithoutTSConfigs: ReadonlySet<string> = new Set(['config'])
|
||||
|
||||
async function checkTsConfigs({ packages, fix }: { fix?: boolean; packages: Package[] }) {
|
||||
let numErrors = 0
|
||||
|
||||
for (const workspace of packages) {
|
||||
const tsconfigPath = join(workspace.path, 'tsconfig.json')
|
||||
if (packagesWithoutTSConfigs.has(workspace.name)) {
|
||||
continue
|
||||
}
|
||||
|
||||
const tsconfig = (await readJsonIfExists(tsconfigPath)) as {
|
||||
references?: { path: string }[]
|
||||
}
|
||||
if (!tsconfig) {
|
||||
throw new Error('No tsconfig.json found at ' + tsconfigPath)
|
||||
}
|
||||
|
||||
const tldrawDeps = Object.keys({
|
||||
...workspace.packageJson.dependencies,
|
||||
...workspace.packageJson.devDependencies,
|
||||
}).filter((dep) => dep.startsWith('@tldraw/'))
|
||||
|
||||
const fixedDeps = []
|
||||
const missingRefs = []
|
||||
const currentRefs = new Set<string>([...(tsconfig.references?.map((ref) => ref.path) ?? [])])
|
||||
for (const dep of tldrawDeps) {
|
||||
// construct the expected path to the dependency's tsconfig
|
||||
const matchingWorkspace = packages.find((p) => p.name === dep)
|
||||
if (!matchingWorkspace) {
|
||||
throw new Error(`No workspace found for ${dep}`)
|
||||
}
|
||||
const tsconfigReferencePath = relative(workspace.path, matchingWorkspace.path)
|
||||
fixedDeps.push({ path: tsconfigReferencePath })
|
||||
if (currentRefs.has(tsconfigReferencePath)) {
|
||||
currentRefs.delete(tsconfigReferencePath)
|
||||
} else {
|
||||
missingRefs.push(dep)
|
||||
}
|
||||
}
|
||||
|
||||
fixedDeps.sort((a, b) => a.path.localeCompare(b.path))
|
||||
if (currentRefs.size > 0) {
|
||||
if (fix) {
|
||||
tsconfig.references = fixedDeps
|
||||
writeJsonFile(tsconfigPath, tsconfig)
|
||||
} else {
|
||||
numErrors++
|
||||
nicelog(
|
||||
[
|
||||
'❌ ',
|
||||
kleur.red(`${workspace.name}: `),
|
||||
kleur.blue(relative(process.cwd(), tsconfigPath)),
|
||||
kleur.grey(' has unnecessary reference(s) to '),
|
||||
kleur.red([...currentRefs].join(', ')),
|
||||
].join('')
|
||||
)
|
||||
}
|
||||
}
|
||||
if (missingRefs.length) {
|
||||
if (fix) {
|
||||
tsconfig.references = fixedDeps
|
||||
writeJsonFile(tsconfigPath, tsconfig)
|
||||
} else {
|
||||
numErrors++
|
||||
nicelog(
|
||||
[
|
||||
'❌ ',
|
||||
kleur.red(`${workspace.name}: `),
|
||||
kleur.blue(relative(process.cwd(), tsconfigPath)),
|
||||
kleur.grey(' is missing reference(s) to '),
|
||||
kleur.red(missingRefs.join(', ')),
|
||||
].join('')
|
||||
)
|
||||
nicelog('The references entry should look like this:')
|
||||
nicelog('"references": ' + JSON.stringify(fixedDeps, null, 2))
|
||||
}
|
||||
}
|
||||
}
|
||||
if (numErrors > 0) {
|
||||
nicelog('Run `yarn check-tsconfigs --fix` to fix these problems')
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
async function main({ fix }: { fix?: boolean }) {
|
||||
const packages = await getAllWorkspacePackages()
|
||||
|
||||
await checkTsConfigs({ packages, fix })
|
||||
}
|
||||
|
||||
main({
|
||||
fix: process.argv.includes('--fix'),
|
||||
})
|
Loading…
Reference in a new issue