Skip to content

Commit

Permalink
feat(tsconfig): add types.d.ts convention
Browse files Browse the repository at this point in the history
supports #1036
  • Loading branch information
jasonkuhrt committed Jun 16, 2020
1 parent 2f33a25 commit 699b380
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 9 deletions.
8 changes: 8 additions & 0 deletions docs/guides/project-layout.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,14 @@ Autocomplete with Nexus TS LSP:

![](https://user-images.githubusercontent.com/284476/82776802-1cef3b00-9e1a-11ea-88c3-065869407380.png)

##### Conventions

Nexus has some conventions about `tsconfig.json` settings designed to support your zero-config experience.

###### Local Typing Declaration File

Sometimes you need to augment or provide outright types for some third party library. Do this by creating a `types.d.ts` in your project root. Nexus automatically configures `tsconfig.json` to pick this file up.

## Conventions

Nexus imposes a few requirements about how you structure your codebase.
Expand Down
26 changes: 20 additions & 6 deletions src/lib/layout/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ function tsconfig(input?: TsConfigJson): TsConfigJson {
rootDir: '.',
plugins: [{ name: NEXUS_TS_LSP_IMPORT_ID }],
},
include: ['.'],
include: ['types.d.ts', '.'],
}
return defaultsDeep(input, defaultTsConfigContent)
}
Expand Down Expand Up @@ -152,6 +152,17 @@ describe('tsconfig', () => {
ctx.setup({ 'app.ts': '' })
})

it('warns if "types.d.ts" is missing from include', async () => {
ctx.setup({
'tsconfig.json': tsconfigSource({ include: ['.'] }),
})
await ctx.createLayoutThrow()
expect(logs).toMatchInlineSnapshot(`
"▲ nexus:tsconfig Please add \\"types.d.ts\\" to your \\"include\\" array. If you do not then results from Nexus and your IDE will not agree if the declaration file is used in your project.
"
`)
})

