Skip to content

Commit

Permalink
fix: improve tsconfig extends checks (#61413)
Browse files Browse the repository at this point in the history
Co-authored-by: Sebastian Silbermann <[email protected]>
  • Loading branch information
ryan-nauman and eps1lon authored Apr 23, 2024
1 parent 3fa9cb7 commit c09ce24
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 12 deletions.
38 changes: 30 additions & 8 deletions packages/next/src/lib/typescript/writeConfigurationDefaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,10 +223,33 @@ export async function writeConfigurationDefaults(
)
)
} else if (hasAppDir && !rawConfig.include.includes(nextAppTypes)) {
userTsConfig.include.push(nextAppTypes)
suggestedActions.push(
cyan('include') + ' was updated to add ' + bold(`'${nextAppTypes}'`)
)
if (!Array.isArray(userTsConfig.include)) {
userTsConfig.include = []
}
// rawConfig will resolve all extends and include paths (ex: tsconfig.json, tsconfig.base.json, etc.)
// if it doesn't match userTsConfig then update the userTsConfig to add the
// rawConfig's includes in addition to nextAppTypes
if (
rawConfig.include.length !== userTsConfig.include.length ||
JSON.stringify(rawConfig.include.sort()) !==
JSON.stringify(userTsConfig.include.sort())
) {
userTsConfig.include.push(...rawConfig.include, nextAppTypes)
suggestedActions.push(
cyan('include') +
' was set to ' +
bold(
`[${[...rawConfig.include, nextAppTypes]
.map((i) => `'${i}'`)
.join(', ')}]`
)
)
} else {
userTsConfig.include.push(nextAppTypes)
suggestedActions.push(
cyan('include') + ' was updated to add ' + bold(`'${nextAppTypes}'`)
)
}
}

// Enable the Next.js typescript plugin.
Expand Down Expand Up @@ -270,14 +293,13 @@ export async function writeConfigurationDefaults(
)
}

// If `strict` is set to `false` or `strictNullChecks` is set to `false`,
// If `strict` is set to `false` and `strictNullChecks` is set to `false`,
// then set `strictNullChecks` to `true`.
if (
hasPagesDir &&
hasAppDir &&
userTsConfig.compilerOptions &&
!userTsConfig.compilerOptions.strict &&
!('strictNullChecks' in userTsConfig.compilerOptions)
!tsOptions.strict &&
!('strictNullChecks' in tsOptions)
) {
userTsConfig.compilerOptions.strictNullChecks = true
suggestedActions.push(
Expand Down
6 changes: 2 additions & 4 deletions test/integration/tsconfig-verifier/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -695,8 +695,7 @@ import path from 'path'
"{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"target": "ES2017",
"strictNullChecks": true
"target": "ES2017"
}
}
"
Expand Down Expand Up @@ -764,8 +763,7 @@ import path from 'path'
"extends": "./tsconfig.base.json",
"compilerOptions": {
"target": "ES2017",
"incremental": true,
"strictNullChecks": true
"incremental": true
}
}
"
Expand Down
102 changes: 102 additions & 0 deletions test/unit/write-configuration-defaults.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/* eslint-env jest */
import fs from 'fs-extra'
import { join } from 'path'
import { writeConfigurationDefaults } from 'next/dist/lib/typescript/writeConfigurationDefaults'
import * as ts from 'typescript'

const fixtureDir = join(__dirname, 'fixtures/config-ts')
const tsconfigFile = join(fixtureDir, 'tsconfig.json')
const tsconfigBaseFile = join(fixtureDir, 'tsconfig.base.json')
const distDir = '.next'
const nextAppTypes = `${distDir}/types/**/*.ts`

describe('tsconfig.base.json', () => {
beforeEach(async () => {
await fs.ensureDir(fixtureDir)
})
afterEach(async () => {
await fs.remove(tsconfigFile)
await fs.remove(tsconfigBaseFile)
})

describe('appDir', () => {
it('should support empty includes when base provides it', async () => {
const include = ['**/*.ts', '**/*.tsx', nextAppTypes]
const content = {
extends: './tsconfig.base.json',
}
const baseContent = {
include,
}

await fs.writeFile(tsconfigFile, JSON.stringify(content, null, 2))
await fs.writeFile(tsconfigBaseFile, JSON.stringify(baseContent, null, 2))

await expect(
writeConfigurationDefaults(ts, tsconfigFile, false, true, distDir, true)
).resolves.not.toThrow()

const output = await fs.readFile(tsconfigFile, 'utf8')
const parsed = JSON.parse(output)

expect(parsed.include).toBeUndefined()
})

it('should replace includes when base is missing appTypes', async () => {
const include = ['**/*.ts', '**/*.tsx']
const content = {
extends: './tsconfig.base.json',
}
const baseContent = {
include,
}

await fs.writeFile(tsconfigFile, JSON.stringify(content, null, 2))
await fs.writeFile(tsconfigBaseFile, JSON.stringify(baseContent, null, 2))

await expect(
writeConfigurationDefaults(ts, tsconfigFile, false, true, distDir, true)
).resolves.not.toThrow()

const output = await fs.readFile(tsconfigFile, 'utf8')
const parsed = JSON.parse(output)

expect(parsed.include.sort()).toMatchInlineSnapshot(`
[
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts",
]
`)
})

it('should not add strictNullChecks if base provides it', async () => {
const content = {
extends: './tsconfig.base.json',
}

const baseContent = {
compilerOptions: {
strictNullChecks: true,
strict: true,
},
}

await fs.writeFile(tsconfigFile, JSON.stringify(content, null, 2))
await fs.writeFile(tsconfigBaseFile, JSON.stringify(baseContent, null, 2))

await writeConfigurationDefaults(
ts,
tsconfigFile,
false,
true,
distDir,
true
)
const output = await fs.readFile(tsconfigFile, 'utf8')
const parsed = JSON.parse(output)

expect(parsed.compilerOptions.strictNullChecks).toBeUndefined()
})
})
})

0 comments on commit c09ce24

Please sign in to comment.