drop-es6-polyfills.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. /**
  4. * @license
  5. * Copyright Google Inc. All Rights Reserved.
  6. *
  7. * Use of this source code is governed by an MIT-style license that can be
  8. * found in the LICENSE file at https://angular.io/license
  9. */
  10. const core_1 = require("@angular-devkit/core");
  11. const schematics_1 = require("@angular-devkit/schematics");
  12. const crypto_1 = require("crypto");
  13. const ts = require("../../third_party/github.com/Microsoft/TypeScript/lib/typescript");
  14. const toDrop = {
  15. 'core-js/es6/symbol': true,
  16. 'core-js/es6/object': true,
  17. 'core-js/es6/function': true,
  18. 'core-js/es6/parse-int': true,
  19. 'core-js/es6/parse-float': true,
  20. 'core-js/es6/number': true,
  21. 'core-js/es6/math': true,
  22. 'core-js/es6/string': true,
  23. 'core-js/es6/date': true,
  24. 'core-js/es6/array': true,
  25. 'core-js/es6/regexp': true,
  26. 'core-js/es6/map': true,
  27. 'core-js/es6/set': true,
  28. 'core-js/es6/weak-map': true,
  29. };
  30. const header = `/**
  31. * This file includes polyfills needed by Angular and is loaded before the app.
  32. * You can add your own extra polyfills to this file.
  33. *
  34. * This file is divided into 2 sections:
  35. * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
  36. * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
  37. * file.
  38. *
  39. * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
  40. * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
  41. * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
  42. *
  43. * Learn more in https://angular.io/guide/browser-support
  44. */
  45. /***************************************************************************************************
  46. * BROWSER POLYFILLS
  47. */
  48. `;
  49. const applicationPolyfillsHeader = 'APPLICATION IMPORTS';
  50. const browserPolyfillsHeader = 'BROWSER POLYFILLS';
  51. const knownPolyfillHashes = [
  52. '3dba718d7afe009e112e10d69073d2a2',
  53. 'fccdb76b06ea636933f8b99b1c8d9725',
  54. '97e16639be1de06153695f5fefde745d',
  55. 'd6c13d6dcf94ff3749283f33dd0d4864',
  56. '79bf0fd46c215e5f4145e15641c325f3',
  57. '6fe8080c7e38ee0ce677fdbc3884377a',
  58. '8e7f6abb3d2dca03b4dbb300e400a880',
  59. ];
  60. function dropES2015PolyfillsFromFile(polyfillPath) {
  61. return (tree) => {
  62. const source = tree.read(polyfillPath);
  63. if (!source) {
  64. return;
  65. }
  66. const content = source.toString();
  67. // Check if file is unmodified, if so then replace and return
  68. const hash = crypto_1.createHash('md5');
  69. // normalize line endings to increase hash match chances
  70. hash.update(content.replace(/\r\n|\r/g, '\n'));
  71. const digest = hash.digest('hex');
  72. if (knownPolyfillHashes.includes(digest)) {
  73. // Replace with new project polyfills file
  74. // This removes the need to parse and also updates all included comments
  75. // mergeWith overwrite doesn't work so clear out existing file
  76. tree.delete(polyfillPath);
  77. return schematics_1.mergeWith(schematics_1.apply(schematics_1.url('../../application/files/src'), [
  78. schematics_1.filter(path => path === '/polyfills.ts.template'),
  79. schematics_1.move('/polyfills.ts.template', polyfillPath),
  80. ]), schematics_1.MergeStrategy.Overwrite);
  81. }
  82. if (!content.includes('core-js')) {
  83. // no action required if no mention of core-js
  84. return;
  85. }
  86. const sourceFile = ts.createSourceFile(polyfillPath, content.replace(/^\uFEFF/, ''), ts.ScriptTarget.Latest, true);
  87. const imports = sourceFile.statements
  88. .filter(s => s.kind === ts.SyntaxKind.ImportDeclaration);
  89. if (imports.length === 0) {
  90. return;
  91. }
  92. // Start the update of the file.
  93. const recorder = tree.beginUpdate(polyfillPath);
  94. const applicationPolyfillsStart = content.indexOf(applicationPolyfillsHeader);
  95. const browserPolyfillsStart = content.indexOf(browserPolyfillsHeader);
  96. let addHeader = false;
  97. for (const i of imports) {
  98. const module = ts.isStringLiteral(i.moduleSpecifier) && i.moduleSpecifier.text;
  99. // We do not want to remove imports which are after the "APPLICATION IMPORTS" header.
  100. if (module && toDrop[module] && applicationPolyfillsStart > i.getFullStart()) {
  101. recorder.remove(i.getFullStart(), i.getFullWidth());
  102. if (i.getFullStart() <= browserPolyfillsStart) {
  103. addHeader = true;
  104. }
  105. }
  106. }
  107. // We've removed the header since it's part of the JSDoc of the nodes we dropped
  108. if (addHeader) {
  109. recorder.insertLeft(0, header);
  110. }
  111. tree.commitUpdate(recorder);
  112. };
  113. }
  114. /**
  115. * Drop ES2015 polyfills from all application projects
  116. */
  117. function dropES2015Polyfills() {
  118. return (tree) => {
  119. // Simple. Take the ast of polyfills (if it exists) and find the import metadata. Remove it.
  120. const angularConfigContent = tree.read('angular.json') || tree.read('.angular.json');
  121. const rules = [];
  122. if (!angularConfigContent) {
  123. // Is this even an angular project?
  124. return;
  125. }
  126. const angularJson = core_1.parseJson(angularConfigContent.toString(), core_1.JsonParseMode.Loose);
  127. if (!core_1.isJsonObject(angularJson) || !core_1.isJsonObject(angularJson.projects)) {
  128. // If that field isn't there, no use...
  129. return;
  130. }
  131. // For all projects
  132. for (const projectName of Object.keys(angularJson.projects)) {
  133. const project = angularJson.projects[projectName];
  134. if (!core_1.isJsonObject(project)) {
  135. continue;
  136. }
  137. if (project.projectType !== 'application') {
  138. continue;
  139. }
  140. const architect = project.architect;
  141. if (!core_1.isJsonObject(architect)
  142. || !core_1.isJsonObject(architect.build)
  143. || !core_1.isJsonObject(architect.build.options)
  144. || typeof architect.build.options.polyfills !== 'string') {
  145. continue;
  146. }
  147. rules.push(dropES2015PolyfillsFromFile(architect.build.options.polyfills));
  148. }
  149. return schematics_1.chain(rules);
  150. };
  151. }
  152. exports.dropES2015Polyfills = dropES2015Polyfills;