refactor(ivy): ngcc - implement abstract FileSystem (#29643)

This commit introduces a new interface, which abstracts access
to the underlying `FileSystem`. There is initially one concrete
implementation, `NodeJsFileSystem`, which is simply wrapping the
`fs` library of NodeJs.

Going forward, we can provide a `MockFileSystem` for test, which
should allow us to stop using `mock-fs` for most of the unit tests.
We could also implement a `CachedFileSystem` that may improve the
performance of ngcc.

PR Close #29643
This commit is contained in:
Pete Bacon Darwin
2019-04-28 20:47:57 +01:00
committed by Andrew Kushnir
parent 1fd2cc6340
commit 16d7dde2ad
36 changed files with 590 additions and 353 deletions

View File

@ -6,9 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ConstantPool} from '@angular/compiler';
import {NOOP_PERF_RECORDER} from '@angular/compiler-cli/src/ngtsc/perf';
import * as path from 'canonical-path';
import * as fs from 'fs';
import * as path from 'path';
import * as ts from 'typescript';
import {BaseDefDecoratorHandler, ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, PipeDecoratorHandler, ReferencesRegistry, ResourceLoader} from '../../../src/ngtsc/annotations';
@ -19,6 +17,7 @@ import {PartialEvaluator} from '../../../src/ngtsc/partial_evaluator';
import {AbsoluteFsPath, LogicalFileSystem} from '../../../src/ngtsc/path';
import {LocalModuleScopeRegistry, MetadataDtsModuleScopeResolver} from '../../../src/ngtsc/scope';
import {CompileResult, DecoratorHandler, DetectResult, HandlerPrecedence} from '../../../src/ngtsc/transform';
import {FileSystem} from '../file_system/file_system';
import {DecoratedClass} from '../host/decorated_class';
import {NgccReflectionHost} from '../host/ngcc_host';
import {isDefined} from '../utils';
@ -53,9 +52,10 @@ export interface MatchingHandler<A, M> {
* Simple class that resolves and loads files directly from the filesystem.
*/
class NgccResourceLoader implements ResourceLoader {
constructor(private fs: FileSystem) {}
canPreload = false;
preload(): undefined|Promise<void> { throw new Error('Not implemented.'); }
load(url: string): string { return fs.readFileSync(url, 'utf8'); }
load(url: string): string { return this.fs.readFile(AbsoluteFsPath.resolve(url)); }
resolve(url: string, containingFile: string): string {
return path.resolve(path.dirname(containingFile), url);
}
@ -65,7 +65,7 @@ class NgccResourceLoader implements ResourceLoader {
* This Analyzer will analyze the files that have decorated classes that need to be transformed.
*/
export class DecorationAnalyzer {
resourceManager = new NgccResourceLoader();
resourceManager = new NgccResourceLoader(this.fs);
metaRegistry = new LocalMetadataRegistry();
dtsMetaReader = new DtsMetadataReader(this.typeChecker, this.reflectionHost);
fullMetaReader = new CompoundMetadataReader([this.metaRegistry, this.dtsMetaReader]);
@ -73,8 +73,8 @@ export class DecorationAnalyzer {
new LocalIdentifierStrategy(),
new AbsoluteModuleStrategy(this.program, this.typeChecker, this.options, this.host),
// TODO(alxhub): there's no reason why ngcc needs the "logical file system" logic here, as ngcc
// projects only ever have one rootDir. Instead, ngcc should just switch its emitted imort based
// on whether a bestGuessOwningModule is present in the Reference.
// projects only ever have one rootDir. Instead, ngcc should just switch its emitted import
// based on whether a bestGuessOwningModule is present in the Reference.
new LogicalProjectStrategy(this.typeChecker, new LogicalFileSystem(this.rootDirs)),
]);
dtsModuleScopeResolver =
@ -110,7 +110,7 @@ export class DecorationAnalyzer {
];
constructor(
private program: ts.Program, private options: ts.CompilerOptions,
private fs: FileSystem, private program: ts.Program, private options: ts.CompilerOptions,
private host: ts.CompilerHost, private typeChecker: ts.TypeChecker,
private reflectionHost: NgccReflectionHost, private referencesRegistry: ReferencesRegistry,
private rootDirs: AbsoluteFsPath[], private isCore: boolean) {}

View File

@ -7,6 +7,7 @@
*/
import * as ts from 'typescript';
import {AbsoluteFsPath} from '../../../src/ngtsc/path';
import {Declaration} from '../../../src/ngtsc/reflection';
import {NgccReflectionHost} from '../host/ngcc_host';
import {hasNameIdentifier, isDefined} from '../utils';
@ -14,8 +15,8 @@ import {NgccReferencesRegistry} from './ngcc_references_registry';
export interface ExportInfo {
identifier: string;
from: string;
dtsFrom?: string|null;
from: AbsoluteFsPath;
dtsFrom?: AbsoluteFsPath|null;
alias?: string|null;
}
export type PrivateDeclarationsAnalyses = ExportInfo[];
@ -93,11 +94,12 @@ export class PrivateDeclarationsAnalyzer {
});
return Array.from(privateDeclarations.keys()).map(id => {
const from = id.getSourceFile().fileName;
const from = AbsoluteFsPath.fromSourceFile(id.getSourceFile());
const declaration = privateDeclarations.get(id) !;
const alias = exportAliasDeclarations.get(id) || null;
const dtsDeclaration = this.host.getDtsDeclaration(declaration.node);
const dtsFrom = dtsDeclaration && dtsDeclaration.getSourceFile().fileName;
const dtsFrom =
dtsDeclaration && AbsoluteFsPath.fromSourceFile(dtsDeclaration.getSourceFile());
return {identifier: id.text, from, dtsFrom, alias};
});