it('fails if tsconfig settings does not lead to matching any source files', async () => {
ctx.fs.remove('app.ts')
const res = await ctx.createLayout().then(leftOrThrow)
Expand All @@ -162,7 +173,7 @@ describe('tsconfig', () => {
Object {
"category": 1,
"code": 18003,
"messageText": "No inputs were found in config file '__DYNAMIC__/tsconfig.json'. Specified 'include' paths were '[\\".\\"]' and 'exclude' paths were '[]'.",
"messageText": "No inputs were found in config file '__DYNAMIC__/tsconfig.json'. Specified 'include' paths were '[\\"types.d.ts\\",\\".\\"]' and 'exclude' paths were '[]'.",
},
],
},
Expand Down Expand Up @@ -196,14 +207,15 @@ describe('tsconfig', () => {
"target": "es2016",
},
"include": Array [
"types.d.ts",
".",
],
}
`)
})

describe('composite projects', () => {
it('inheritable settigs are recognized but include rootDir and plugins must be local', async () => {
it('inheritable settigs are recognized but "include", "rootDir", "plugins" must be local', async () => {
nestTmpDir()
ctx.fs.write('src/app.ts', '')
ctx.fs.write('../tsconfig.packages.json', tsconfigSource())
Expand All @@ -216,7 +228,8 @@ describe('tsconfig', () => {
\\"plugins\\": [{ \\"name\\": \\"nexus/typescript-language-service\\" }]
▲ nexus:tsconfig Please set \`compilerOptions.rootDir\` to \\".\\"
▲ nexus:tsconfig Please add \\"types.d.ts\\" to your \\"include\\" array. If you do not then results from Nexus and your IDE will not agree if the declaration file is used in your project.
▲ nexus:tsconfig Please set \`compilerOptions.rootDir\` to \\".\\"
▲ nexus:tsconfig Please set \`include\` to have \\".\\"
"
`)
Expand Down Expand Up @@ -273,12 +286,13 @@ describe('tsconfig', () => {
})
const layout = await ctx.createLayoutThrow()
expect(logs).toMatchInlineSnapshot(`
"▲ nexus:tsconfig Please set \`compilerOptions.rootDir\` to \\".\\"
"▲ nexus:tsconfig Please add \\"types.d.ts\\" to your \\"include\\" array. If you do not then results from Nexus and your IDE will not agree if the declaration file is used in your project.
▲ nexus:tsconfig Please set \`compilerOptions.rootDir\` to \\".\\"
▲ nexus:tsconfig Please set \`include\` to have \\".\\"
"
`)
expect(layout.tsConfig.content.raw.compilerOptions.rootDir).toEqual('.')
expect(layout.tsConfig.content.raw.include).toEqual(['.'])
expect(layout.tsConfig.content.raw.include).toEqual(['types.d.ts', '.'])
})
it('need the Nexus TS LSP setup', async () => {
ctx.setup({
Expand Down
30 changes: 27 additions & 3 deletions src/lib/layout/tsconfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,19 @@ export async function readOrScaffoldTsconfig(input: {
)
}

/**
* Setup types declaration file support
*/

if (!tsconfigSourceOriginal.include?.includes('types.d.ts')) {
tsconfigSource.include.push('types.d.ts')
const val = chalk.yellowBright(`"types.d.ts"`)
const setting = chalk.yellowBright(`"include"`)
log.warn(
`Please add ${val} to your ${setting} array. If you do not then results from Nexus and your IDE will not agree if the declaration file is used in your project.`
)
}

/**
* Setup source root (aka. rootDir)
*/
Expand All @@ -174,7 +187,8 @@ export async function readOrScaffoldTsconfig(input: {
if (!tsconfigSource.compilerOptions.rootDir) {
tsconfigSource.compilerOptions.rootDir = '.'
const setting = renderSetting('compilerOptions.rootDir')
log.warn(`Please set ${setting} to "${tsconfigSource.compilerOptions.rootDir}"`)
const val = renderValString(tsconfigSource.compilerOptions.rootDir)
log.warn(`Please set ${setting} to ${val}`)
}

if (!tsconfigSource.include.includes(tsconfigSource.compilerOptions.rootDir!)) {
Expand Down Expand Up @@ -240,6 +254,9 @@ export async function readOrScaffoldTsconfig(input: {
return right({ content: tsconfigParsed, path: tsconfigPath })
}

/**
* Create tsconfig source contents, optimized for Nexus
*/
export function tsconfigTemplate(input: { sourceRootRelative: string; outRootRelative: string }): string {
// Render empty source root as '.' which is what node path module relative func will do when same dir.
const sourceRelative = input.sourceRootRelative || '.'
Expand All @@ -253,14 +270,21 @@ export function tsconfigTemplate(input: { sourceRootRelative: string; outRootRel
noEmit: true,
plugins: [{ name: 'nexus/typescript-language-service' }],
},
include: [sourceRelative],
include: ['types.d.ts', sourceRelative],
}
return JSON.stringify(config, null, 2)
}

/**
* Prettifier a property path for terminal output.
* Prettify a property path for terminal output.
*/
function renderSetting(setting: string) {
return chalk.yellowBright(`\`${setting}\``)
}

/**
* Prettify a JSON string value for terminal output.
*/
function renderValString(val: string): string {
return chalk.yellowBright(`"${val}"`)
}
8 changes: 8 additions & 0 deletions website/content/02-guides/06-project-layout.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ Autocomplete with Nexus TS LSP:

![](https://user-images.githubusercontent.com/284476/82776802-1cef3b00-9e1a-11ea-88c3-065869407380.png)

### Conventions

Nexus has some conventions about `tsconfig.json` settings designed to support your zero-config experience.

#### Local Typing Declaration File

Sometimes you need to augment or provide outright types for some third party library. Do this by creating a `types.d.ts` in your project root. Nexus automatically configures `tsconfig.json` to pick this file up.

## Conventions

Nexus imposes a few requirements about how you structure your codebase.
Expand Down

0 comments on commit 699b380

Please sign in to comment.