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:
Leosvel Pérez Espinosa 2025-03-26 15:26:05 +01:00 committed by GitHub
parent 9cd7579040
commit ab311c0f07
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 863 additions and 8 deletions

View File

@ -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, {

View File

@ -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