From 869e3e8edc62125ce2e84b1922dbb9ec6f845a2f Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin Date: Thu, 23 May 2019 18:49:16 +0100 Subject: [PATCH] fix(ivy): ngcc - infer entry-point typings from format paths (#30591) Some packages do not actually provide a `typings` field in their package.json. But TypeScript naturally infers the typings file from the location of the JavaScript source file. This commit modifies ngcc to do a similar inference when finding entry-points to process. Fixes #28603 (FW-1299) PR Close #30591 --- .../ngcc/src/packages/entry_point.ts | 21 ++++++++- .../ngcc/test/packages/entry_point_spec.ts | 45 +++++++++++++++++-- 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/packages/compiler-cli/ngcc/src/packages/entry_point.ts b/packages/compiler-cli/ngcc/src/packages/entry_point.ts index 6bcfff20c5..2c043d210f 100644 --- a/packages/compiler-cli/ngcc/src/packages/entry_point.ts +++ b/packages/compiler-cli/ngcc/src/packages/entry_point.ts @@ -91,7 +91,8 @@ export function getEntryPointInfo( } // We must have a typings property - const typings = entryPointPackageJson.typings || entryPointPackageJson.types; + const typings = entryPointPackageJson.typings || entryPointPackageJson.types || + guessTypingsFromPackageJson(fs, entryPointPath, entryPointPackageJson); if (!typings) { return null; } @@ -191,3 +192,21 @@ function mergeConfigAndPackageJson( } } } + +function guessTypingsFromPackageJson( + fs: FileSystem, entryPointPath: AbsoluteFsPath, + entryPointPackageJson: EntryPointPackageJson): AbsoluteFsPath|null { + for (const prop of SUPPORTED_FORMAT_PROPERTIES) { + const field = entryPointPackageJson[prop]; + if (typeof field !== 'string') { + // Some crazy packages have things like arrays in these fields! + continue; + } + const relativeTypingsPath = field.replace(/\.js$/, '.d.ts'); + const typingsPath = resolve(entryPointPath, relativeTypingsPath); + if (fs.exists(typingsPath)) { + return typingsPath; + } + } + return null; +} diff --git a/packages/compiler-cli/ngcc/test/packages/entry_point_spec.ts b/packages/compiler-cli/ngcc/test/packages/entry_point_spec.ts index c8735f68c2..984379a11b 100644 --- a/packages/compiler-cli/ngcc/test/packages/entry_point_spec.ts +++ b/packages/compiler-cli/ngcc/test/packages/entry_point_spec.ts @@ -10,7 +10,7 @@ import {AbsoluteFsPath, FileSystem, absoluteFrom, getFileSystem} from '../../../ import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; import {loadTestFiles} from '../../../test/helpers'; import {NgccConfiguration} from '../../src/packages/configuration'; -import {getEntryPointInfo} from '../../src/packages/entry_point'; +import {SUPPORTED_FORMAT_PROPERTIES, getEntryPointInfo} from '../../src/packages/entry_point'; import {MockLogger} from '../helpers/mock_logger'; runInEachFileSystem(() => { @@ -178,6 +178,43 @@ runInEachFileSystem(() => { expect(entryPoint).toBe(null); }); + for (let prop of SUPPORTED_FORMAT_PROPERTIES) { + // Ignore the UMD format + if (prop === 'main') continue; + // Let's give 'module' a specific path, otherwise compute it based on the property. + const typingsPath = prop === 'module' ? 'index' : `${prop}/missing_typings`; + + it(`should return an object if it can guess the typings path from the "${prop}" field`, () => { + loadTestFiles([ + { + name: _('/project/node_modules/some_package/missing_typings/package.json'), + contents: createPackageJson('missing_typings', {excludes: ['typings']}), + }, + { + name: _( + `/project/node_modules/some_package/missing_typings/${typingsPath}.metadata.json`), + contents: 'some meta data', + }, + { + name: _(`/project/node_modules/some_package/missing_typings/${typingsPath}.d.ts`), + contents: '// some typings file', + }, + ]); + const config = new NgccConfiguration(fs, _('/project')); + const entryPoint = getEntryPointInfo( + fs, config, new MockLogger(), SOME_PACKAGE, + _('/project/node_modules/some_package/missing_typings')); + expect(entryPoint).toEqual({ + name: 'some_package/missing_typings', + package: SOME_PACKAGE, + path: _('/project/node_modules/some_package/missing_typings'), + typings: _(`/project/node_modules/some_package/missing_typings/${typingsPath}.d.ts`), + packageJson: loadPackageJson(fs, '/project/node_modules/some_package/missing_typings'), + compiledByAngular: true, + }); + }); + } + it('should return an object with `compiledByAngular` set to false if there is no metadata.json file next to the typing file', () => { loadTestFiles([ @@ -311,9 +348,11 @@ runInEachFileSystem(() => { [typingsProp]: `./${packageName}.d.ts`, fesm2015: `./fesm2015/${packageName}.js`, esm2015: `./esm2015/${packageName}.js`, - fesm5: `./fesm2015/${packageName}.js`, - esm5: `./esm2015/${packageName}.js`, + es2015: `./es2015/${packageName}.js`, + fesm5: `./fesm5/${packageName}.js`, + esm5: `./esm5/${packageName}.js`, main: `./bundles/${packageName}.umd.js`, + module: './index.js', }; if (excludes) { excludes.forEach(exclude => delete packageJson[exclude]);