From 3cf55c195b9d136f5b06455dce834504cf8d6643 Mon Sep 17 00:00:00 2001 From: Pete Bacon Darwin Date: Fri, 31 Jan 2020 21:07:58 +0000 Subject: [PATCH] refactor(ngcc): add additional build marker helpers (#35079) PR Close #35079 --- .../ngcc/src/packages/build_marker.ts | 42 +++++++ .../ngcc/test/packages/build_marker_spec.ts | 107 +++++++++++++++++- 2 files changed, 148 insertions(+), 1 deletion(-) diff --git a/packages/compiler-cli/ngcc/src/packages/build_marker.ts b/packages/compiler-cli/ngcc/src/packages/build_marker.ts index 140a3efc6b..3e214a63f0 100644 --- a/packages/compiler-cli/ngcc/src/packages/build_marker.ts +++ b/packages/compiler-cli/ngcc/src/packages/build_marker.ts @@ -6,11 +6,53 @@ * found in the LICENSE file at https://angular.io/license */ import {AbsoluteFsPath} from '../../../src/ngtsc/file_system'; +import {NGCC_PROPERTY_EXTENSION} from '../writing/new_entry_point_file_writer'; import {PackageJsonUpdater} from '../writing/package_json_updater'; import {EntryPointPackageJson, PackageJsonFormatProperties} from './entry_point'; export const NGCC_VERSION = '0.0.0-PLACEHOLDER'; +/** + * Returns true if there is a format in this entry-point that was compiled with an outdated version + * of ngcc. + * + * @param packageJson The parsed contents of the package.json for the entry-point + */ +export function needsCleaning(packageJson: EntryPointPackageJson): boolean { + return Object.values(packageJson.__processed_by_ivy_ngcc__ || {}) + .some(value => value !== NGCC_VERSION); +} + +/** + * Clean any build marker artifacts from the given `packageJson` object. + * @param packageJson The parsed contents of the package.json to modify + * @returns true if the package was modified during cleaning + */ +export function cleanPackageJson(packageJson: EntryPointPackageJson): boolean { + if (packageJson.__processed_by_ivy_ngcc__ !== undefined) { + // Remove the actual marker + delete packageJson.__processed_by_ivy_ngcc__; + // Remove new format properties that have been added by ngcc + for (const prop of Object.keys(packageJson)) { + if (prop.endsWith(NGCC_PROPERTY_EXTENSION)) { + delete packageJson[prop]; + } + } + + // Also remove the prebulish script if we modified it + const scripts = packageJson.scripts; + if (scripts !== undefined && scripts.prepublishOnly) { + delete scripts.prepublishOnly; + if (scripts.prepublishOnly__ivy_ngcc_bak !== undefined) { + scripts.prepublishOnly = scripts.prepublishOnly__ivy_ngcc_bak; + delete scripts.prepublishOnly__ivy_ngcc_bak; + } + } + return true; + } + return false; +} + /** * Check whether ngcc has already processed a given entry-point format. * diff --git a/packages/compiler-cli/ngcc/test/packages/build_marker_spec.ts b/packages/compiler-cli/ngcc/test/packages/build_marker_spec.ts index 9c729341ac..e6637cf99d 100644 --- a/packages/compiler-cli/ngcc/test/packages/build_marker_spec.ts +++ b/packages/compiler-cli/ngcc/test/packages/build_marker_spec.ts @@ -8,7 +8,8 @@ import {absoluteFrom, getFileSystem} from '../../../src/ngtsc/file_system'; import {runInEachFileSystem} from '../../../src/ngtsc/file_system/testing'; import {loadTestFiles} from '../../../test/helpers'; -import {hasBeenProcessed, markAsProcessed} from '../../src/packages/build_marker'; +import {NGCC_VERSION, cleanPackageJson, hasBeenProcessed, markAsProcessed, needsCleaning} from '../../src/packages/build_marker'; +import {EntryPointPackageJson} from '../../src/packages/entry_point'; import {DirectPackageJsonUpdater} from '../../src/writing/package_json_updater'; runInEachFileSystem(() => { @@ -194,5 +195,109 @@ runInEachFileSystem(() => { it('should return false if no markers exist', () => { expect(hasBeenProcessed({name: 'test'}, 'module')).toBe(false); }); }); + + describe('needsCleaning()', () => { + it('should return true if any format has been compiled with a different version', () => { + expect(needsCleaning({ + name: 'test', + __processed_by_ivy_ngcc__: {'fesm2015': '8.0.0', 'esm5': NGCC_VERSION} + })).toBe(true); + }); + + it('should return false if all formats have been compiled with the current version', () => { + expect(needsCleaning({name: 'test', __processed_by_ivy_ngcc__: {'fesm2015': NGCC_VERSION}})) + .toBe(false); + }); + + it('should return false if no formats have been compiled', () => { + expect(needsCleaning({name: 'test', __processed_by_ivy_ngcc__: {}})).toBe(false); + expect(needsCleaning({name: 'test'})).toBe(false); + }); + }); + + describe('cleanPackageJson()', () => { + it('should not touch the object if there is no build marker', () => { + const packageJson: EntryPointPackageJson = {name: 'test-package'}; + const result = cleanPackageJson(packageJson); + expect(result).toBe(false); + expect(packageJson).toEqual({name: 'test-package'}); + }); + + it('should remove the processed marker', () => { + const packageJson: EntryPointPackageJson = { + name: 'test-package', + __processed_by_ivy_ngcc__: {'fesm2015': '8.0.0'} + }; + const result = cleanPackageJson(packageJson); + expect(result).toBe(true); + expect(packageJson).toEqual({name: 'test-package'}); + }); + + it('should remove new entry-point format properties', () => { + const packageJson: EntryPointPackageJson = { + name: 'test-package', + __processed_by_ivy_ngcc__: {'fesm2015': '8.0.0'}, + fesm2015: 'index.js', + fesm2015_ivy_ngcc: '__ivy_ngcc__/index.js' + }; + const result = cleanPackageJson(packageJson); + expect(result).toBe(true); + expect(packageJson).toEqual({name: 'test-package', fesm2015: 'index.js'}); + }); + + it('should remove the prepublish script if there was a processed marker', () => { + const packageJson: EntryPointPackageJson = { + name: 'test-package', + __processed_by_ivy_ngcc__: {'fesm2015': '8.0.0'}, + scripts: {prepublishOnly: 'added by ngcc', test: 'do testing'}, + }; + const result = cleanPackageJson(packageJson); + expect(result).toBe(true); + expect(packageJson).toEqual({ + name: 'test-package', + scripts: {test: 'do testing'}, + }); + }); + + it('should revert and remove the backup for the prepublish script if there was a processed marker', + () => { + const packageJson: EntryPointPackageJson = { + name: 'test-package', + __processed_by_ivy_ngcc__: {'fesm2015': '8.0.0'}, + scripts: { + prepublishOnly: 'added by ngcc', + prepublishOnly__ivy_ngcc_bak: 'original', + test: 'do testing' + }, + }; + const result = cleanPackageJson(packageJson); + expect(result).toBe(true); + expect(packageJson).toEqual({ + name: 'test-package', + scripts: {prepublishOnly: 'original', test: 'do testing'}, + }); + }); + + it('should not touch the scripts if there was no processed marker', () => { + const packageJson: EntryPointPackageJson = { + name: 'test-package', + scripts: { + prepublishOnly: 'added by ngcc', + prepublishOnly__ivy_ngcc_bak: 'original', + test: 'do testing' + }, + }; + const result = cleanPackageJson(packageJson); + expect(result).toBe(false); + expect(packageJson).toEqual({ + name: 'test-package', + scripts: { + prepublishOnly: 'added by ngcc', + prepublishOnly__ivy_ngcc_bak: 'original', + test: 'do testing' + } + }); + }); + }); }); });