Skip to content

Commit a355e7d

Browse files
committed
feat(@schematics/angular): drop es6 from modern polyfills
1. Remove imports of es6 polyfills introduced by the CLI. 2. Refactor the migrations for version 8 by moving the codelyzer and polyfill transforms into different files. The PR drops all `core-js/es6` polyfills that we've introduced with the CLI, except the commented ones. We do not remove commented imports, since they are not part of the internal es6 polyfills. The migration automatically drops the associated comments with the removed imports since they are part of the node - under its `jsDoc` property.
1 parent 36d78de commit a355e7d

File tree

6 files changed

+269
-84
lines changed

6 files changed

+269
-84
lines changed

packages/angular_devkit/schematics/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export * from './rules/url';
2525
export * from './tree/delegate';
2626
export * from './tree/empty';
2727
export * from './tree/host-tree';
28-
export {UpdateRecorder} from './tree/interface';
28+
export { UpdateRecorder } from './tree/interface';
2929
export * from './engine/schematic';
3030
export * from './sink/dryrun';
3131
export * from './sink/filesystem';
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import { JsonParseMode, parseJsonAst } from '@angular-devkit/core';
10+
import {
11+
Rule,
12+
SchematicContext,
13+
Tree,
14+
} from '@angular-devkit/schematics';
15+
import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
16+
import {
17+
NodeDependency,
18+
NodeDependencyType,
19+
addPackageJsonDependency,
20+
} from '../../utility/dependencies';
21+
import { findPropertyInAstObject } from '../../utility/json-utils';
22+
23+
const ruleMapping: {[key: string]: string} = {
24+
'contextual-life-cycle': 'contextual-lifecycle',
25+
'no-conflicting-life-cycle-hooks': 'no-conflicting-lifecycle',
26+
'no-life-cycle-call': 'no-lifecycle-call',
27+
'use-life-cycle-interface': 'use-lifecycle-interface',
28+
'decorator-not-allowed': 'contextual-decorator',
29+
'enforce-component-selector': 'use-component-selector',
30+
'no-output-named-after-standard-event': 'no-output-native',
31+
'use-host-property-decorator': 'no-host-metadata-property',
32+
'use-input-property-decorator': 'no-inputs-metadata-property',
33+
'use-output-property-decorator': 'no-outputs-metadata-property',
34+
'no-queries-parameter': 'no-queries-metadata-property',
35+
'pipe-impure': 'no-pipe-impure',
36+
'use-view-encapsulation': 'use-component-view-encapsulation',
37+
i18n: 'template-i18n',
38+
'banana-in-box': 'template-banana-in-box',
39+
'no-template-call-expression': 'template-no-call-expression',
40+
'templates-no-negated-async': 'template-no-negated-async',
41+
'trackBy-function': 'template-use-track-by-function',
42+
'no-attribute-parameter-decorator': 'no-attribute-decorator',
43+
'max-inline-declarations': 'component-max-inline-declarations',
44+
};
45+
46+
export const updateTsLintConfig = (): Rule => {
47+
return (host: Tree) => {
48+
const tsLintPath = '/tslint.json';
49+
const buffer = host.read(tsLintPath);
50+
if (!buffer) {
51+
return host;
52+
}
53+
const tsCfgAst = parseJsonAst(buffer.toString(), JsonParseMode.Loose);
54+
55+
if (tsCfgAst.kind != 'object') {
56+
return host;
57+
}
58+
59+
const rulesNode = findPropertyInAstObject(tsCfgAst, 'rules');
60+
if (!rulesNode || rulesNode.kind != 'object') {
61+
return host;
62+
}
63+
64+
const recorder = host.beginUpdate(tsLintPath);
65+
66+
rulesNode.properties.forEach(prop => {
67+
const mapping = ruleMapping[prop.key.value];
68+
if (mapping) {
69+
recorder.remove(prop.key.start.offset + 1, prop.key.value.length);
70+
recorder.insertLeft(prop.key.start.offset + 1, mapping);
71+
}
72+
});
73+
74+
host.commitUpdate(recorder);
75+
76+
return host;
77+
};
78+
};
79+
80+
export const updatePackageJson = () => {
81+
return (host: Tree, context: SchematicContext) => {
82+
const dependency: NodeDependency = {
83+
type: NodeDependencyType.Dev,
84+
name: 'codelyzer',
85+
version: '^5.0.0',
86+
overwrite: true,
87+
};
88+
89+
addPackageJsonDependency(host, dependency);
90+
context.addTask(new NodePackageInstallTask());
91+
92+
return host;
93+
};
94+
};
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import { Rule, Tree } from '@angular-devkit/schematics';
10+
import * as ts from '../../third_party/github.com/Microsoft/TypeScript/lib/typescript';
11+
12+
const toDrop: {[importName: string]: true} = {
13+
'core-js/es6/symbol': true,
14+
'core-js/es6/object': true,
15+
'core-js/es6/function': true,
16+
'core-js/es6/parse-int': true,
17+
'core-js/es6/parse-float': true,
18+
'core-js/es6/number': true,
19+
'core-js/es6/math': true,
20+
'core-js/es6/string': true,
21+
'core-js/es6/date': true,
22+
'core-js/es6/array': true,
23+
'core-js/es6/regexp': true,
24+
'core-js/es6/map': true,
25+
'zone.js/dist/zone': true,
26+
'core-js/es6/set': true,
27+
};
28+
29+
const header = `/**
30+
*/
31+
32+
/***************************************************************************************************
33+
* BROWSER POLYFILLS
34+
*/
35+
36+
/** IE9, IE10 and IE11 requires all of the following polyfills. **/
37+
// import 'core-js/es6/weak-map';`;
38+
39+
const applicationPolyfillsHeader = 'APPLICATION IMPORTS';
40+
41+
export const dropES2015Polyfills = (): Rule => {
42+
return (tree: Tree) => {
43+
const path = '/polyfills.ts';
44+
const source = tree.read(path);
45+
if (!source) {
46+
return;
47+
}
48+
49+
// Start the update of the file.
50+
const recorder = tree.beginUpdate(path);
51+
52+
const sourceFile = ts.createSourceFile(path, source.toString(), ts.ScriptTarget.Latest, true);
53+
const imports = sourceFile.statements
54+
.filter(s => s.kind === ts.SyntaxKind.ImportDeclaration) as ts.ImportDeclaration[];
55+
56+
const applicationPolyfillsStart = sourceFile.getText().indexOf(applicationPolyfillsHeader);
57+
58+
if (imports.length === 0) { return; }
59+
60+
for (const i of imports) {
61+
const module = ts.isStringLiteral(i.moduleSpecifier) && i.moduleSpecifier.text;
62+
// We do not want to remove imports which are after the "APPLICATION IMPORTS" header.
63+
if (module && toDrop[module] && applicationPolyfillsStart > i.getFullStart()) {
64+
recorder.remove(i.getFullStart(), i.getFullWidth());
65+
}
66+
}
67+
68+
// We've removed the header since it's part of the JSDoc of the nodes we dropped
69+
// As part of the header, we also add the comment for importing WeakMap since
70+
// it's not part of the internal ES2015 polyfills we provide.
71+
if (sourceFile.getText().indexOf(header) < 0) {
72+
recorder.insertLeft(0, header);
73+
}
74+
75+
tree.commitUpdate(recorder);
76+
};
77+
};
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
// tslint:disable:no-big-function
9+
import { EmptyTree } from '@angular-devkit/schematics';
10+
import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';
11+
12+
describe('Migration to version 8', () => {
13+
const schematicRunner = new SchematicTestRunner(
14+
'migrations',
15+
require.resolve('../migration-collection.json'),
16+
);
17+
18+
let tree: UnitTestTree;
19+
const polyfillsPath = '/polyfills.ts';
20+
const defaultOptions = {};
21+
const polyfills = `/**
22+
*/
23+
24+
/***************************************************************************************************
25+
* BROWSER POLYFILLS
26+
*/
27+
28+
/** IE9, IE10 and IE11 requires all of the following polyfills. **/
29+
import 'core-js/es6/symbol';
30+
import 'core-js/es6/object';
31+
import 'core-js/es6/function';
32+
import 'core-js/es6/parse-int';
33+
import 'core-js/es6/parse-float';
34+
import 'core-js/es6/number';
35+
import 'core-js/es6/math';
36+
import 'core-js/es6/string';
37+
import 'core-js/es6/date';
38+
import 'core-js/es6/array';
39+
import 'core-js/es6/regexp';
40+
import 'core-js/es6/map';
41+
// import 'core-js/es6/weak-map';
42+
import 'core-js/es6/set';
43+
44+
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
45+
// import 'classlist.js'; // Run "npm install --save classlist.js".
46+
47+
/** IE10 and IE11 requires the following for the Reflect API. */
48+
// import 'core-js/es6/reflect';
49+
50+
/** Evergreen browsers require these. **/
51+
// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
52+
import 'core-js/es7/reflect';
53+
54+
/***************************************************************************************************
55+
* Zone JS is required by default for Angular itself.
56+
*/
57+
import 'zone.js/dist/zone'; // Included with Angular CLI.
58+
59+
/***************************************************************************************************
60+
* APPLICATION IMPORTS
61+
*/
62+
`;
63+
64+
const packageJson = {
65+
devDependencies: {
66+
codelyzer: '^4.5.0',
67+
},
68+
};
69+
const packageJsonPath = '/package.json';
70+
71+
describe('Migration to differential polyfill loading', () => {
72+
beforeEach(() => {
73+
tree = new UnitTestTree(new EmptyTree());
74+
tree.create(polyfillsPath, polyfills);
75+
tree.create(packageJsonPath, JSON.stringify(packageJson, null, 2));
76+
});
77+
78+
it('should drop the es6 polyfills', () => {
79+
tree = schematicRunner.runSchematic('migration-07', defaultOptions, tree);
80+
const polyfills = tree.readContent(polyfillsPath);
81+
expect(polyfills).not.toContain('core-js/es6/symbol');
82+
expect(polyfills).not.toContain('core-js/es6/set');
83+
expect(polyfills).not.toContain('zone.js');
84+
expect(polyfills).not.toContain('Zone');
85+
86+
// We don't want to drop this commented import comments
87+
expect(polyfills).toContain('core-js/es6/reflect');
88+
expect(polyfills).toContain('core-js/es7/reflect');
89+
expect(polyfills).toContain('BROWSER POLYFILLS');
90+
expect(polyfills).toContain('core-js/es6/weak-map');
91+
});
92+
});
93+
});

