Skip to content

fix(language-service): Support to resolve the re-export component. #62585

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

ivanwonder
Copy link
Contributor

@ivanwonder ivanwonder commented Jul 11, 2025

In the context of TypeScript (TS), a re-exported symbol is considered a distinct symbol.
This means that a developer can choose to import either the re-exported symbol or
the original symbol. However, in the context of Angular, the re-exported symbol
is treated as the same component because it uses the same selector.

This pull request will utilize the most recent re-export component file to
resolve the module specifier.

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • angular.dev application / infrastructure changes
  • Other... Please describe:

What is the current behavior?

Issue Number: N/A

What is the new behavior?

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

@angular-robot angular-robot bot added the area: language-service Issues related to Angular's VS Code language service label Jul 11, 2025
@ngbot ngbot bot added this to the Backlog milestone Jul 11, 2025
@ivanwonder ivanwonder force-pushed the support-re-export-component branch 2 times, most recently from 5ba6e32 to 68a6b85 Compare July 11, 2025 11:48
@ivanwonder ivanwonder marked this pull request as ready for review July 11, 2025 11:50
@pullapprove pullapprove bot requested a review from crisbeto July 11, 2025 11:50
@ivanwonder
Copy link
Contributor Author

@atscott Take a look when you have time.

@ivanwonder ivanwonder force-pushed the support-re-export-component branch from 68a6b85 to e771902 Compare July 15, 2025 13:52
@crisbeto crisbeto requested review from atscott and removed request for crisbeto July 15, 2025 14:54
@atscott
Copy link
Contributor

atscott commented Jul 15, 2025

/gemini review

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the language service to correctly handle re-exported components by resolving the most recent re-export. The changes involve modifying how module specifiers are resolved to include the export name, and using the TypeScript type checker to identify aliased symbols. The implementation looks solid and includes a good test case. I've found a few areas for improvement, mainly around documentation clarity and code duplication, including one high-severity issue with an incorrect example in a comment.

Comment on lines 963 to 981
const sf = program.getSourceFile(tsEntry.tsCompletionEntrySymbolFileName);
if (sf === undefined) {
return false;
}
const sfSymbol = typeChecker.getSymbolAtLocation(sf);
if (sfSymbol === undefined) {
return false;
}
const tsEntrySymbol = typeChecker.tryGetMemberInModuleExports(
tsEntry.tsCompletionEntrySymbolName,
sfSymbol,
);
if (tsEntrySymbol === undefined) {
return false;
}
const tsEntryType = typeChecker.getTypeOfSymbol(tsEntrySymbol);
return tsEntryType.symbol?.declarations?.[0] === toImport.node;
});
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This block of code for resolving a symbol from TsCompletionEntryInfo is very similar to the new getSymbolFromTsEntryInfo function in packages/compiler-cli/src/ngtsc/typecheck/src/checker.ts. To improve maintainability and avoid code duplication, consider refactoring this logic into a shared utility function that can be used in both places. If getSymbolFromTsEntryInfo can be exported from checker.ts (or a shared file) and used here, that would be ideal.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exporting the getSymbolFromTsEntryInfo function from checker.ts is not the correct approach. Allowing code duplication is acceptable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll refactor this if there is a better approach.

In the context of TypeScript (TS), a re-exported symbol is considered a distinct symbol.
This means that a developer can choose to import either the re-exported symbol or
the original symbol. However, in the context of Angular, the re-exported symbol
is treated as the same component because it uses the same selector.

This pull request will utilize the most recent re-export component file to
resolve the module specifier.
@ivanwonder ivanwonder force-pushed the support-re-export-component branch from e771902 to 2fc2f52 Compare July 16, 2025 02:35
@ivanwonder ivanwonder requested a review from atscott July 16, 2025 02:41
Copy link
Contributor

@atscott atscott left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally LGTM. Unless I'm misunderstanding, I think there might be some risk of always preferring the alias. When working within a package directory, the original definition might be preferable to the alias? That said, if we're only ever allowing one completion item, then we have to make a choice and likely the alias is the one we want most of the time?

@ivanwonder
Copy link
Contributor Author

Generally LGTM. Unless I'm misunderstanding, I think there might be some risk of always preferring the alias. When working within a package directory, the original definition might be preferable to the alias? That said, if we're only ever allowing one completion item, then we have to make a choice and likely the alias is the one we want most of the time?

Yes, personally, I think the alias is the best one. Now the ts tends to choose the shortest path.

image

a/a1.ts and a2.ts export the symbol ivanTest, the ts chooses a2.ts. For the ivanTest1 and ivanTest in this PR, I choose the ivanTest1 in the file a3.

image

If a package re-exports a component, it means importing that component from the package is allowed by the package. The package can provide better options by adjusting the exported symbols(for example: don't re-export it).

Maybe in the future, Angular LS will support display choice for the same component. This can be removed. It's better to have a rule here to allow the developer to adjust the code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: language-service Issues related to Angular's VS Code language service
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants