Skip to content

Commit 8e53a2b

Browse files
committed
fix(ngcc): do not collect private declarations from external packages
Previously, while trying to build an `NgccReflectionHost`'s `privateDtsDeclarationMap`, `computePrivateDtsDeclarationMap()` would try to collect exported declarations from all source files of the program (i.e. without checking whether they were within the target package, as happens for declarations in `.d.ts` files). Most of the time, that would not be a problem, because external packages would be represented as `.d.ts` files in the program. But when an external package had no typings, the JS files would be used instead. As a result, the `ReflectionHost` would try to (unnecessarilly) parse the file in order to extract exported declarations, which in turn would be harmless in most cases. There are certain cases, though, where the `ReflectionHost` would throw an error, because it cannot parse the external package's JS file. This could happen, for example, in `UmdReflectionHost`, which expects the file to contain exactly one statement. See angular#34544 for more details on a real-world failure. This commit fixes the issue by ensuring that `computePrivateDtsDeclarationMap()` will only collect exported declarations from files within the target package. Jira issue: [FW-1794](https://angular-team.atlassian.net/browse/FW-1794) Fixes angular#34544
1 parent 2fe8897 commit 8e53a2b

File tree

10 files changed

+74
-16
lines changed

10 files changed

+74
-16
lines changed

integration/ngcc/debug-test.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ node $(pwd)/../../scripts/build-packages-dist.js
1515

1616
# Workaround https://github.com/yarnpkg/yarn/issues/2165
1717
# Yarn will cache file://dist URIs and not update Angular code
18-
readonly cache=../.yarn_local_cache
18+
export readonly cache=../.yarn_local_cache
1919
function rm_cache {
2020
rm -rf $cache
2121
}

integration/ngcc/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"@angular/material": "9.0.0-rc.4",
1414
"@angular/platform-browser": "file:../../dist/packages-dist/platform-browser",
1515
"@angular/platform-browser-dynamic": "file:../../dist/packages-dist/platform-browser-dynamic",
16+
"@angular/platform-server": "file:../../dist/packages-dist/platform-server",
1617
"@angular/router": "file:../../dist/packages-dist/router",
1718
"@types/node": "file:../../node_modules/@types/node",
1819
"rxjs": "file:../../node_modules/rxjs",

integration/ngcc/test.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,17 @@ assertSucceeded "Expected 'ngcc' to log 'Compiling'."
140140
assertSucceeded "Expected 'ngcc' to not add trailing commas to factory function parameters in UMD."
141141

142142

143+
# Can it compile `@angular/platform-server` in UMD + typings without errors?
144+
# (The CLI prefers the `main` property (which maps to UMD) over `module` when compiling `@angular/platform-server`.
145+
# See https://github.com/angular/angular-cli/blob/e36853338/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/server.ts#L34)
146+
rm -rf node_modules/@angular/platform-server && \
147+
yarn install --cache-folder $cache --check-files && \
148+
test -d node_modules/@angular/platform-server
149+
assertSucceeded "Expected to re-install '@angular/platform-server'."
150+
151+
ngcc --properties main --target @angular/platform-server
152+
assertSucceeded "Expected 'ngcc' to successfully compile '@angular/platform-server' (main)."
153+
143154
# Can it be safely run again (as a noop)?
144155
# And check that it logged skipping compilation as expected
145156
ngcc -l debug | grep 'Skipping'

integration/ngcc/yarn.lock

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@
4949
"@angular/platform-browser@file:../../dist/packages-dist/platform-browser":
5050
version "9.0.0-rc.1"
5151

52+
"@angular/platform-server@file:../../dist/packages-dist/platform-server":
53+
version "9.0.0-rc.1"
54+
dependencies:
55+
domino "^2.1.2"
56+
xhr2 "^0.1.4"
57+
5258
"@angular/router@file:../../dist/packages-dist/router":
5359
version "9.0.0-rc.1"
5460

@@ -853,6 +859,11 @@ dev-ip@^1.0.1:
853859
resolved "https://registry.yarnpkg.com/dev-ip/-/dev-ip-1.0.1.tgz#a76a3ed1855be7a012bb8ac16cb80f3c00dc28f0"
854860
integrity sha1-p2o+0YVb56ASu4rBbLgPPADcKPA=
855861

