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
|
- name: Check scripts
|
||||||
run: yarn check-scripts
|
run: yarn check-scripts
|
||||||
|
|
||||||
|
- name: Check tsconfigs
|
||||||
|
run: yarn check-tsconfigs
|
||||||
|
|
||||||
- name: Lint
|
- name: Lint
|
||||||
run: yarn lint
|
run: yarn lint
|
||||||
|
|
||||||
|
|
|
@ -7,10 +7,17 @@
|
||||||
"emitDeclarationOnly": false
|
"emitDeclarationOnly": false
|
||||||
},
|
},
|
||||||
"references": [
|
"references": [
|
||||||
{ "path": "../../packages/tlsync" },
|
{
|
||||||
{ "path": "../../packages/tlschema" },
|
"path": "../../packages/store"
|
||||||
{ "path": "../../packages/validate" },
|
},
|
||||||
{ "path": "../../packages/store" },
|
{
|
||||||
{ "path": "../../packages/utils" }
|
"path": "../../packages/tlschema"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "../../packages/tlsync"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "../../packages/utils"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,14 @@
|
||||||
"include": ["**/*.ts", "**/*.tsx"],
|
"include": ["**/*.ts", "**/*.tsx"],
|
||||||
"exclude": ["node_modules", "_archive"],
|
"exclude": ["node_modules", "_archive"],
|
||||||
"references": [
|
"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"
|
"outDir": "./.tsbuild"
|
||||||
},
|
},
|
||||||
"references": [
|
"references": [
|
||||||
{ "path": "../../packages/tldraw" },
|
{
|
||||||
{ "path": "../../packages/utils" },
|
"path": "../../packages/assets"
|
||||||
{ "path": "../../packages/assets" },
|
},
|
||||||
{ "path": "../../packages/validate" }
|
{
|
||||||
|
"path": "../../packages/tldraw"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,5 +7,9 @@
|
||||||
"emitDeclarationOnly": false,
|
"emitDeclarationOnly": false,
|
||||||
"types": ["@cloudflare/workers-types", "@types/node"]
|
"types": ["@cloudflare/workers-types", "@types/node"]
|
||||||
},
|
},
|
||||||
"references": []
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "../../packages/utils"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,5 +19,12 @@
|
||||||
},
|
},
|
||||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||||
"exclude": ["node_modules", "_archive"],
|
"exclude": ["node_modules", "_archive"],
|
||||||
"references": [{ "path": "../../packages/utils" }, { "path": "../../packages/validate" }]
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "../../packages/utils"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "../../packages/validate"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,5 +23,12 @@
|
||||||
"experimentalDecorators": true
|
"experimentalDecorators": true
|
||||||
},
|
},
|
||||||
"include": ["src", "../messages", "scripts"],
|
"include": ["src", "../messages", "scripts"],
|
||||||
"references": [{ "path": "../../../packages/tldraw" }]
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "../../../packages/assets"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "../../../packages/tldraw"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,5 +23,12 @@
|
||||||
"experimentalDecorators": true
|
"experimentalDecorators": true
|
||||||
},
|
},
|
||||||
"include": ["src", "../messages", "scripts"],
|
"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}\"",
|
"format": "prettier --write --cache \"**/*.{ts,tsx,js,jsx,json}\"",
|
||||||
"typecheck": "yarn refresh-assets && tsx scripts/typecheck.ts",
|
"typecheck": "yarn refresh-assets && tsx scripts/typecheck.ts",
|
||||||
"check-scripts": "tsx scripts/check-scripts.ts",
|
"check-scripts": "tsx scripts/check-scripts.ts",
|
||||||
|
"check-tsconfigs": "tsx scripts/check-tsconfigs.ts",
|
||||||
"api-check": "lazy api-check",
|
"api-check": "lazy api-check",
|
||||||
"test-ci": "lazy test-ci",
|
"test-ci": "lazy test-ci",
|
||||||
"test": "lazy test",
|
"test": "lazy test",
|
||||||
|
|
|
@ -14,5 +14,9 @@
|
||||||
"rootDir": "src",
|
"rootDir": "src",
|
||||||
"resolveJsonModule": false
|
"resolveJsonModule": false
|
||||||
},
|
},
|
||||||
"references": [{ "path": "../utils" }]
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "../utils"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,10 +11,20 @@
|
||||||
"types": ["node", "@types/jest"]
|
"types": ["node", "@types/jest"]
|
||||||
},
|
},
|
||||||
"references": [
|
"references": [
|
||||||
{ "path": "../tlschema" },
|
{
|
||||||
{ "path": "../store" },
|
"path": "../state"
|
||||||
{ "path": "../validate" },
|
},
|
||||||
{ "path": "../utils" },
|
{
|
||||||
{ "path": "../state" }
|
"path": "../store"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "../tlschema"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "../utils"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "../validate"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,5 @@
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "./.tsbuild",
|
"outDir": "./.tsbuild",
|
||||||
"rootDir": "src"
|
"rootDir": "src"
|
||||||
},
|
}
|
||||||
"references": [{ "path": "../utils" }]
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,5 +6,12 @@
|
||||||
"outDir": "./.tsbuild",
|
"outDir": "./.tsbuild",
|
||||||
"rootDir": "src"
|
"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"],
|
"exclude": ["node_modules", "dist", "**/*.css", ".tsbuild*", "./scripts/legacy-translations"],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "./.tsbuild",
|
"outDir": "./.tsbuild",
|
||||||
// TODO: Enable noImplicitReturns
|
|
||||||
"noImplicitReturns": false,
|
"noImplicitReturns": false,
|
||||||
"rootDir": "src"
|
"rootDir": "src"
|
||||||
},
|
},
|
||||||
"references": [{ "path": "../editor" }]
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "../editor"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,5 +6,18 @@
|
||||||
"outDir": "./.tsbuild",
|
"outDir": "./.tsbuild",
|
||||||
"rootDir": "src"
|
"rootDir": "src"
|
||||||
},
|
},
|
||||||
"references": [{ "path": "../store" }, { "path": "../validate" }, { "path": "../utils" }]
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "../state"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "../store"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "../utils"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "../validate"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,10 +7,20 @@
|
||||||
"rootDir": "src"
|
"rootDir": "src"
|
||||||
},
|
},
|
||||||
"references": [
|
"references": [
|
||||||
{ "path": "../tldraw" },
|
{
|
||||||
{ "path": "../tlschema" },
|
"path": "../state"
|
||||||
{ "path": "../state" },
|
},
|
||||||
{ "path": "../store" },
|
{
|
||||||
{ "path": "../utils" }
|
"path": "../store"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "../tldraw"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "../tlschema"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "../utils"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,5 +6,9 @@
|
||||||
"outDir": "./.tsbuild",
|
"outDir": "./.tsbuild",
|
||||||
"rootDir": "src"
|
"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