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 () => {
|
it('should add extended config files', async () => {
|
||||||
await applyFilesToTempFsAndContext(tempFs, context, {
|
await applyFilesToTempFsAndContext(tempFs, context, {
|
||||||
'tsconfig.base.json': JSON.stringify({
|
'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 () => {
|
it('should only add exclude paths that are not part of other tsconfig files include paths', async () => {
|
||||||
// exact match
|
// exact match
|
||||||
await applyFilesToTempFsAndContext(tempFs, context, {
|
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 () => {
|
it('should be able to extended config files', async () => {
|
||||||
await applyFilesToTempFsAndContext(tempFs, context, {
|
await applyFilesToTempFsAndContext(tempFs, context, {
|
||||||
'tsconfig.base.json': JSON.stringify({
|
'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 () => {
|
it('should only add exclude paths that are not part of other tsconfig files include paths', async () => {
|
||||||
// exact match
|
// exact match
|
||||||
await applyFilesToTempFsAndContext(tempFs, context, {
|
await applyFilesToTempFsAndContext(tempFs, context, {
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import {
|
import {
|
||||||
CreateNodesContextV2,
|
|
||||||
createNodesFromFiles,
|
createNodesFromFiles,
|
||||||
detectPackageManager,
|
detectPackageManager,
|
||||||
getPackageManagerCommand,
|
getPackageManagerCommand,
|
||||||
@ -11,18 +10,17 @@ import {
|
|||||||
type CreateDependencies,
|
type CreateDependencies,
|
||||||
type CreateNodes,
|
type CreateNodes,
|
||||||
type CreateNodesContext,
|
type CreateNodesContext,
|
||||||
|
type CreateNodesContextV2,
|
||||||
type CreateNodesV2,
|
type CreateNodesV2,
|
||||||
type NxJsonConfiguration,
|
type NxJsonConfiguration,
|
||||||
type ProjectConfiguration,
|
type ProjectConfiguration,
|
||||||
type TargetConfiguration,
|
type TargetConfiguration,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { getNamedInputs } from '@nx/devkit/src/utils/get-named-inputs';
|
import { getNamedInputs } from '@nx/devkit/src/utils/get-named-inputs';
|
||||||
import picomatch = require('picomatch');
|
|
||||||
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
|
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
|
||||||
import {
|
import {
|
||||||
basename,
|
basename,
|
||||||
dirname,
|
dirname,
|
||||||
extname,
|
|
||||||
join,
|
join,
|
||||||
normalize,
|
normalize,
|
||||||
relative,
|
relative,
|
||||||
@ -31,10 +29,11 @@ import {
|
|||||||
} from 'node:path';
|
} from 'node:path';
|
||||||
import * as posix from 'node:path/posix';
|
import * as posix from 'node:path/posix';
|
||||||
import { hashArray, hashFile, hashObject } from 'nx/src/hasher/file-hasher';
|
import { hashArray, hashFile, hashObject } from 'nx/src/hasher/file-hasher';
|
||||||
|
import picomatch = require('picomatch');
|
||||||
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
|
// eslint-disable-next-line @typescript-eslint/no-restricted-imports
|
||||||
import { getLockFileName } from 'nx/src/plugins/js/lock-file/lock-file';
|
import { getLockFileName } from 'nx/src/plugins/js/lock-file/lock-file';
|
||||||
import { workspaceDataDirectory } from 'nx/src/utils/cache-directory';
|
import { workspaceDataDirectory } from 'nx/src/utils/cache-directory';
|
||||||
import type { ParsedCommandLine, System } from 'typescript';
|
import type { Extension, ParsedCommandLine, System } from 'typescript';
|
||||||
import {
|
import {
|
||||||
addBuildAndWatchDepsTargets,
|
addBuildAndWatchDepsTargets,
|
||||||
isValidPackageJsonBuildConfig,
|
isValidPackageJsonBuildConfig,
|
||||||
@ -83,6 +82,7 @@ type TsconfigCacheData = {
|
|||||||
extendedFilesHash: string;
|
extendedFilesHash: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let ts: typeof import('typescript');
|
||||||
const pmc = getPackageManagerCommand();
|
const pmc = getPackageManagerCommand();
|
||||||
|
|
||||||
let tsConfigCache: Record<string, TsconfigCacheData>;
|
let tsConfigCache: Record<string, TsconfigCacheData>;
|
||||||
@ -320,6 +320,9 @@ async function getConfigFileHash(
|
|||||||
lockFileHash,
|
lockFileHash,
|
||||||
optionsHash,
|
optionsHash,
|
||||||
...(packageJson ? [hashObject(packageJson)] : []),
|
...(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),
|
...Object.entries(internalProjectReferences),
|
||||||
];
|
];
|
||||||
const absoluteProjectRoot = join(workspaceRoot, projectRoot);
|
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]) => {
|
projectTsConfigFiles.forEach(([configPath, config]) => {
|
||||||
configFiles.add(configPath);
|
configFiles.add(configPath);
|
||||||
const offset = relative(absoluteProjectRoot, dirname(configPath));
|
const offset = relative(absoluteProjectRoot, dirname(configPath));
|
||||||
(config.raw?.include ?? []).forEach((p: string) =>
|
(config.raw?.include ?? []).forEach((p: string) => {
|
||||||
includePaths.add(join(offset, p))
|
const normalized = normalizeInput(join(offset, p), config);
|
||||||
);
|
normalized.forEach((input) => includePaths.add(input));
|
||||||
|
});
|
||||||
|
|
||||||
if (config.raw?.exclude) {
|
if (config.raw?.exclude) {
|
||||||
/**
|
/**
|
||||||
@ -1071,7 +1127,6 @@ function getExtendedFilesHash(
|
|||||||
return hashes.join('|');
|
return hashes.join('|');
|
||||||
}
|
}
|
||||||
|
|
||||||
let ts: typeof import('typescript');
|
|
||||||
function readTsConfig(
|
function readTsConfig(
|
||||||
tsConfigPath: string,
|
tsConfigPath: string,
|
||||||
workspaceRoot: string
|
workspaceRoot: string
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user