update-app-tsconfigs.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  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 path_1 = require("path");
  12. const json_utils_1 = require("../../utility/json-utils");
  13. const workspace_models_1 = require("../../utility/workspace-models");
  14. const utils_1 = require("./utils");
  15. /**
  16. * Update the tsconfig files for applications
  17. * - Removes enableIvy: true
  18. * - Sets stricter file inclusions
  19. * - Sets module compiler option to esnext or commonjs
  20. */
  21. function updateApplicationTsConfigs() {
  22. return (tree, context) => {
  23. const workspace = utils_1.getWorkspace(tree);
  24. const logger = context.logger;
  25. // Add `module` option in the workspace tsconfig
  26. updateModuleCompilerOption(tree, '/tsconfig.json');
  27. for (const { target, project } of utils_1.getTargets(workspace, 'build', workspace_models_1.Builders.Browser)) {
  28. updateTsConfig(tree, target, project, workspace_models_1.Builders.Browser, logger);
  29. }
  30. for (const { target, project } of utils_1.getTargets(workspace, 'server', workspace_models_1.Builders.Server)) {
  31. updateTsConfig(tree, target, project, workspace_models_1.Builders.Server, logger);
  32. }
  33. for (const { target, project } of utils_1.getTargets(workspace, 'test', workspace_models_1.Builders.Karma)) {
  34. updateTsConfig(tree, target, project, workspace_models_1.Builders.Karma, logger);
  35. }
  36. return tree;
  37. };
  38. }
  39. exports.updateApplicationTsConfigs = updateApplicationTsConfigs;
  40. function updateTsConfig(tree, builderConfig, project, builderName, logger) {
  41. var _a;
  42. const options = utils_1.getAllOptions(builderConfig);
  43. for (const option of options) {
  44. let recorder;
  45. const tsConfigOption = json_utils_1.findPropertyInAstObject(option, 'tsConfig');
  46. if (!tsConfigOption || tsConfigOption.kind !== 'string') {
  47. continue;
  48. }
  49. const tsConfigPath = tsConfigOption.value;
  50. let tsConfigAst = utils_1.readJsonFileAsAstObject(tree, tsConfigPath);
  51. if (!tsConfigAst) {
  52. logger.warn(`Cannot find file: ${tsConfigPath}`);
  53. continue;
  54. }
  55. // Remove 'enableIvy: true' since this is the default in version 9.
  56. const angularCompilerOptions = json_utils_1.findPropertyInAstObject(tsConfigAst, 'angularCompilerOptions');
  57. if (angularCompilerOptions && angularCompilerOptions.kind === 'object') {
  58. const enableIvy = json_utils_1.findPropertyInAstObject(angularCompilerOptions, 'enableIvy');
  59. if (enableIvy && enableIvy.kind === 'true') {
  60. recorder = tree.beginUpdate(tsConfigPath);
  61. if (angularCompilerOptions.properties.length === 1) {
  62. // remove entire 'angularCompilerOptions'
  63. json_utils_1.removePropertyInAstObject(recorder, tsConfigAst, 'angularCompilerOptions');
  64. }
  65. else {
  66. json_utils_1.removePropertyInAstObject(recorder, angularCompilerOptions, 'enableIvy');
  67. }
  68. tree.commitUpdate(recorder);
  69. }
  70. }
  71. // Update 'module' compilerOption
  72. updateModuleCompilerOption(tree, tsConfigPath, builderName);
  73. // Add stricter file inclusions to avoid unused file warning during compilation
  74. if (builderName !== workspace_models_1.Builders.Karma) {
  75. // Note: we need to re-read the tsconfig after very commit because
  76. // otherwise the updates will be out of sync since we are ammending the same node.
  77. // we are already checking that tsconfig exists above!
  78. // tslint:disable-next-line: no-non-null-assertion
  79. tsConfigAst = utils_1.readJsonFileAsAstObject(tree, tsConfigPath);
  80. const include = json_utils_1.findPropertyInAstObject(tsConfigAst, 'include');
  81. if (include && include.kind === 'array') {
  82. const tsInclude = include.elements.find(({ value }) => typeof value === 'string' && value.endsWith('**/*.ts'));
  83. if (tsInclude) {
  84. const { start, end } = tsInclude;
  85. recorder = tree.beginUpdate(tsConfigPath);
  86. recorder.remove(start.offset, end.offset - start.offset);
  87. // Replace ts includes with d.ts
  88. recorder.insertLeft(start.offset, tsInclude.text.replace('.ts', '.d.ts'));
  89. tree.commitUpdate(recorder);
  90. }
  91. }
  92. else {
  93. // Includes are not present, add includes to dts files
  94. // By default when 'include' nor 'files' fields are used TypeScript
  95. // will include all ts files.
  96. const srcRootAst = json_utils_1.findPropertyInAstObject(project, 'sourceRoot');
  97. const include = ((_a = srcRootAst) === null || _a === void 0 ? void 0 : _a.kind) === 'string'
  98. ? core_1.join(core_1.normalize(srcRootAst.value), '**/*.d.ts')
  99. : '**/*.d.ts';
  100. recorder = tree.beginUpdate(tsConfigPath);
  101. json_utils_1.insertPropertyInAstObjectInOrder(recorder, tsConfigAst, 'include', [include], 2);
  102. tree.commitUpdate(recorder);
  103. }
  104. const files = json_utils_1.findPropertyInAstObject(tsConfigAst, 'files');
  105. if (!files) {
  106. const newFiles = [];
  107. const tsConfigDir = path_1.dirname(utils_1.forwardSlashPath(tsConfigPath));
  108. const mainOption = json_utils_1.findPropertyInAstObject(option, 'main');
  109. if (mainOption && mainOption.kind === 'string') {
  110. newFiles.push(utils_1.forwardSlashPath(path_1.relative(tsConfigDir, utils_1.forwardSlashPath(mainOption.value))));
  111. }
  112. const polyfillsOption = json_utils_1.findPropertyInAstObject(option, 'polyfills');
  113. if (polyfillsOption && polyfillsOption.kind === 'string') {
  114. newFiles.push(utils_1.forwardSlashPath(path_1.relative(tsConfigDir, utils_1.forwardSlashPath(polyfillsOption.value))));
  115. }
  116. if (newFiles.length) {
  117. recorder = tree.beginUpdate(tsConfigPath);
  118. // tslint:disable-next-line: no-non-null-assertion
  119. tsConfigAst = utils_1.readJsonFileAsAstObject(tree, tsConfigPath);
  120. json_utils_1.insertPropertyInAstObjectInOrder(recorder, tsConfigAst, 'files', newFiles, 2);
  121. tree.commitUpdate(recorder);
  122. }
  123. recorder = tree.beginUpdate(tsConfigPath);
  124. // tslint:disable-next-line: no-non-null-assertion
  125. tsConfigAst = utils_1.readJsonFileAsAstObject(tree, tsConfigPath);
  126. json_utils_1.removePropertyInAstObject(recorder, tsConfigAst, 'exclude');
  127. tree.commitUpdate(recorder);
  128. }
  129. }
  130. }
  131. }
  132. function updateModuleCompilerOption(tree, tsConfigPath, builderName) {
  133. const tsConfigAst = utils_1.readJsonFileAsAstObject(tree, tsConfigPath);
  134. if (!tsConfigAst) {
  135. return;
  136. }
  137. const compilerOptions = json_utils_1.findPropertyInAstObject(tsConfigAst, 'compilerOptions');
  138. if (!compilerOptions || compilerOptions.kind !== 'object') {
  139. return;
  140. }
  141. const configExtends = json_utils_1.findPropertyInAstObject(tsConfigAst, 'extends');
  142. const isExtendedConfig = configExtends && configExtends.kind === 'string';
  143. const recorder = tree.beginUpdate(tsConfigPath);
  144. // Server tsconfig should have a module of commonjs
  145. const moduleType = builderName === workspace_models_1.Builders.Server ? 'commonjs' : 'esnext';
  146. if (isExtendedConfig && builderName !== workspace_models_1.Builders.Server) {
  147. json_utils_1.removePropertyInAstObject(recorder, compilerOptions, 'module');
  148. }
  149. else {
  150. const scriptModule = json_utils_1.findPropertyInAstObject(compilerOptions, 'module');
  151. if (!scriptModule) {
  152. json_utils_1.insertPropertyInAstObjectInOrder(recorder, compilerOptions, 'module', moduleType, 4);
  153. }
  154. else if (scriptModule.value !== moduleType) {
  155. const { start, end } = scriptModule;
  156. recorder.remove(start.offset, end.offset - start.offset);
  157. recorder.insertLeft(start.offset, `"${moduleType}"`);
  158. }
  159. }
  160. tree.commitUpdate(recorder);
  161. }