fix(js): handle ts project refs pointing to non-existing files and prune ts refs for projects with no deps (#28130)

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #
This commit is contained in:
Leosvel Pérez Espinosa 2024-09-27 08:08:56 +02:00 committed by GitHub
parent 56eabffb2b
commit 5d6b3576f8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 52 additions and 7 deletions

View File

@ -371,12 +371,19 @@ describe('syncGenerator()', () => {
{ path: '../c' }, // this is not a dependency, should be pruned { path: '../c' }, // this is not a dependency, should be pruned
], ],
}); });
// add a project with no dependencies
addProject('c');
updateJson(tree, 'packages/c/tsconfig.json', (json) => {
// this is not a dependency, should be pruned
json.references = [{ path: '../d' }];
return json;
});
await syncGenerator(tree); await syncGenerator(tree);
const rootTsconfig = readJson(tree, 'packages/b/tsconfig.json'); const bTsconfigJson = readJson(tree, 'packages/b/tsconfig.json');
// The dependency reference on "a" is added to the start of the array // The dependency reference on "a" is added to the start of the array
expect(rootTsconfig.references).toMatchInlineSnapshot(` expect(bTsconfigJson.references).toMatchInlineSnapshot(`
[ [
{ {
"path": "../a", "path": "../a",
@ -389,6 +396,8 @@ describe('syncGenerator()', () => {
}, },
] ]
`); `);
const cTsconfigJson = readJson(tree, 'packages/c/tsconfig.json');
expect(cTsconfigJson.references).toStrictEqual([]);
}); });
it('should not prune existing external project references that are not dependencies but are git ignored', async () => { it('should not prune existing external project references that are not dependencies but are git ignored', async () => {

View File

@ -176,8 +176,7 @@ export async function syncGenerator(tree: Tree): Promise<SyncGeneratorResult> {
for (const [projectName, data] of Object.entries(projectGraph.dependencies)) { for (const [projectName, data] of Object.entries(projectGraph.dependencies)) {
if ( if (
!projectGraph.nodes[projectName] || !projectGraph.nodes[projectName] ||
projectGraph.nodes[projectName].data.root === '.' || projectGraph.nodes[projectName].data.root === '.'
!data.length
) { ) {
continue; continue;
} }
@ -208,9 +207,6 @@ export async function syncGenerator(tree: Tree): Promise<SyncGeneratorResult> {
projectGraph, projectGraph,
collectedDependencies collectedDependencies
); );
if (!dependencies.length) {
continue;
}
for (const runtimeTsConfigFileName of runtimeTsConfigFileNames) { for (const runtimeTsConfigFileName of runtimeTsConfigFileNames) {
const runtimeTsConfigPath = joinPathFragments( const runtimeTsConfigPath = joinPathFragments(

View File

@ -443,6 +443,19 @@ describe(`Plugin: ${PLUGIN_NAME}`, () => {
`); `);
}); });
it('should handle ts project references pointing to non-existing files and not throw', async () => {
await applyFilesToTempFsAndContext(tempFs, context, {
'libs/my-lib/tsconfig.json': JSON.stringify({
references: [{ path: '../my-lib-2' }],
}),
'libs/my-lib/package.json': `{}`,
});
await expect(
invokeCreateNodesOnMatchingFiles(context, {})
).resolves.not.toThrow();
});
describe('inputs', () => { describe('inputs', () => {
it('should add the config file and the `include` and `exclude` patterns', async () => { it('should add the config file and the `include` and `exclude` patterns', async () => {
await applyFilesToTempFsAndContext(tempFs, context, { await applyFilesToTempFsAndContext(tempFs, context, {
@ -1821,6 +1834,23 @@ describe(`Plugin: ${PLUGIN_NAME}`, () => {
`); `);
}); });
it('should handle ts project references pointing to non-existing files and not throw', async () => {
await applyFilesToTempFsAndContext(tempFs, context, {
'libs/my-lib/tsconfig.json': JSON.stringify({
references: [{ path: '../my-lib-2' }],
}),
'libs/my-lib/tsconfig.lib.json': `{}`,
'libs/my-lib/package.json': `{}`,
});
await expect(
invokeCreateNodesOnMatchingFiles(context, {
typecheck: false,
build: true,
})
).resolves.not.toThrow();
});
describe('inputs', () => { describe('inputs', () => {
it('should add the config file and the `include` and `exclude` patterns', async () => { it('should add the config file and the `include` and `exclude` patterns', async () => {
await applyFilesToTempFsAndContext(tempFs, context, { await applyFilesToTempFsAndContext(tempFs, context, {

View File

@ -545,6 +545,11 @@ function resolveInternalProjectReferences(
continue; continue;
} }
if (!existsSync(refConfigPath)) {
// the referenced tsconfig doesn't exist, ignore it
continue;
}
if (isExternalProjectReference(refConfigPath, workspaceRoot, projectRoot)) { if (isExternalProjectReference(refConfigPath, workspaceRoot, projectRoot)) {
continue; continue;
} }
@ -585,6 +590,11 @@ function hasExternalProjectReferences(
continue; continue;
} }
if (!existsSync(refConfigPath)) {
// the referenced tsconfig doesn't exist, ignore it
continue;
}
if (isExternalProjectReference(refConfigPath, workspaceRoot, projectRoot)) { if (isExternalProjectReference(refConfigPath, workspaceRoot, projectRoot)) {
return true; return true;
} }