862+
domino@^2.1.2:
863+
version "2.1.4"
864+
resolved "https://registry.yarnpkg.com/domino/-/domino-2.1.4.tgz#78922e7fab7c610f35792b6c745b7962d342e9c4"
865+
integrity sha512-l70mlQ7IjPKC8kT7GljQXJZmt5OqFL+RE91ik5y5WWQtsd9wP8R7gpFnNu96fK5MqAAZRXfLLsnzKtkty5fWGQ==
866+
856867
easy-extender@^2.3.4:
857868
version "2.3.4"
858869
resolved "https://registry.yarnpkg.com/easy-extender/-/easy-extender-2.3.4.tgz#298789b64f9aaba62169c77a2b3b64b4c9589b8f"
@@ -3479,6 +3490,11 @@ ws@~3.3.1:
34793490
safe-buffer "~5.1.0"
34803491
ultron "~1.1.0"
34813492

3493+
xhr2@^0.1.4:
3494+
version "0.1.4"
3495+
resolved "https://registry.yarnpkg.com/xhr2/-/xhr2-0.1.4.tgz#7f87658847716db5026323812f818cadab387a5f"
3496+
integrity sha1-f4dliEdxbbUCYyOBL4GMras4el8=
3497+
34823498
xml2js@^0.4.17:
34833499
version "0.4.19"
34843500
resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7"

integration/run_tests.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ fi
3838

3939
# Workaround https://github.com/yarnpkg/yarn/issues/2165
4040
# Yarn will cache file://dist URIs and not update Angular code
41-
readonly cache=.yarn_local_cache
41+
export readonly cache=.yarn_local_cache
4242
function rm_cache {
4343
rm -rf $cache
4444
}

