Skip to content

Commit

Permalink
fix(@schematics/angular): handle polyfill migration in non root appli…
Browse files Browse the repository at this point in the history
…cations
  • Loading branch information
Alan Agius committed Apr 15, 2019
1 parent efccea6 commit 80749b3
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 23 deletions.
Expand Up @@ -6,7 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/

import { Rule, Tree } from '@angular-devkit/schematics';
import { JsonParseMode, isJsonObject, join, normalize, parseJson } from '@angular-devkit/core';
import { Rule, Tree, chain, noop } from '@angular-devkit/schematics';
import * as ts from '../../third_party/github.com/Microsoft/TypeScript/lib/typescript';

const toDrop: {[importName: string]: true} = {
Expand All @@ -26,35 +27,52 @@ const toDrop: {[importName: string]: true} = {
};

const header = `/**
*/
* This file includes polyfills needed by Angular and is loaded before the app.
* You can add your own extra polyfills to this file.
*
* This file is divided into 2 sections:
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
* file.
*
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
*
* Learn more in https://angular.io/guide/browser-support
*/
/***************************************************************************************************
* BROWSER POLYFILLS
*/
/** IE9, IE10 and IE11 requires all of the following polyfills. **/
// import 'core-js/es6/weak-map';`;
// import 'core-js/es6/weak-map';
`;

const applicationPolyfillsHeader = 'APPLICATION IMPORTS';

export const dropES2015Polyfills = (): Rule => {
function dropES2015PolyfillsFromFile(polyfillPath: string): Rule {
return (tree: Tree) => {
const path = '/polyfills.ts';
const source = tree.read(path);
const source = tree.read(polyfillPath);
if (!source) {
return;
return noop();
}

// Start the update of the file.
const recorder = tree.beginUpdate(path);
const recorder = tree.beginUpdate(polyfillPath);

const sourceFile = ts.createSourceFile(path, source.toString(), ts.ScriptTarget.Latest, true);
const sourceFile = ts.createSourceFile(polyfillPath,
source.toString(),
ts.ScriptTarget.Latest,
true,
);
const imports = sourceFile.statements
.filter(s => s.kind === ts.SyntaxKind.ImportDeclaration) as ts.ImportDeclaration[];
.filter(s => s.kind === ts.SyntaxKind.ImportDeclaration) as ts.ImportDeclaration[];

const applicationPolyfillsStart = sourceFile.getText().indexOf(applicationPolyfillsHeader);

if (imports.length === 0) { return; }
if (imports.length === 0) { return noop(); }

for (const i of imports) {
const module = ts.isStringLiteral(i.moduleSpecifier) && i.moduleSpecifier.text;
Expand All @@ -73,4 +91,43 @@ export const dropES2015Polyfills = (): Rule => {

tree.commitUpdate(recorder);
};
};
}

/**
* Move the import reflect metadata polyfill from the polyfill file to the dev environment. This is
* not guaranteed to work, but if it doesn't it will result in no changes made.
*/
export function dropES2015Polyfills(): Rule {
return (tree) => {
// Simple. Take the ast of polyfills (if it exists) and find the import metadata. Remove it.
const angularConfigContent = tree.read('angular.json') || tree.read('.angular.json');
const rules: Rule[] = [];

if (!angularConfigContent) {
// Is this even an angular project?
return;
}

const angularJson = parseJson(angularConfigContent.toString(), JsonParseMode.Loose);

if (!isJsonObject(angularJson) || !isJsonObject(angularJson.projects)) {
// If that field isn't there, no use...
return;
}

// For all projects
for (const projectName of Object.keys(angularJson.projects)) {
const project = angularJson.projects[projectName];
if (!isJsonObject(project)) {
continue;
}
if (typeof project.sourceRoot != 'string' || project.projectType !== 'application') {
continue;
}

rules.push(dropES2015PolyfillsFromFile(join(normalize(project.sourceRoot), '/polyfills.ts')));
}

return chain(rules);
};
}
Expand Up @@ -16,7 +16,7 @@ describe('Migration to version 8', () => {
);

let tree: UnitTestTree;
const polyfillsPath = '/polyfills.ts';
const polyfillsPath = '/src/polyfills.ts';
const defaultOptions = {};
const polyfills = `/**
*/
Expand Down Expand Up @@ -61,18 +61,19 @@ import 'zone.js/dist/zone'; // Included with Angular CLI.
*/
`;

const packageJson = {
devDependencies: {
codelyzer: '^4.5.0',
},
};
const packageJsonPath = '/package.json';

describe('Migration to differential polyfill loading', () => {
beforeEach(() => {
beforeEach(async () => {
tree = new UnitTestTree(new EmptyTree());
tree.create(polyfillsPath, polyfills);
tree.create(packageJsonPath, JSON.stringify(packageJson, null, 2));
tree = await schematicRunner.runExternalSchematicAsync(
require.resolve('../../collection.json'), 'ng-new',
{
name: 'migration-test',
version: '1.2.3',
directory: '.',
},
tree,
).toPromise();
tree.overwrite(polyfillsPath, polyfills);
});

it('should drop the es6 polyfills', () => {
Expand All @@ -89,5 +90,25 @@ import 'zone.js/dist/zone'; // Included with Angular CLI.
expect(polyfills).toContain('BROWSER POLYFILLS');
expect(polyfills).toContain('core-js/es6/weak-map');
});

it('should work as expected for a project with a root', async () => {
const originalContent = JSON.parse(tree.readContent('angular.json'));
originalContent.projects['migration-test'].sourceRoot = 'foo/src';
tree.overwrite('angular.json', JSON.stringify(originalContent));
const polyfillPath = '/foo/src/polyfills.ts';
tree.create(polyfillPath, polyfills);
tree = schematicRunner.runSchematic('migration-07', defaultOptions, tree);
const newPolyfills = tree.readContent(polyfillPath);
expect(newPolyfills).not.toContain('core-js/es6/symbol');
expect(newPolyfills).not.toContain('core-js/es6/set');
expect(newPolyfills).toContain('zone.js');
expect(newPolyfills).toContain('Zone');

// We don't want to drop this commented import comments
expect(newPolyfills).toContain('core-js/es6/reflect');
expect(newPolyfills).toContain('core-js/es7/reflect');
expect(newPolyfills).toContain('BROWSER POLYFILLS');
expect(newPolyfills).toContain('core-js/es6/weak-map');
});
});
});

0 comments on commit 80749b3

Please sign in to comment.