refactor(language-service): language_service_adapter -> adapters (#39619)

This rename is done because we know have a file system adapter over a
project as well as the compiler adapter.

PR Close #39619
This commit is contained in:
ayazhafiz 2020-10-30 17:16:39 -05:00 committed by atscott
parent 64c3135be7
commit d39c4bbe37
6 changed files with 30 additions and 65 deletions

View File

@ -108,9 +108,10 @@ export function formatDiagnostics(
}
}
/** Used to read configuration files. */
// TODO(ayazhafiz): split FileSystem into a ReadonlyFileSystem and make this a
// subset of that.
export type ParseConfigurationHost =
export type ConfigurationHost =
Pick<FileSystem, 'readFile'|'exists'|'lstat'|'resolve'|'join'|'dirname'|'extname'|'pwd'>;
export interface ParsedConfiguration {
@ -119,11 +120,11 @@ export interface ParsedConfiguration {
rootNames: string[];
projectReferences?: readonly ts.ProjectReference[]|undefined;
emitFlags: api.EmitFlags;
errors: Diagnostics;
errors: ts.Diagnostic[];
}
export function calcProjectFileAndBasePath(
project: string, host: ParseConfigurationHost = getFileSystem()):
project: string, host: ConfigurationHost = getFileSystem()):
{projectFile: AbsoluteFsPath, basePath: AbsoluteFsPath} {
const absProject = host.resolve(project);
const projectIsDir = host.lstat(absProject).isDirectory();
@ -145,7 +146,7 @@ export function createNgCompilerOptions(
export function readConfiguration(
project: string, existingOptions?: ts.CompilerOptions,
host: ParseConfigurationHost = getFileSystem()): ParsedConfiguration {
host: ConfigurationHost = getFileSystem()): ParsedConfiguration {
try {
const {projectFile, basePath} = calcProjectFileAndBasePath(project, host);
@ -223,11 +224,14 @@ export function readConfiguration(
emitFlags
};
} catch (e) {
const errors: Diagnostics = [{
const errors: ts.Diagnostic[] = [{
category: ts.DiagnosticCategory.Error,
messageText: e.stack,
source: api.SOURCE,
code: api.UNKNOWN_ERROR_CODE
file: undefined,
start: undefined,
length: undefined,
source: 'angular',
code: api.UNKNOWN_ERROR_CODE,
}];
return {project: '', errors, rootNames: [], options: {}, emitFlags: api.EmitFlags.Default};
}

View File

@ -6,7 +6,9 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ParseConfigurationHost} from '@angular/compiler-cli';
/** @fileoverview provides adapters for communicating with the ng compiler */
import {ConfigurationHost} from '@angular/compiler-cli';
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 {isShim} from '@angular/compiler-cli/src/ngtsc/shims';
@ -88,14 +90,13 @@ export class LanguageServiceAdapter implements NgCompilerAdapter {
* because signatures of calls like `FileSystem#readFile` are a bit stricter
* than those on the adapter.
*/
export class LSParseConfigHost implements ParseConfigurationHost {
private readonly host: ts.server.ServerHost = this.project.projectService.host;
constructor(private readonly project: ts.server.Project) {}
export class LSParseConfigHost implements ConfigurationHost {
constructor(private readonly serverHost: ts.server.ServerHost) {}
exists(path: AbsoluteFsPath): boolean {
return this.project.fileExists(path) || this.project.directoryExists(path);
return this.serverHost.fileExists(path) || this.serverHost.directoryExists(path);
}
readFile(path: AbsoluteFsPath): string {
const content = this.project.readFile(path);
const content = this.serverHost.readFile(path);
if (content === undefined) {
throw new Error(`LanguageServiceFS#readFile called on unavailable file ${path}`);
}
@ -104,10 +105,10 @@ export class LSParseConfigHost implements ParseConfigurationHost {
lstat(path: AbsoluteFsPath): FileStats {
return {
isFile: () => {
return this.project.fileExists(path);
return this.serverHost.fileExists(path);
},
isDirectory: () => {
return this.project.directoryExists(path);
return this.serverHost.directoryExists(path);
},
isSymbolicLink: () => {
throw new Error(`LanguageServiceFS#lstat#isSymbolicLink not implemented`);
@ -115,13 +116,13 @@ export class LSParseConfigHost implements ParseConfigurationHost {
};
}
pwd(): AbsoluteFsPath {
return this.project.getCurrentDirectory() as AbsoluteFsPath;
return this.serverHost.getCurrentDirectory() as AbsoluteFsPath;
}
extname(path: AbsoluteFsPath|PathSegment): string {
return p.extname(path);
}
resolve(...paths: string[]): AbsoluteFsPath {
return this.host.resolvePath(this.join(paths[0], ...paths.slice(1))) as AbsoluteFsPath;
return this.serverHost.resolvePath(this.join(paths[0], ...paths.slice(1))) as AbsoluteFsPath;
}
dirname<T extends PathString>(file: T): T {
return p.dirname(file) as T;

View File

@ -12,7 +12,7 @@ import {TrackedIncrementalBuildStrategy} from '@angular/compiler-cli/src/ngtsc/i
import {TypeCheckingProgramStrategy} from '@angular/compiler-cli/src/ngtsc/typecheck/api';
import * as ts from 'typescript/lib/tsserverlibrary';
import {LanguageServiceAdapter} from './language_service_adapter';
import {LanguageServiceAdapter} from './adapters';
import {isExternalTemplate} from './utils';
/**

View File

@ -6,15 +6,15 @@
* found in the LICENSE file at https://angular.io/license
*/
import {CompilerOptions, formatDiagnostics, ParseConfigurationHost, readConfiguration} from '@angular/compiler-cli';
import {CompilerOptions, ConfigurationHost, readConfiguration} from '@angular/compiler-cli';
import {absoluteFromSourceFile, AbsoluteFsPath} from '@angular/compiler-cli/src/ngtsc/file_system';
import {TypeCheckShimGenerator} from '@angular/compiler-cli/src/ngtsc/typecheck';
import {OptimizeFor, TypeCheckingProgramStrategy} from '@angular/compiler-cli/src/ngtsc/typecheck/api';
import * as ts from 'typescript/lib/tsserverlibrary';
import {LanguageServiceAdapter, LSParseConfigHost} from './adapters';
import {CompilerFactory} from './compiler_factory';
import {DefinitionBuilder} from './definitions';
import {LanguageServiceAdapter, LSParseConfigHost} from './language_service_adapter';
import {QuickInfoBuilder} from './quick_info';
import {getTargetAtPosition} from './template_target';
import {getTemplateInfoAtPosition, isTypeScriptFile} from './utils';
@ -27,7 +27,7 @@ export class LanguageService {
private readonly parseConfigHost: LSParseConfigHost;
constructor(project: ts.server.Project, private readonly tsLS: ts.LanguageService) {
this.parseConfigHost = new LSParseConfigHost(project);
this.parseConfigHost = new LSParseConfigHost(project.projectService.host);
this.options = parseNgCompilerOptions(project, this.parseConfigHost);
this.strategy = createTypeCheckingProgramStrategy(project);
this.adapter = new LanguageServiceAdapter(project);
@ -116,15 +116,15 @@ export class LanguageService {
}
}
export function parseNgCompilerOptions(
project: ts.server.Project, host: ParseConfigurationHost): CompilerOptions {
function parseNgCompilerOptions(
project: ts.server.Project, host: ConfigurationHost): CompilerOptions {
if (!(project instanceof ts.server.ConfiguredProject)) {
return {};
}
const {options, errors} =
readConfiguration(project.getConfigFilePath(), /* existingOptions */ undefined, host);
if (errors.length > 0) {
project.error(formatDiagnostics(errors));
project.setProjectErrors(errors);
}
return options;

View File

@ -1,41 +0,0 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import * as ts from 'typescript/lib/tsserverlibrary';
import {LanguageServiceAdapter} from '../../language_service_adapter';
import {MockService, setup, TEST_TEMPLATE} from './mock_host';
describe('Language service adapter', () => {
let project: ts.server.Project;
let service: MockService;
beforeAll(() => {
const {project: _project, service: _service} = setup();
project = _project;
service = _service;
});
it('should mark template dirty if it has not seen the template before', () => {
const adapter = new LanguageServiceAdapter(project);
expect(adapter.isTemplateDirty(TEST_TEMPLATE)).toBeTrue();
});
it('should not mark template dirty if template has not changed', () => {
const adapter = new LanguageServiceAdapter(project);
adapter.readResource(TEST_TEMPLATE);
expect(adapter.isTemplateDirty(TEST_TEMPLATE)).toBeFalse();
});
it('should mark template dirty if template has changed', () => {
const adapter = new LanguageServiceAdapter(project);
service.overwrite(TEST_TEMPLATE, '<p>Hello World</p>');
expect(adapter.isTemplateDirty(TEST_TEMPLATE)).toBeTrue();
});
});

View File

@ -10,6 +10,7 @@ import {NgCompiler} from '@angular/compiler-cli/src/ngtsc/core';
import {isExternalResource} from '@angular/compiler-cli/src/ngtsc/metadata';
import {DeclarationNode} from '@angular/compiler-cli/src/ngtsc/reflection';
import {DirectiveSymbol} from '@angular/compiler-cli/src/ngtsc/typecheck/api';
import {Diagnostic as ngDiagnostic, isNgDiagnostic} from '@angular/compiler-cli/src/transformers/api';
import * as e from '@angular/compiler/src/expression_parser/ast'; // e for expression AST
import * as t from '@angular/compiler/src/render3/r3_ast'; // t for template AST
import * as ts from 'typescript';