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 // TODO(ayazhafiz): split FileSystem into a ReadonlyFileSystem and make this a
// subset of that. // subset of that.
export type ParseConfigurationHost = export type ConfigurationHost =
Pick<FileSystem, 'readFile'|'exists'|'lstat'|'resolve'|'join'|'dirname'|'extname'|'pwd'>; Pick<FileSystem, 'readFile'|'exists'|'lstat'|'resolve'|'join'|'dirname'|'extname'|'pwd'>;
export interface ParsedConfiguration { export interface ParsedConfiguration {
@ -119,11 +120,11 @@ export interface ParsedConfiguration {
rootNames: string[]; rootNames: string[];
projectReferences?: readonly ts.ProjectReference[]|undefined; projectReferences?: readonly ts.ProjectReference[]|undefined;
emitFlags: api.EmitFlags; emitFlags: api.EmitFlags;
errors: Diagnostics; errors: ts.Diagnostic[];
} }
export function calcProjectFileAndBasePath( export function calcProjectFileAndBasePath(
project: string, host: ParseConfigurationHost = getFileSystem()): project: string, host: ConfigurationHost = getFileSystem()):
{projectFile: AbsoluteFsPath, basePath: AbsoluteFsPath} { {projectFile: AbsoluteFsPath, basePath: AbsoluteFsPath} {
const absProject = host.resolve(project); const absProject = host.resolve(project);
const projectIsDir = host.lstat(absProject).isDirectory(); const projectIsDir = host.lstat(absProject).isDirectory();
@ -145,7 +146,7 @@ export function createNgCompilerOptions(
export function readConfiguration( export function readConfiguration(
project: string, existingOptions?: ts.CompilerOptions, project: string, existingOptions?: ts.CompilerOptions,
host: ParseConfigurationHost = getFileSystem()): ParsedConfiguration { host: ConfigurationHost = getFileSystem()): ParsedConfiguration {
try { try {
const {projectFile, basePath} = calcProjectFileAndBasePath(project, host); const {projectFile, basePath} = calcProjectFileAndBasePath(project, host);
@ -223,11 +224,14 @@ export function readConfiguration(
emitFlags emitFlags
}; };
} catch (e) { } catch (e) {
const errors: Diagnostics = [{ const errors: ts.Diagnostic[] = [{
category: ts.DiagnosticCategory.Error, category: ts.DiagnosticCategory.Error,
messageText: e.stack, messageText: e.stack,
source: api.SOURCE, file: undefined,
code: api.UNKNOWN_ERROR_CODE start: undefined,
length: undefined,
source: 'angular',
code: api.UNKNOWN_ERROR_CODE,
}]; }];
return {project: '', errors, rootNames: [], options: {}, emitFlags: api.EmitFlags.Default}; 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 * 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 {NgCompilerAdapter} from '@angular/compiler-cli/src/ngtsc/core/api';
import {absoluteFrom, AbsoluteFsPath, FileStats, PathSegment, PathString} from '@angular/compiler-cli/src/ngtsc/file_system'; import {absoluteFrom, 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';
@ -88,14 +90,13 @@ export class LanguageServiceAdapter implements NgCompilerAdapter {
* because signatures of calls like `FileSystem#readFile` are a bit stricter * because signatures of calls like `FileSystem#readFile` are a bit stricter
* than those on the adapter. * than those on the adapter.
*/ */
export class LSParseConfigHost implements ParseConfigurationHost { export class LSParseConfigHost implements ConfigurationHost {
private readonly host: ts.server.ServerHost = this.project.projectService.host; constructor(private readonly serverHost: ts.server.ServerHost) {}
constructor(private readonly project: ts.server.Project) {}
exists(path: AbsoluteFsPath): boolean { 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 { readFile(path: AbsoluteFsPath): string {
const content = this.project.readFile(path); const content = this.serverHost.readFile(path);
if (content === undefined) { if (content === undefined) {
throw new Error(`LanguageServiceFS#readFile called on unavailable file ${path}`); throw new Error(`LanguageServiceFS#readFile called on unavailable file ${path}`);
} }
@ -104,10 +105,10 @@ export class LSParseConfigHost implements ParseConfigurationHost {
lstat(path: AbsoluteFsPath): FileStats { lstat(path: AbsoluteFsPath): FileStats {
return { return {
isFile: () => { isFile: () => {
return this.project.fileExists(path); return this.serverHost.fileExists(path);
}, },
isDirectory: () => { isDirectory: () => {
return this.project.directoryExists(path); return this.serverHost.directoryExists(path);
}, },
isSymbolicLink: () => { isSymbolicLink: () => {
throw new Error(`LanguageServiceFS#lstat#isSymbolicLink not implemented`); throw new Error(`LanguageServiceFS#lstat#isSymbolicLink not implemented`);
@ -115,13 +116,13 @@ export class LSParseConfigHost implements ParseConfigurationHost {
}; };
} }
pwd(): AbsoluteFsPath { pwd(): AbsoluteFsPath {
return this.project.getCurrentDirectory() as AbsoluteFsPath; return this.serverHost.getCurrentDirectory() as AbsoluteFsPath;
} }
extname(path: AbsoluteFsPath|PathSegment): string { extname(path: AbsoluteFsPath|PathSegment): string {
return p.extname(path); return p.extname(path);
} }
resolve(...paths: string[]): AbsoluteFsPath { 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 { dirname<T extends PathString>(file: T): T {
return p.dirname(file) as 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 {TypeCheckingProgramStrategy} from '@angular/compiler-cli/src/ngtsc/typecheck/api';
import * as ts from 'typescript/lib/tsserverlibrary'; import * as ts from 'typescript/lib/tsserverlibrary';
import {LanguageServiceAdapter} from './language_service_adapter'; import {LanguageServiceAdapter} from './adapters';
import {isExternalTemplate} from './utils'; import {isExternalTemplate} from './utils';
/** /**

View File

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