George Kalpakas 6ab43d7335 fix(ngcc): correctly detect external files from nested node_modules/ (#36559)
Previously, when we needed to detect whether a file is external to a
package, we only checked whether the relative path to the file from the
package's root started with `..`. This would detect external imports
when the packages were siblings (e.g. peer dependencies or hoisted to
the top of `node_modules/` by the package manager), but would fail to
detect imports from packages located in nested `node_modules/` as
external. For example, importing `node_modules/foo/node_modules/bar`
from a file in `node_modules/foo/` would be considered internal to the
`foo` package.

This could result in processing/analyzing more files than necessary.
More importantly it could lead to errors due to trying to analyze
non-Angular packages that were direct dependencies of Angular packages.

This commit fixes it by also verifying that the relative path to a file
does not start with `node_modules/`.

Jira issue: [FW-2068](https://angular-team.atlassian.net/browse/FW-2068)

Fixes #36526

PR Close #36559
2020-04-10 09:10:26 -07:00

48 lines
1.9 KiB
TypeScript

/**
* @license
* Copyright Google Inc. 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';
import {absoluteFrom} from '../../../src/ngtsc/file_system';
import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing';
import {isWithinPackage} from '../../src/analysis/util';
runInEachFileSystem(() => {
describe('isWithinPackage', () => {
let _: typeof absoluteFrom;
beforeEach(() => _ = absoluteFrom);
it('should return true if the source-file is contained in the package', () => {
const packagePath = _('/node_modules/test');
const file =
ts.createSourceFile(_('/node_modules/test/src/index.js'), '', ts.ScriptTarget.ES2015);
expect(isWithinPackage(packagePath, file)).toBe(true);
});
it('should return false if the source-file is not contained in the package', () => {
const packagePath = _('/node_modules/test');
const file =
ts.createSourceFile(_('/node_modules/other/src/index.js'), '', ts.ScriptTarget.ES2015);
expect(isWithinPackage(packagePath, file)).toBe(false);
});
it('should return false if the source-file is inside the package\'s `node_modules/`', () => {
const packagePath = _('/node_modules/test');
// An external file inside the package's `node_modules/`.
const file1 = ts.createSourceFile(
_('/node_modules/test/node_modules/other/src/index.js'), '', ts.ScriptTarget.ES2015);
expect(isWithinPackage(packagePath, file1)).toBe(false);
// An internal file starting with `node_modules`.
const file2 = ts.createSourceFile(
_('/node_modules/test/node_modules_optimizer.js'), '', ts.ScriptTarget.ES2015);
expect(isWithinPackage(packagePath, file2)).toBe(true);
});
});
});