fix(language-service): include compilerOptions.rootDir in rootDirs (#40243)

When resolving references, the Ivy compiler has a few strategies it could use.

For relative path, one of strategies is [`RelativePathStrategy`](
https://github.com/angular/angular/blob/master/packages/compiler-cli/src/
ngtsc/imports/README.md#relativepathstrategy). This strategy
relies on `compilerOptions.rootDir` and `compilerOptions.rootDirs` to perform
the resolution, but language service only passes `rootDirs` to the compiler,
and not `rootDir`.

In reality, `rootDir` is very different from `rootDirs` even though they
sound the same.
According to the official [TS documentation][1],
> `rootDir` specifies the root directory of input files. Only use to control
> the output directory structure with --outDir.

> `rootDirs` is a list of root folders whose combined content represent the
> structure of the project at runtime. See [Module Resolution documentation](
> https://www.typescriptlang.org/docs/handbook/
> module-resolution.html#virtual-directories-with-rootdirs)
> for more details.

For now, we keep the behavior between compiler and language service consistent,
but we will revisit the notion of `rootDir` and how it is used later.

Fix angular/vscode-ng-language-service#1039

[1]: https://www.typescriptlang.org/docs/handbook/compiler-options.html

PR Close #40243
This commit is contained in:
Keen Yee Liau 2020-12-22 15:07:45 -08:00 committed by Joey Perrott
parent 335d6c8c00
commit a62416c6e4
3 changed files with 7 additions and 3 deletions

View File

@ -92,7 +92,9 @@ export function isExported(node: DeclarationNode): boolean {
topLevel.modifiers.some(modifier => modifier.kind === ts.SyntaxKind.ExportKeyword); topLevel.modifiers.some(modifier => modifier.kind === ts.SyntaxKind.ExportKeyword);
} }
export function getRootDirs(host: ts.CompilerHost, options: ts.CompilerOptions): AbsoluteFsPath[] { export function getRootDirs(
host: Pick<ts.CompilerHost, 'getCurrentDirectory'|'getCanonicalFileName'>,
options: ts.CompilerOptions): AbsoluteFsPath[] {
const rootDirs: string[] = []; const rootDirs: string[] = [];
if (options.rootDirs !== undefined) { if (options.rootDirs !== undefined) {
rootDirs.push(...options.rootDirs); rootDirs.push(...options.rootDirs);

View File

@ -18,6 +18,7 @@ ts_library(
"//packages/compiler-cli/src/ngtsc/shims", "//packages/compiler-cli/src/ngtsc/shims",
"//packages/compiler-cli/src/ngtsc/typecheck", "//packages/compiler-cli/src/ngtsc/typecheck",
"//packages/compiler-cli/src/ngtsc/typecheck/api", "//packages/compiler-cli/src/ngtsc/typecheck/api",
"//packages/compiler-cli/src/ngtsc/util",
"@npm//@types/node", "@npm//@types/node",
"@npm//typescript", "@npm//typescript",
], ],

View File

@ -10,8 +10,9 @@
import {ConfigurationHost} from '@angular/compiler-cli'; import {ConfigurationHost} from '@angular/compiler-cli';
import {NgCompilerAdapter} from '@angular/compiler-cli/src/ngtsc/core/api'; import {NgCompilerAdapter} from '@angular/compiler-cli/src/ngtsc/core/api';
import {absoluteFrom, AbsoluteFsPath, FileStats, PathSegment, PathString} from '@angular/compiler-cli/src/ngtsc/file_system'; import {AbsoluteFsPath, FileStats, PathSegment, PathString} from '@angular/compiler-cli/src/ngtsc/file_system';
import {isShim} from '@angular/compiler-cli/src/ngtsc/shims'; import {isShim} from '@angular/compiler-cli/src/ngtsc/shims';
import {getRootDirs} from '@angular/compiler-cli/src/ngtsc/util/src/typescript';
import * as p from 'path'; import * as p from 'path';
import * as ts from 'typescript/lib/tsserverlibrary'; import * as ts from 'typescript/lib/tsserverlibrary';
@ -27,7 +28,7 @@ export class LanguageServiceAdapter implements NgCompilerAdapter {
private readonly templateVersion = new Map<string, string>(); private readonly templateVersion = new Map<string, string>();
constructor(private readonly project: ts.server.Project) { constructor(private readonly project: ts.server.Project) {
this.rootDirs = project.getCompilationSettings().rootDirs?.map(absoluteFrom) || []; this.rootDirs = getRootDirs(this, project.getCompilationSettings());
} }
isShim(sf: ts.SourceFile): boolean { isShim(sf: ts.SourceFile): boolean {