packages/schematics/angular/migrations/update-8/index.ts

Lines changed: 4 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -5,99 +5,20 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.io/license
77
*/
8-
import { JsonParseMode, parseJsonAst } from '@angular-devkit/core';
8+
99
import {
1010
Rule,
11-
SchematicContext,
12-
Tree,
1311
chain,
1412
} from '@angular-devkit/schematics';
15-
import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
16-
import {
17-
NodeDependency,
18-
NodeDependencyType,
19-
addPackageJsonDependency,
20-
} from '../../utility/dependencies';
21-
import { findPropertyInAstObject } from '../../utility/json-utils';
22-
23-
const ruleMapping: {[key: string]: string} = {
24-
'contextual-life-cycle': 'contextual-lifecycle',
25-
'no-conflicting-life-cycle-hooks': 'no-conflicting-lifecycle',
26-
'no-life-cycle-call': 'no-lifecycle-call',
27-
'use-life-cycle-interface': 'use-lifecycle-interface',
28-
'decorator-not-allowed': 'contextual-decorator',
29-
'enforce-component-selector': 'use-component-selector',
30-
'no-output-named-after-standard-event': 'no-output-native',
31-
'use-host-property-decorator': 'no-host-metadata-property',
32-
'use-input-property-decorator': 'no-inputs-metadata-property',
33-
'use-output-property-decorator': 'no-outputs-metadata-property',
34-
'no-queries-parameter': 'no-queries-metadata-property',
35-
'pipe-impure': 'no-pipe-impure',
36-
'use-view-encapsulation': 'use-component-view-encapsulation',
37-
i18n: 'template-i18n',
38-
'banana-in-box': 'template-banana-in-box',
39-
'no-template-call-expression': 'template-no-call-expression',
40-
'templates-no-negated-async': 'template-no-negated-async',
41-
'trackBy-function': 'template-use-track-by-function',
42-
'no-attribute-parameter-decorator': 'no-attribute-decorator',
43-
'max-inline-declarations': 'component-max-inline-declarations',
44-
};
45-
46-
function updateTsLintConfig(): Rule {
47-
return (host: Tree) => {
48-
const tsLintPath = '/tslint.json';
49-
const buffer = host.read(tsLintPath);
50-
if (!buffer) {
51-
return host;
52-
}
53-
const tsCfgAst = parseJsonAst(buffer.toString(), JsonParseMode.Loose);
54-
55-
if (tsCfgAst.kind != 'object') {
56-
return host;
57-
}
58-
59-
const rulesNode = findPropertyInAstObject(tsCfgAst, 'rules');
60-
if (!rulesNode || rulesNode.kind != 'object') {
61-
return host;
62-
}
63-
64-
const recorder = host.beginUpdate(tsLintPath);
65-
66-
rulesNode.properties.forEach(prop => {
67-
const mapping = ruleMapping[prop.key.value];
68-
if (mapping) {
69-
recorder.remove(prop.key.start.offset + 1, prop.key.value.length);
70-
recorder.insertLeft(prop.key.start.offset + 1, mapping);
71-
}
72-
});
73-
74-
host.commitUpdate(recorder);
75-
76-
return host;
77-
};
78-
}
79-
80-
function updatePackageJson() {
81-
return (host: Tree, context: SchematicContext) => {
82-
const dependency: NodeDependency = {
83-
type: NodeDependencyType.Dev,
84-
name: 'codelyzer',
85-
version: '^5.0.0',
86-
overwrite: true,
87-
};
88-
89-
addPackageJsonDependency(host, dependency);
90-
context.addTask(new NodePackageInstallTask());
91-
92-
return host;
93-
};
94-
}
13+
import { updatePackageJson, updateTsLintConfig } from './codelyzer-5';
14+
import { dropES2015Polyfills } from './drop-es6-polyfills';
9515

9616
export default function(): Rule {
9717
return () => {
9818
return chain([
9919
updateTsLintConfig(),
10020
updatePackageJson(),
21+
dropES2015Polyfills(),
10122
]);
10223
};
10324
}

0 commit comments

Comments
 (0)