feat(compiler-cli): support getting resource dependencies for a source file (#38048)

The compiler maintains an internal dependency graph of all resource
dependencies for application source files. This information can be useful
for tools that integrate the compiler and need to support file watching.
This change adds a `getResourceDependencies` method to the
`NgCompiler` class that allows compiler integrations to access resource
dependencies of files within the compilation.

PR Close #38048
This commit is contained in:
Charles Lyding 2020-07-14 12:10:53 -04:00 committed by Joey Perrott
parent 3bbbf39b58
commit 5dbf357224
3 changed files with 51 additions and 0 deletions

View File

@ -162,6 +162,17 @@ export class NgCompiler {
this.ignoreForEmit = this.adapter.ignoreForEmit; this.ignoreForEmit = this.adapter.ignoreForEmit;
} }
/**
* Get the resource dependencies of a file.
*
* If the file is not part of the compilation, an empty array will be returned.
*/
getResourceDependencies(file: ts.SourceFile): string[] {
this.ensureAnalyzed();
return this.incrementalDriver.depGraph.getResourceDependencies(file);
}
/** /**
* Get all Angular-related diagnostics for this compilation. * Get all Angular-related diagnostics for this compilation.
* *

View File

@ -105,6 +105,40 @@ runInEachFileSystem(() => {
expect(components).toEqual(new Set([CmpA, CmpC])); expect(components).toEqual(new Set([CmpA, CmpC]));
}); });
}); });
describe('getResourceDependencies', () => {
it('should return resource dependencies of a component source file', () => {
const COMPONENT = _('/cmp.ts');
fs.writeFile(COMPONENT, `
import {Component} from '@angular/core';
@Component({
selector: 'test-cmp',
templateUrl: './template.html',
styleUrls: ['./style.css'],
})
export class Cmp {}
`);
fs.writeFile(_('/template.html'), `<h1>Resource</h1>`);
fs.writeFile(_('/style.css'), `h1 { }`);
const options: NgCompilerOptions = {
strictTemplates: true,
};
const baseHost = new NgtscCompilerHost(getFileSystem(), options);
const host = NgCompilerHost.wrap(baseHost, [COMPONENT], options, /* oldProgram */ null);
const program = ts.createProgram({host, options, rootNames: host.inputFiles});
const compiler = new NgCompiler(
host, options, program, new ReusedProgramStrategy(program, host, options, []),
new NoopIncrementalBuildStrategy(), /** enableTemplateTypeChecker */ false);
const deps = compiler.getResourceDependencies(getSourceFileOrError(program, COMPONENT));
expect(deps.length).toBe(2);
expect(deps).toEqual(jasmine.arrayContaining([
jasmine.stringMatching(/\/template.html$/),
jasmine.stringMatching(/\/style.css$/),
]));
});
});
}); });
}); });

View File

@ -53,6 +53,12 @@ export class FileDependencyGraph<T extends {fileName: string} = ts.SourceFile> i
} }
} }
getResourceDependencies(from: T): AbsoluteFsPath[] {
const node = this.nodes.get(from);
return node ? [...node.usesResources] : [];
}
isStale(sf: T, changedTsPaths: Set<string>, changedResources: Set<AbsoluteFsPath>): boolean { isStale(sf: T, changedTsPaths: Set<string>, changedResources: Set<AbsoluteFsPath>): boolean {
return isLogicallyChanged(sf, this.nodeFor(sf), changedTsPaths, EMPTY_SET, changedResources); return isLogicallyChanged(sf, this.nodeFor(sf), changedTsPaths, EMPTY_SET, changedResources);
} }