fix(ngcc): do not add DTS deep imports to missing packages list (#34695)

When searching the typings program for a package for imports a
distinction is drawn between missing entry-points and deep imports.

Previously in the `DtsDependencyHost` these deep imports may be
marked as missing if there was no typings file at the deep import path.
Instead there may be a javascript file instead. In practice this means
the import is "deep" and not "missing".

Now the `DtsDependencyHost` will also consider `.js` files when checking
for deep-imports, and it will also look inside `@types/...` for a suitable
deep-imported typings file.

Fixes #34720

PR Close #34695
This commit is contained in:
Pete Bacon Darwin
2020-01-09 14:23:50 +00:00
committed by atscott
parent da51d884a1
commit 85b5c365fc
3 changed files with 298 additions and 20 deletions

View File

@ -5,7 +5,7 @@
* 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 {FileSystem} from '../../../src/ngtsc/file_system';
import {AbsoluteFsPath, FileSystem} from '../../../src/ngtsc/file_system';
import {PathMappings} from '../utils';
import {EsmDependencyHost} from './esm_dependency_host';
import {ModuleResolver} from './module_resolver';
@ -15,6 +15,18 @@ import {ModuleResolver} from './module_resolver';
*/
export class DtsDependencyHost extends EsmDependencyHost {
constructor(fs: FileSystem, pathMappings?: PathMappings) {
super(fs, new ModuleResolver(fs, pathMappings, ['', '.d.ts', '/index.d.ts']));
super(
fs, new ModuleResolver(fs, pathMappings, ['', '.d.ts', '/index.d.ts', '.js', '/index.js']));
}
/**
* Attempts to process the `importPath` directly and also inside `@types/...`.
*/
protected processImport(
importPath: string, file: AbsoluteFsPath, dependencies: Set<AbsoluteFsPath>,
missing: Set<string>, deepImports: Set<string>, alreadySeen: Set<AbsoluteFsPath>): boolean {
return super.processImport(importPath, file, dependencies, missing, deepImports, alreadySeen) ||
super.processImport(
`@types/${importPath}`, file, dependencies, missing, deepImports, alreadySeen);
}
}

View File

@ -44,29 +44,42 @@ export class EsmDependencyHost extends DependencyHostBase {
.filter(isStringImportOrReexport)
// Grab the id of the module that is being imported
.map(stmt => stmt.moduleSpecifier.text)
// Resolve this module id into an absolute path
.forEach(importPath => {
const resolvedModule = this.moduleResolver.resolveModuleImport(importPath, file);
if (resolvedModule) {
if (resolvedModule instanceof ResolvedRelativeModule) {
const internalDependency = resolvedModule.modulePath;
if (!alreadySeen.has(internalDependency)) {
alreadySeen.add(internalDependency);
this.recursivelyCollectDependencies(
internalDependency, dependencies, missing, deepImports, alreadySeen);
}
} else {
if (resolvedModule instanceof ResolvedDeepImport) {
deepImports.add(resolvedModule.importPath);
} else {
dependencies.add(resolvedModule.entryPointPath);
}
}
} else {
const resolved =
this.processImport(importPath, file, dependencies, missing, deepImports, alreadySeen);
if (!resolved) {
missing.add(importPath);
}
});
}
/**
* Resolve the given `importPath` from `file` and add it to the appropriate set.
*
* @returns `true` if the import was resolved (to an entry-point, a local import, or a
* deep-import).
*/
protected processImport(
importPath: string, file: AbsoluteFsPath, dependencies: Set<AbsoluteFsPath>,
missing: Set<string>, deepImports: Set<string>, alreadySeen: Set<AbsoluteFsPath>): boolean {
const resolvedModule = this.moduleResolver.resolveModuleImport(importPath, file);
if (resolvedModule === null) {
return false;
}
if (resolvedModule instanceof ResolvedRelativeModule) {
const internalDependency = resolvedModule.modulePath;
if (!alreadySeen.has(internalDependency)) {
alreadySeen.add(internalDependency);
this.recursivelyCollectDependencies(
internalDependency, dependencies, missing, deepImports, alreadySeen);
}
} else if (resolvedModule instanceof ResolvedDeepImport) {
deepImports.add(resolvedModule.importPath);
} else {
dependencies.add(resolvedModule.entryPointPath);
}
return true;
}
}
/**