fix(js): normalize tsconfig include paths correctly in @nx/js/typescript plugin (#30496)
## Current Behavior The `@nx/js/typescript` plugin infers incorrect inputs for tsconfig `include` patterns when their last segment doesn't contain a wildcard or an extension (e.g. `"include": ["src"]`). ## Expected Behavior The `@nx/js/typescript` plugin should [normalize such `include` patterns](https://www.typescriptlang.org/tsconfig/#include) and infer valid inputs. ## Related Issue(s) Fixes #30014
This commit is contained in:
parent
9cd7579040
commit
ab311c0f07
@ -795,6 +795,307 @@ describe(`Plugin: ${PLUGIN_NAME}`, () => {
|
||||
`);
|
||||
});
|
||||
|
||||
it('should normalize and add directories in `include` with the ts extensions', async () => {
|
||||
await applyFilesToTempFsAndContext(tempFs, context, {
|
||||
'libs/my-lib/tsconfig.json': JSON.stringify({
|
||||
include: ['src'],
|
||||
// set this to keep outputs smaller
|
||||
compilerOptions: { outDir: 'dist' },
|
||||
}),
|
||||
'libs/my-lib/package.json': `{}`,
|
||||
});
|
||||
|
||||
expect(await invokeCreateNodesOnMatchingFiles(context, {}))
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"projects": {
|
||||
"libs/my-lib": {
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"typecheck": {
|
||||
"cache": true,
|
||||
"command": "tsc --build --emitDeclarationOnly",
|
||||
"dependsOn": [
|
||||
"^typecheck",
|
||||
],
|
||||
"inputs": [
|
||||
"{projectRoot}/package.json",
|
||||
"{projectRoot}/tsconfig.json",
|
||||
"{projectRoot}/src/**/*.ts",
|
||||
"{projectRoot}/src/**/*.tsx",
|
||||
"{projectRoot}/src/**/*.d.ts",
|
||||
"{projectRoot}/src/**/*.cts",
|
||||
"{projectRoot}/src/**/*.d.cts",
|
||||
"{projectRoot}/src/**/*.mts",
|
||||
"{projectRoot}/src/**/*.d.mts",
|
||||
"^production",
|
||||
{
|
||||
"externalDependencies": [
|
||||
"typescript",
|
||||
],
|
||||
},
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs type-checking for the project.",
|
||||
"help": {
|
||||
"command": "npx tsc --build --help",
|
||||
"example": {
|
||||
"args": [
|
||||
"--force",
|
||||
],
|
||||
},
|
||||
},
|
||||
"technologies": [
|
||||
"typescript",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "libs/my-lib",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/dist",
|
||||
],
|
||||
"syncGenerators": [
|
||||
"@nx/js:typescript-sync",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should normalize and add directories in `include` with the ts and js extensions when `allowJs` is true', async () => {
|
||||
await applyFilesToTempFsAndContext(tempFs, context, {
|
||||
'libs/my-lib/tsconfig.json': JSON.stringify({
|
||||
include: ['src'],
|
||||
// set this to keep outputs smaller
|
||||
compilerOptions: { outDir: 'dist', allowJs: true },
|
||||
}),
|
||||
'libs/my-lib/package.json': `{}`,
|
||||
});
|
||||
|
||||
expect(await invokeCreateNodesOnMatchingFiles(context, {}))
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"projects": {
|
||||
"libs/my-lib": {
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"typecheck": {
|
||||
"cache": true,
|
||||
"command": "tsc --build --emitDeclarationOnly",
|
||||
"dependsOn": [
|
||||
"^typecheck",
|
||||
],
|
||||
"inputs": [
|
||||
"{projectRoot}/package.json",
|
||||
"{projectRoot}/tsconfig.json",
|
||||
"{projectRoot}/src/**/*.ts",
|
||||
"{projectRoot}/src/**/*.tsx",
|
||||
"{projectRoot}/src/**/*.d.ts",
|
||||
"{projectRoot}/src/**/*.js",
|
||||
"{projectRoot}/src/**/*.jsx",
|
||||
"{projectRoot}/src/**/*.cts",
|
||||
"{projectRoot}/src/**/*.d.cts",
|
||||
"{projectRoot}/src/**/*.cjs",
|
||||
"{projectRoot}/src/**/*.mts",
|
||||
"{projectRoot}/src/**/*.d.mts",
|
||||
"{projectRoot}/src/**/*.mjs",
|
||||
"^production",
|
||||
{
|
||||
"externalDependencies": [
|
||||
"typescript",
|
||||
],
|
||||
},
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs type-checking for the project.",
|
||||
"help": {
|
||||
"command": "npx tsc --build --help",
|
||||
"example": {
|
||||
"args": [
|
||||
"--force",
|
||||
],
|
||||
},
|
||||
},
|
||||
"technologies": [
|
||||
"typescript",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "libs/my-lib",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/dist",
|
||||
],
|
||||
"syncGenerators": [
|
||||
"@nx/js:typescript-sync",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should normalize and add directories in `include` with the ts and json extensions when `resolveJsonModule` is true', async () => {
|
||||
await applyFilesToTempFsAndContext(tempFs, context, {
|
||||
'libs/my-lib/tsconfig.json': JSON.stringify({
|
||||
include: ['src'],
|
||||
// set this to keep outputs smaller
|
||||
compilerOptions: {
|
||||
outDir: 'dist',
|
||||
resolveJsonModule: true,
|
||||
},
|
||||
}),
|
||||
'libs/my-lib/package.json': `{}`,
|
||||
});
|
||||
|
||||
expect(await invokeCreateNodesOnMatchingFiles(context, {}))
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"projects": {
|
||||
"libs/my-lib": {
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"typecheck": {
|
||||
"cache": true,
|
||||
"command": "tsc --build --emitDeclarationOnly",
|
||||
"dependsOn": [
|
||||
"^typecheck",
|
||||
],
|
||||
"inputs": [
|
||||
"{projectRoot}/package.json",
|
||||
"{projectRoot}/tsconfig.json",
|
||||
"{projectRoot}/src/**/*.ts",
|
||||
"{projectRoot}/src/**/*.tsx",
|
||||
"{projectRoot}/src/**/*.d.ts",
|
||||
"{projectRoot}/src/**/*.cts",
|
||||
"{projectRoot}/src/**/*.d.cts",
|
||||
"{projectRoot}/src/**/*.mts",
|
||||
"{projectRoot}/src/**/*.d.mts",
|
||||
"{projectRoot}/src/**/*.json",
|
||||
"^production",
|
||||
{
|
||||
"externalDependencies": [
|
||||
"typescript",
|
||||
],
|
||||
},
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs type-checking for the project.",
|
||||
"help": {
|
||||
"command": "npx tsc --build --help",
|
||||
"example": {
|
||||
"args": [
|
||||
"--force",
|
||||
],
|
||||
},
|
||||
},
|
||||
"technologies": [
|
||||
"typescript",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "libs/my-lib",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/dist",
|
||||
],
|
||||
"syncGenerators": [
|
||||
"@nx/js:typescript-sync",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should normalize and add directories in `include` with the ts, js and json extensions when `allowJs` and `resolveJsonModule` are true', async () => {
|
||||
await applyFilesToTempFsAndContext(tempFs, context, {
|
||||
'libs/my-lib/tsconfig.json': JSON.stringify({
|
||||
include: ['src'],
|
||||
// set this to keep outputs smaller
|
||||
compilerOptions: {
|
||||
outDir: 'dist',
|
||||
allowJs: true,
|
||||
resolveJsonModule: true,
|
||||
},
|
||||
}),
|
||||
'libs/my-lib/package.json': `{}`,
|
||||
});
|
||||
|
||||
expect(await invokeCreateNodesOnMatchingFiles(context, {}))
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"projects": {
|
||||
"libs/my-lib": {
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"typecheck": {
|
||||
"cache": true,
|
||||
"command": "tsc --build --emitDeclarationOnly",
|
||||
"dependsOn": [
|
||||
"^typecheck",
|
||||
],
|
||||
"inputs": [
|
||||
"{projectRoot}/package.json",
|
||||
"{projectRoot}/tsconfig.json",
|
||||
"{projectRoot}/src/**/*.ts",
|
||||
"{projectRoot}/src/**/*.tsx",
|
||||
"{projectRoot}/src/**/*.d.ts",
|
||||
"{projectRoot}/src/**/*.js",
|
||||
"{projectRoot}/src/**/*.jsx",
|
||||
"{projectRoot}/src/**/*.cts",
|
||||
"{projectRoot}/src/**/*.d.cts",
|
||||
"{projectRoot}/src/**/*.cjs",
|
||||
"{projectRoot}/src/**/*.mts",
|
||||
"{projectRoot}/src/**/*.d.mts",
|
||||
"{projectRoot}/src/**/*.mjs",
|
||||
"{projectRoot}/src/**/*.json",
|
||||
"^production",
|
||||
{
|
||||
"externalDependencies": [
|
||||
"typescript",
|
||||
],
|
||||
},
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs type-checking for the project.",
|
||||
"help": {
|
||||
"command": "npx tsc --build --help",
|
||||
"example": {
|
||||
"args": [
|
||||
"--force",
|
||||
],
|
||||
},
|
||||
},
|
||||
"technologies": [
|
||||
"typescript",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "libs/my-lib",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/dist",
|
||||
],
|
||||
"syncGenerators": [
|
||||
"@nx/js:typescript-sync",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should add extended config files', async () => {
|
||||
await applyFilesToTempFsAndContext(tempFs, context, {
|
||||
'tsconfig.base.json': JSON.stringify({
|
||||
@ -1107,6 +1408,103 @@ describe(`Plugin: ${PLUGIN_NAME}`, () => {
|
||||
`);
|
||||
});
|
||||
|
||||
it('should normalize and add directories in `include` from internal project references', async () => {
|
||||
await applyFilesToTempFsAndContext(tempFs, context, {
|
||||
'libs/my-lib/tsconfig.json': JSON.stringify({
|
||||
files: [],
|
||||
include: [],
|
||||
references: [
|
||||
{ path: './tsconfig.lib.json' },
|
||||
{ path: './tsconfig.spec.json' },
|
||||
],
|
||||
// set this to keep outputs smaller
|
||||
compilerOptions: { outDir: 'dist' },
|
||||
}),
|
||||
'libs/my-lib/tsconfig.lib.json': JSON.stringify({
|
||||
include: ['src/**/*.ts'],
|
||||
exclude: ['tests'], // should be ignored because another referenced internal project includes this same pattern
|
||||
// set this to keep outputs smaller
|
||||
compilerOptions: { outDir: 'dist' },
|
||||
}),
|
||||
'libs/my-lib/tsconfig.spec.json': JSON.stringify({
|
||||
include: ['tests'], // directory pattern that should be normalized
|
||||
references: [{ path: './tsconfig.lib.json' }],
|
||||
compilerOptions: {
|
||||
outDir: 'dist', // set this to keep outputs smaller
|
||||
allowJs: true, // should result in including js extensions in the normalized include paths
|
||||
},
|
||||
}),
|
||||
'libs/my-lib/package.json': `{}`,
|
||||
});
|
||||
|
||||
expect(await invokeCreateNodesOnMatchingFiles(context, {}))
|
||||
.toMatchInlineSnapshot(`
|
||||
{
|
||||
"projects": {
|
||||
"libs/my-lib": {
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"typecheck": {
|
||||
"cache": true,
|
||||
"command": "tsc --build --emitDeclarationOnly",
|
||||
"dependsOn": [
|
||||
"^typecheck",
|
||||
],
|
||||
"inputs": [
|
||||
"{projectRoot}/package.json",
|
||||
"{projectRoot}/tsconfig.json",
|
||||
"{projectRoot}/tsconfig.lib.json",
|
||||
"{projectRoot}/tsconfig.spec.json",
|
||||
"{projectRoot}/src/**/*.ts",
|
||||
"{projectRoot}/tests/**/*.ts",
|
||||
"{projectRoot}/tests/**/*.tsx",
|
||||
"{projectRoot}/tests/**/*.d.ts",
|
||||
"{projectRoot}/tests/**/*.js",
|
||||
"{projectRoot}/tests/**/*.jsx",
|
||||
"{projectRoot}/tests/**/*.cts",
|
||||
"{projectRoot}/tests/**/*.d.cts",
|
||||
"{projectRoot}/tests/**/*.cjs",
|
||||
"{projectRoot}/tests/**/*.mts",
|
||||
"{projectRoot}/tests/**/*.d.mts",
|
||||
"{projectRoot}/tests/**/*.mjs",
|
||||
"^production",
|
||||
{
|
||||
"externalDependencies": [
|
||||
"typescript",
|
||||
],
|
||||
},
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Runs type-checking for the project.",
|
||||
"help": {
|
||||
"command": "npx tsc --build --help",
|
||||
"example": {
|
||||
"args": [
|
||||
"--force",
|
||||
],
|
||||
},
|
||||
},
|
||||
"technologies": [
|
||||
"typescript",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "libs/my-lib",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/dist",
|
||||
],
|
||||
"syncGenerators": [
|
||||
"@nx/js:typescript-sync",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should only add exclude paths that are not part of other tsconfig files include paths', async () => {
|
||||
// exact match
|
||||
await applyFilesToTempFsAndContext(tempFs, context, {
|
||||
@ -2845,6 +3243,320 @@ describe(`Plugin: ${PLUGIN_NAME}`, () => {
|
||||
`);
|
||||
});
|
||||
|
||||
it('should normalize and add directories in `include` with the ts extensions', async () => {
|
||||
await applyFilesToTempFsAndContext(tempFs, context, {
|
||||
'libs/my-lib/tsconfig.lib.json': JSON.stringify({
|
||||
compilerOptions: { outDir: 'dist' },
|
||||
include: ['src'],
|
||||
}),
|
||||
'libs/my-lib/tsconfig.json': `{}`,
|
||||
'libs/my-lib/package.json': `{"main": "dist/index.js"}`,
|
||||
});
|
||||
|
||||
expect(
|
||||
await invokeCreateNodesOnMatchingFiles(context, {
|
||||
typecheck: false,
|
||||
build: true,
|
||||
})
|
||||
).toMatchInlineSnapshot(`
|
||||
{
|
||||
"projects": {
|
||||
"libs/my-lib": {
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"build": {
|
||||
"cache": true,
|
||||
"command": "tsc --build tsconfig.lib.json",
|
||||
"dependsOn": [
|
||||
"^build",
|
||||
],
|
||||
"inputs": [
|
||||
"{projectRoot}/package.json",
|
||||
"{projectRoot}/tsconfig.lib.json",
|
||||
"{projectRoot}/src/**/*.ts",
|
||||
"{projectRoot}/src/**/*.tsx",
|
||||
"{projectRoot}/src/**/*.d.ts",
|
||||
"{projectRoot}/src/**/*.cts",
|
||||
"{projectRoot}/src/**/*.d.cts",
|
||||
"{projectRoot}/src/**/*.mts",
|
||||
"{projectRoot}/src/**/*.d.mts",
|
||||
"^production",
|
||||
{
|
||||
"externalDependencies": [
|
||||
"typescript",
|
||||
],
|
||||
},
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Builds the project with \`tsc\`.",
|
||||
"help": {
|
||||
"command": "npx tsc --build --help",
|
||||
"example": {
|
||||
"args": [
|
||||
"--force",
|
||||
],
|
||||
},
|
||||
},
|
||||
"technologies": [
|
||||
"typescript",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "libs/my-lib",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/dist",
|
||||
],
|
||||
"syncGenerators": [
|
||||
"@nx/js:typescript-sync",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should normalize and add directories in `include` with the ts and js extensions when `allowJs` is true', async () => {
|
||||
await applyFilesToTempFsAndContext(tempFs, context, {
|
||||
'libs/my-lib/tsconfig.lib.json': JSON.stringify({
|
||||
compilerOptions: { outDir: 'dist', allowJs: true },
|
||||
include: ['src'],
|
||||
}),
|
||||
'libs/my-lib/tsconfig.json': `{}`,
|
||||
'libs/my-lib/package.json': `{"main": "dist/index.js"}`,
|
||||
});
|
||||
|
||||
expect(
|
||||
await invokeCreateNodesOnMatchingFiles(context, {
|
||||
typecheck: false,
|
||||
build: true,
|
||||
})
|
||||
).toMatchInlineSnapshot(`
|
||||
{
|
||||
"projects": {
|
||||
"libs/my-lib": {
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"build": {
|
||||
"cache": true,
|
||||
"command": "tsc --build tsconfig.lib.json",
|
||||
"dependsOn": [
|
||||
"^build",
|
||||
],
|
||||
"inputs": [
|
||||
"{projectRoot}/package.json",
|
||||
"{projectRoot}/tsconfig.lib.json",
|
||||
"{projectRoot}/src/**/*.ts",
|
||||
"{projectRoot}/src/**/*.tsx",
|
||||
"{projectRoot}/src/**/*.d.ts",
|
||||
"{projectRoot}/src/**/*.js",
|
||||
"{projectRoot}/src/**/*.jsx",
|
||||
"{projectRoot}/src/**/*.cts",
|
||||
"{projectRoot}/src/**/*.d.cts",
|
||||
"{projectRoot}/src/**/*.cjs",
|
||||
"{projectRoot}/src/**/*.mts",
|
||||
"{projectRoot}/src/**/*.d.mts",
|
||||
"{projectRoot}/src/**/*.mjs",
|
||||
"^production",
|
||||
{
|
||||
"externalDependencies": [
|
||||
"typescript",
|
||||
],
|
||||
},
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Builds the project with \`tsc\`.",
|
||||
"help": {
|
||||
"command": "npx tsc --build --help",
|
||||
"example": {
|
||||
"args": [
|
||||
"--force",
|
||||
],
|
||||
},
|
||||
},
|
||||
"technologies": [
|
||||
"typescript",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "libs/my-lib",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/dist",
|
||||
],
|
||||
"syncGenerators": [
|
||||
"@nx/js:typescript-sync",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should normalize and add directories in `include` with the ts and json extensions when `resolveJsonModule` is true', async () => {
|
||||
await applyFilesToTempFsAndContext(tempFs, context, {
|
||||
'libs/my-lib/tsconfig.lib.json': JSON.stringify({
|
||||
compilerOptions: { outDir: 'dist', resolveJsonModule: true },
|
||||
include: ['src'],
|
||||
}),
|
||||
'libs/my-lib/tsconfig.json': `{}`,
|
||||
'libs/my-lib/package.json': `{"main": "dist/index.js"}`,
|
||||
});
|
||||
|
||||
expect(
|
||||
await invokeCreateNodesOnMatchingFiles(context, {
|
||||
typecheck: false,
|
||||
build: true,
|
||||
})
|
||||
).toMatchInlineSnapshot(`
|
||||
{
|
||||
"projects": {
|
||||
"libs/my-lib": {
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"build": {
|
||||
"cache": true,
|
||||
"command": "tsc --build tsconfig.lib.json",
|
||||
"dependsOn": [
|
||||
"^build",
|
||||
],
|
||||
"inputs": [
|
||||
"{projectRoot}/package.json",
|
||||
"{projectRoot}/tsconfig.lib.json",
|
||||
"{projectRoot}/src/**/*.ts",
|
||||
"{projectRoot}/src/**/*.tsx",
|
||||
"{projectRoot}/src/**/*.d.ts",
|
||||
"{projectRoot}/src/**/*.cts",
|
||||
"{projectRoot}/src/**/*.d.cts",
|
||||
"{projectRoot}/src/**/*.mts",
|
||||
"{projectRoot}/src/**/*.d.mts",
|
||||
"{projectRoot}/src/**/*.json",
|
||||
"^production",
|
||||
{
|
||||
"externalDependencies": [
|
||||
"typescript",
|
||||
],
|
||||
},
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Builds the project with \`tsc\`.",
|
||||
"help": {
|
||||
"command": "npx tsc --build --help",
|
||||
"example": {
|
||||
"args": [
|
||||
"--force",
|
||||
],
|
||||
},
|
||||
},
|
||||
"technologies": [
|
||||
"typescript",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "libs/my-lib",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/dist",
|
||||
],
|
||||
"syncGenerators": [
|
||||
"@nx/js:typescript-sync",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should normalize and add directories in `include` with the ts, js and json extensions when `allowJs` and `resolveJsonModule` are true', async () => {
|
||||
await applyFilesToTempFsAndContext(tempFs, context, {
|
||||
'libs/my-lib/tsconfig.lib.json': JSON.stringify({
|
||||
compilerOptions: {
|
||||
outDir: 'dist',
|
||||
allowJs: true,
|
||||
resolveJsonModule: true,
|
||||
},
|
||||
include: ['src'],
|
||||
}),
|
||||
'libs/my-lib/tsconfig.json': `{}`,
|
||||
'libs/my-lib/package.json': `{"main": "dist/index.js"}`,
|
||||
});
|
||||
|
||||
expect(
|
||||
await invokeCreateNodesOnMatchingFiles(context, {
|
||||
typecheck: false,
|
||||
build: true,
|
||||
})
|
||||
).toMatchInlineSnapshot(`
|
||||
{
|
||||
"projects": {
|
||||
"libs/my-lib": {
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"build": {
|
||||
"cache": true,
|
||||
"command": "tsc --build tsconfig.lib.json",
|
||||
"dependsOn": [
|
||||
"^build",
|
||||
],
|
||||
"inputs": [
|
||||
"{projectRoot}/package.json",
|
||||
"{projectRoot}/tsconfig.lib.json",
|
||||
"{projectRoot}/src/**/*.ts",
|
||||
"{projectRoot}/src/**/*.tsx",
|
||||
"{projectRoot}/src/**/*.d.ts",
|
||||
"{projectRoot}/src/**/*.js",
|
||||
"{projectRoot}/src/**/*.jsx",
|
||||
"{projectRoot}/src/**/*.cts",
|
||||
"{projectRoot}/src/**/*.d.cts",
|
||||
"{projectRoot}/src/**/*.cjs",
|
||||
"{projectRoot}/src/**/*.mts",
|
||||
"{projectRoot}/src/**/*.d.mts",
|
||||
"{projectRoot}/src/**/*.mjs",
|
||||
"{projectRoot}/src/**/*.json",
|
||||
"^production",
|
||||
{
|
||||
"externalDependencies": [
|
||||
"typescript",
|
||||
],
|
||||
},
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Builds the project with \`tsc\`.",
|
||||
"help": {
|
||||
"command": "npx tsc --build --help",
|
||||
"example": {
|
||||
"args": [
|
||||
"--force",
|
||||
],
|
||||
},
|
||||
},
|
||||
"technologies": [
|
||||
"typescript",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "libs/my-lib",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/dist",
|
||||
],
|
||||
"syncGenerators": [
|
||||
"@nx/js:typescript-sync",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should be able to extended config files', async () => {
|
||||
await applyFilesToTempFsAndContext(tempFs, context, {
|
||||
'tsconfig.base.json': JSON.stringify({
|
||||
@ -3100,6 +3812,94 @@ describe(`Plugin: ${PLUGIN_NAME}`, () => {
|
||||
`);
|
||||
});
|
||||
|
||||
it('should normalize and add directories in `include` from internal project references', async () => {
|
||||
await applyFilesToTempFsAndContext(tempFs, context, {
|
||||
'libs/my-lib/tsconfig.json': '{}',
|
||||
'libs/my-lib/tsconfig.lib.json': JSON.stringify({
|
||||
compilerOptions: { outDir: 'dist' },
|
||||
include: ['src/**/*.ts'],
|
||||
exclude: ['src/**/foo.ts'], // should be ignored because a referenced internal project includes this same pattern
|
||||
references: [{ path: './tsconfig.other.json' }],
|
||||
}),
|
||||
'libs/my-lib/tsconfig.other.json': JSON.stringify({
|
||||
include: ['other', 'src/**/foo.ts'],
|
||||
compilerOptions: {
|
||||
outDir: 'dist', // set this to keep outputs smaller
|
||||
resolveJsonModule: true, // should result in including json extensions in the normalized include paths
|
||||
},
|
||||
}),
|
||||
'libs/my-lib/package.json': `{"main": "dist/index.js"}`, // Should be defined so that the project is considered buildable
|
||||
});
|
||||
|
||||
expect(
|
||||
await invokeCreateNodesOnMatchingFiles(context, {
|
||||
typecheck: false,
|
||||
build: true,
|
||||
})
|
||||
).toMatchInlineSnapshot(`
|
||||
{
|
||||
"projects": {
|
||||
"libs/my-lib": {
|
||||
"projectType": "library",
|
||||
"targets": {
|
||||
"build": {
|
||||
"cache": true,
|
||||
"command": "tsc --build tsconfig.lib.json",
|
||||
"dependsOn": [
|
||||
"^build",
|
||||
],
|
||||
"inputs": [
|
||||
"{projectRoot}/package.json",
|
||||
"{projectRoot}/tsconfig.lib.json",
|
||||
"{projectRoot}/tsconfig.other.json",
|
||||
"{projectRoot}/src/**/*.ts",
|
||||
"{projectRoot}/other/**/*.ts",
|
||||
"{projectRoot}/other/**/*.tsx",
|
||||
"{projectRoot}/other/**/*.d.ts",
|
||||
"{projectRoot}/other/**/*.cts",
|
||||
"{projectRoot}/other/**/*.d.cts",
|
||||
"{projectRoot}/other/**/*.mts",
|
||||
"{projectRoot}/other/**/*.d.mts",
|
||||
"{projectRoot}/other/**/*.json",
|
||||
"{projectRoot}/src/**/foo.ts",
|
||||
"^production",
|
||||
{
|
||||
"externalDependencies": [
|
||||
"typescript",
|
||||
],
|
||||
},
|
||||
],
|
||||
"metadata": {
|
||||
"description": "Builds the project with \`tsc\`.",
|
||||
"help": {
|
||||
"command": "npx tsc --build --help",
|
||||
"example": {
|
||||
"args": [
|
||||
"--force",
|
||||
],
|
||||
},
|
||||
},
|
||||
"technologies": [
|
||||
"typescript",
|
||||
],
|
||||
},
|
||||
"options": {
|
||||
"cwd": "libs/my-lib",
|
||||
},
|
||||
"outputs": [
|
||||
"{projectRoot}/dist",
|
||||
],
|
||||
"syncGenerators": [
|
||||
"@nx/js:typescript-sync",
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should only add exclude paths that are not part of other tsconfig files include paths', async () => {
|
||||
// exact match
|
||||
await applyFilesToTempFsAndContext(tempFs, context, {
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import {
|
||||
CreateNodesContextV2,
|
||||
createNodesFromFiles,
|
||||
detectPackageManager,
|
||||
getPackageManagerCommand,
|
||||
@ -11,18 +10,17 @@ import {
|
||||
type CreateDependencies,
|
||||
type CreateNodes,
|
||||
type CreateNodesContext,
|
||||
type CreateNodesContextV2,
|
||||
type CreateNodesV2,
|
||||
type NxJsonConfiguration,
|
||||
type ProjectConfiguration,
|
||||
type TargetConfiguration,
|
||||
} from '@nx/devkit';
|
||||
import { getNamedInputs } from '@nx/devkit/src/utils/get-named-inputs';
|
||||
import picomatch = require('picomatch');
|
||||
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
|
||||
import {
|
||||
basename,
|
||||
dirname,
|
||||
extname,
|
||||
join,
|
||||
normalize,
|
||||
relative,
|
||||
@ -31,10 +29,11 @@ import {
|
||||
} from 'node:path';
|
||||
import * as posix from 'node:path/posix';
|
||||
import { hashArray, hashFile, hashObject } from 'nx/src/hasher/file-hasher';
|
||||
import picomatch = require('picomatch');
|
||||
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
|
||||
import { getLockFileName } from 'nx/src/plugins/js/lock-file/lock-file';
|
||||
import { workspaceDataDirectory } from 'nx/src/utils/cache-directory';
|
||||
import type { ParsedCommandLine, System } from 'typescript';
|
||||
import type { Extension, ParsedCommandLine, System } from 'typescript';
|
||||
import {
|
||||
addBuildAndWatchDepsTargets,
|
||||
isValidPackageJsonBuildConfig,
|
||||
@ -83,6 +82,7 @@ type TsconfigCacheData = {
|
||||
extendedFilesHash: string;
|
||||
};
|
||||
|
||||
let ts: typeof import('typescript');
|
||||
const pmc = getPackageManagerCommand();
|
||||
|
||||
let tsConfigCache: Record<string, TsconfigCacheData>;
|
||||
@ -320,6 +320,9 @@ async function getConfigFileHash(
|
||||
lockFileHash,
|
||||
optionsHash,
|
||||
...(packageJson ? [hashObject(packageJson)] : []),
|
||||
// change this to bust the cache when making changes that would yield
|
||||
// different results for the same hash
|
||||
hashObject({ bust: 1 }),
|
||||
]);
|
||||
}
|
||||
|
||||
@ -534,12 +537,65 @@ function getInputs(
|
||||
...Object.entries(internalProjectReferences),
|
||||
];
|
||||
const absoluteProjectRoot = join(workspaceRoot, projectRoot);
|
||||
|
||||
if (!ts) {
|
||||
ts = require('typescript');
|
||||
}
|
||||
// https://github.com/microsoft/TypeScript/blob/19b777260b26aac5707b1efd34202054164d4a9d/src/compiler/utilities.ts#L9869
|
||||
const supportedTSExtensions: readonly Extension[] = [
|
||||
ts.Extension.Ts,
|
||||
ts.Extension.Tsx,
|
||||
ts.Extension.Dts,
|
||||
ts.Extension.Cts,
|
||||
ts.Extension.Dcts,
|
||||
ts.Extension.Mts,
|
||||
ts.Extension.Dmts,
|
||||
];
|
||||
// https://github.com/microsoft/TypeScript/blob/19b777260b26aac5707b1efd34202054164d4a9d/src/compiler/utilities.ts#L9878
|
||||
const allSupportedExtensions: readonly Extension[] = [
|
||||
ts.Extension.Ts,
|
||||
ts.Extension.Tsx,
|
||||
ts.Extension.Dts,
|
||||
ts.Extension.Js,
|
||||
ts.Extension.Jsx,
|
||||
ts.Extension.Cts,
|
||||
ts.Extension.Dcts,
|
||||
ts.Extension.Cjs,
|
||||
ts.Extension.Mts,
|
||||
ts.Extension.Dmts,
|
||||
ts.Extension.Mjs,
|
||||
];
|
||||
|
||||
const normalizeInput = (
|
||||
input: string,
|
||||
config: ParsedTsconfigData
|
||||
): string[] => {
|
||||
const extensions = config.options.allowJs
|
||||
? [...allSupportedExtensions]
|
||||
: [...supportedTSExtensions];
|
||||
if (config.options.resolveJsonModule) {
|
||||
extensions.push(ts.Extension.Json);
|
||||
}
|
||||
|
||||
const segments = input.split('/');
|
||||
// An "includes" path "foo" is implicitly a glob "foo/**/*" if its last
|
||||
// segment has no extension, and does not contain any glob characters
|
||||
// itself.
|
||||
// https://github.com/microsoft/TypeScript/blob/19b777260b26aac5707b1efd34202054164d4a9d/src/compiler/utilities.ts#L9577-L9585
|
||||
if (!/[.*?]/.test(segments.at(-1))) {
|
||||
return extensions.map((ext) => `${segments.join('/')}/**/*${ext}`);
|
||||
}
|
||||
|
||||
return [input];
|
||||
};
|
||||
|
||||
projectTsConfigFiles.forEach(([configPath, config]) => {
|
||||
configFiles.add(configPath);
|
||||
const offset = relative(absoluteProjectRoot, dirname(configPath));
|
||||
(config.raw?.include ?? []).forEach((p: string) =>
|
||||
includePaths.add(join(offset, p))
|
||||
);
|
||||
(config.raw?.include ?? []).forEach((p: string) => {
|
||||
const normalized = normalizeInput(join(offset, p), config);
|
||||
normalized.forEach((input) => includePaths.add(input));
|
||||
});
|
||||
|
||||
if (config.raw?.exclude) {
|
||||
/**
|
||||
@ -1071,7 +1127,6 @@ function getExtendedFilesHash(
|
||||
return hashes.join('|');
|
||||
}
|
||||
|
||||
let ts: typeof import('typescript');
|
||||
function readTsConfig(
|
||||
tsConfigPath: string,
|
||||
workspaceRoot: string
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user