packages/compiler-cli/ngcc/src/host/esm2015_host.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export const CONSTRUCTOR_PARAMS = 'ctorParameters' as ts.__String;
5050
*/
5151
export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements NgccReflectionHost {
5252
/**
53-
* A mapping from source declarations typings declarations, which are both publicly exported.
53+
* A mapping from source declarations to typings declarations, which are both publicly exported.
5454
*
5555
* There should be one entry for every public export visible from the root file of the source
5656
* tree. Note that by definition the key and value declarations will not be in the same TS
@@ -1562,14 +1562,14 @@ export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements N
15621562
Map<ts.Declaration, ts.Declaration> {
15631563
const declarationMap = new Map<ts.Declaration, ts.Declaration>();
15641564
const dtsDeclarationMap = new Map<string, ts.Declaration>();
1565-
const dtsFiles = getNonRootFiles(dts);
15661565
const typeChecker = dts.program.getTypeChecker();
1566+
1567+
const dtsFiles = getNonRootPackageFiles(dts);
15671568
for (const dtsFile of dtsFiles) {
1568-
if (isWithinPackage(dts.package, dtsFile)) {
1569-
this.collectDtsExportedDeclarations(dtsDeclarationMap, dtsFile, typeChecker);
1570-
}
1569+
this.collectDtsExportedDeclarations(dtsDeclarationMap, dtsFile, typeChecker);
15711570
}
1572-
const srcFiles = getNonRootFiles(src);
1571+
1572+
const srcFiles = getNonRootPackageFiles(src);
15731573
for (const srcFile of srcFiles) {
15741574
this.collectSrcExportedDeclarations(declarationMap, dtsDeclarationMap, srcFile);
15751575
}
@@ -2035,7 +2035,8 @@ function getRootFileOrFail(bundle: BundleProgram): ts.SourceFile {
20352035
return rootFile;
20362036
}
20372037

2038-
function getNonRootFiles(bundle: BundleProgram): ts.SourceFile[] {
2038+
function getNonRootPackageFiles(bundle: BundleProgram): ts.SourceFile[] {
20392039
const rootFile = bundle.program.getSourceFile(bundle.path);
2040-
return bundle.program.getSourceFiles().filter(f => f !== rootFile);
2040+
return bundle.program.getSourceFiles().filter(
2041+
f => (f !== rootFile) && isWithinPackage(bundle.package, f));
20412042
}

packages/compiler-cli/ngcc/test/host/commonjs_host_spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2184,7 +2184,7 @@ exports.ExternalModule = ExternalModule;
21842184
});
21852185
});
21862186

2187-
describe('getDtsDeclarationsOfClass()', () => {
2187+
describe('getDtsDeclaration()', () => {
21882188
it('should find the dts declaration that has the same relative path to the source file',
21892189
() => {
21902190
loadTestFiles(TYPINGS_SRC_FILES);

packages/compiler-cli/ngcc/test/host/esm2015_host_spec.ts

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,7 @@ runInEachFileSystem(() => {
547547
name: _('/ep/src/index.js'),
548548
contents: `
549549
import 'an_external_lib';
550+
import 'an_external_lib_without_typings';
550551
import {InternalClass} from './internal';
551552
import * as func1 from './func1';
552553
import * as missing from './missing-class';
@@ -579,6 +580,10 @@ runInEachFileSystem(() => {
579580
name: _('/ep/src/shadow-class.js'),
580581
contents: 'export class ShadowClass {}',
581582
},
583+
{
584+
name: _('/an_external_lib_without_typings/index.js'),
585+
contents: '// Some content.',
586+
},
582587
];
583588

584589
TYPINGS_DTS_FILES = [
@@ -1958,7 +1963,7 @@ runInEachFileSystem(() => {
19581963
});
19591964
});
19601965

1961-
describe('getDtsDeclarationsOfClass()', () => {
1966+
describe('getDtsDeclaration()', () => {
19621967
it('should find the dts declaration that has the same relative path to the source file',
19631968
() => {
19641969
loadTestFiles(TYPINGS_SRC_FILES);
@@ -2019,15 +2024,39 @@ runInEachFileSystem(() => {
20192024
getRootFiles(TYPINGS_SRC_FILES)[0], false, [_('/ep/src/shadow-class.js')]);
20202025
const dts = makeTestBundleProgram(
20212026
getRootFiles(TYPINGS_DTS_FILES)[0], false, [_('/ep/typings/shadow-class.d.ts')]);
2022-
const missingClass = getDeclaration(
2027+
const shadowClass = getDeclaration(
20232028
bundle.program, _('/ep/src/shadow-class.js'), 'ShadowClass', isNamedClassDeclaration);
20242029
const host = new Esm2015ReflectionHost(new MockLogger(), false, bundle, dts);
20252030

2026-
const dtsDecl = host.getDtsDeclaration(missingClass) !;
2031+
const dtsDecl = host.getDtsDeclaration(shadowClass) !;
20272032
expect(dtsDecl).not.toBeNull();
20282033
expect(dtsDecl.getSourceFile().fileName).toEqual(_('/ep/typings/shadow-class.d.ts'));
20292034
});
20302035

2036+
it('should ignore source files outside of the entrypoint', () => {
2037+
class TestEsm2015ReflectionHost extends Esm2015ReflectionHost {
2038+
getExportsOfModule(node: ts.Node) {
2039+
if (ts.isSourceFile(node) && (node.fileName === externalLibWithoutTypingsIndex)) {
2040+
throw new Error('Test error');
2041+
}
2042+
return super.getExportsOfModule(node);
2043+
}
2044+
}
2045+
2046+
loadTestFiles(TYPINGS_SRC_FILES);
2047+
loadTestFiles(TYPINGS_DTS_FILES);
2048+
const externalLibWithoutTypingsIndex = _('/an_external_lib_without_typings/index.js');
2049+
const bundle = makeTestBundleProgram(
2050+
getRootFiles(TYPINGS_SRC_FILES)[0], false, [externalLibWithoutTypingsIndex]);
2051+
const dts = makeTestBundleProgram(getRootFiles(TYPINGS_DTS_FILES)[0]);
2052+
const missingClass = getDeclaration(
2053+
bundle.program, _('/ep/src/missing-class.js'), 'MissingClass2',
2054+
isNamedClassDeclaration);
2055+
const host = new TestEsm2015ReflectionHost(new MockLogger(), false, bundle, dts);
2056+
2057+
expect(host.getDtsDeclaration(missingClass)).toBeNull();
2058+
});
2059+
20312060
it('should find the dts file that contains a matching class declaration, even if the source files do not match',
20322061
() => {
20332062
loadTestFiles(TYPINGS_SRC_FILES);

packages/compiler-cli/ngcc/test/host/esm5_host_spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2370,7 +2370,7 @@ runInEachFileSystem(() => {
23702370
});
23712371
});
23722372

2373-
describe('getDtsDeclarationsOfClass()', () => {
2373+
describe('getDtsDeclaration()', () => {
23742374
it('should find the dts declaration that has the same relative path to the source file',
23752375
() => {
23762376
loadTestFiles(TYPINGS_SRC_FILES);

packages/compiler-cli/ngcc/test/host/umd_host_spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2360,7 +2360,7 @@ runInEachFileSystem(() => {
23602360
});
23612361
});
23622362

2363-
describe('getDtsDeclarationsOfClass()', () => {
2363+
describe('getDtsDeclaration()', () => {
23642364
it('should find the dts declaration that has the same relative path to the source file',
23652365
() => {
23662366
loadTestFiles(TYPINGS_SRC_FILES);

0 commit comments

Comments
 (0)