@nx/angular 24.0.0-beta.2 → 24.0.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (204) hide show
  1. package/dist/executors.d.ts +0 -2
  2. package/dist/executors.js +0 -2
  3. package/dist/fesm2022/nx-angular.mjs +0 -4
  4. package/dist/generators.d.ts +0 -4
  5. package/dist/generators.js +0 -4
  6. package/dist/src/executors/application/schema.json +1 -2
  7. package/dist/src/executors/ng-packagr-lite/ng-packagr-adjustments/ng-package/entry-point/write-bundles.transform.js +9 -1
  8. package/dist/src/executors/unit-test/schema.json +6 -1
  9. package/dist/src/executors/unit-test/unit-test.impl.js +5 -0
  10. package/dist/src/executors/utilities/ng-packagr/stylesheet-processor.js +35 -10
  11. package/dist/src/generators/add-linting/add-linting.js +0 -2
  12. package/dist/src/generators/add-linting/schema.d.ts +0 -1
  13. package/dist/src/generators/application/application.js +1 -2
  14. package/dist/src/generators/application/lib/add-e2e.js +0 -6
  15. package/dist/src/generators/application/lib/add-linting.js +0 -1
  16. package/dist/src/generators/application/lib/add-unit-test-runner.js +0 -2
  17. package/dist/src/generators/application/lib/normalize-options.d.ts +1 -1
  18. package/dist/src/generators/application/lib/normalize-options.js +1 -8
  19. package/dist/src/generators/application/schema.d.ts +0 -1
  20. package/dist/src/generators/application/schema.json +1 -1
  21. package/dist/src/generators/convert-to-rspack/convert-to-rspack.js +3 -4
  22. package/dist/src/generators/convert-to-rspack/lib/get-custom-webpack-config.d.ts +1 -2
  23. package/dist/src/generators/convert-to-rspack/lib/get-custom-webpack-config.js +0 -63
  24. package/dist/src/generators/convert-to-rspack/lib/validate-no-module-federation.d.ts +2 -0
  25. package/dist/src/generators/convert-to-rspack/lib/validate-no-module-federation.js +32 -0
  26. package/dist/src/generators/cypress-component-configuration/cypress-component-configuration.js +3 -15
  27. package/dist/src/generators/init/init.js +1 -2
  28. package/dist/src/generators/init/schema.d.ts +0 -2
  29. package/dist/src/generators/library/schema.d.ts +0 -1
  30. package/dist/src/generators/ng-add/migrators/builders/angular-eslint-lint.migrator.js +12 -1
  31. package/dist/src/generators/ng-add/migrators/projects/e2e.migrator.js +12 -16
  32. package/dist/src/generators/ng-add/utilities/workspace.js +1 -3
  33. package/dist/src/generators/storybook-configuration/lib/generate-storybook-configuration.js +0 -2
  34. package/dist/src/generators/utils/add-jest.d.ts +0 -1
  35. package/dist/src/generators/utils/add-jest.js +0 -2
  36. package/dist/src/generators/utils/add-vitest.d.ts +0 -1
  37. package/dist/src/generators/utils/add-vitest.js +0 -1
  38. package/dist/src/generators/utils/testing.d.ts +0 -4
  39. package/dist/src/generators/utils/testing.js +0 -12
  40. package/dist/src/migrations/update-23-1-0/add-angular-build.js +7 -3
  41. package/dist/src/migrations/update-23-1-0/add-angular-build.md +1 -1
  42. package/dist/src/migrations/update-23-1-0/add-trust-proxy-headers.js +9 -2
  43. package/dist/src/migrations/update-24-0-0/upgrade-to-angular-22-2.d.ts +5 -0
  44. package/dist/src/migrations/update-24-0-0/upgrade-to-angular-22-2.js +332 -0
  45. package/dist/src/migrations/update-24-0-0/upgrade-to-angular-22-2.md +46 -0
  46. package/dist/src/utils/assert-cypress-component-testing-support.js +10 -0
  47. package/dist/src/utils/backward-compatible-versions.js +0 -8
  48. package/dist/src/utils/versions.d.ts +4 -8
  49. package/dist/src/utils/versions.js +5 -9
  50. package/dist/types/nx-angular.d.ts +1 -3
  51. package/executors.json +0 -10
  52. package/generators.json +0 -35
  53. package/migrations.json +97 -0
  54. package/package.json +11 -20
  55. package/dist/.npmignore +0 -2
  56. package/dist/fesm2022/nx-angular-mf.mjs +0 -193
  57. package/dist/fesm2022/nx-angular-mf.mjs.map +0 -1
  58. package/dist/fesm2022/nx-angular.mjs.map +0 -1
  59. package/dist/mf/package.json +0 -4
  60. package/dist/src/builders/utilities/module-federation.d.ts +0 -11
  61. package/dist/src/builders/utilities/module-federation.js +0 -109
  62. package/dist/src/executors/module-federation-dev-server/lib/index.d.ts +0 -2
  63. package/dist/src/executors/module-federation-dev-server/lib/index.js +0 -5
  64. package/dist/src/executors/module-federation-dev-server/lib/normalize-options.d.ts +0 -2
  65. package/dist/src/executors/module-federation-dev-server/lib/normalize-options.js +0 -22
  66. package/dist/src/executors/module-federation-dev-server/lib/start-dev-remotes.d.ts +0 -5
  67. package/dist/src/executors/module-federation-dev-server/lib/start-dev-remotes.js +0 -29
  68. package/dist/src/executors/module-federation-dev-server/module-federation-dev-server.impl.d.ts +0 -4
  69. package/dist/src/executors/module-federation-dev-server/module-federation-dev-server.impl.js +0 -111
  70. package/dist/src/executors/module-federation-dev-server/schema.d.ts +0 -38
  71. package/dist/src/executors/module-federation-dev-server/schema.json +0 -171
  72. package/dist/src/executors/module-federation-ssr-dev-server/lib/normalize-options.d.ts +0 -2
  73. package/dist/src/executors/module-federation-ssr-dev-server/lib/normalize-options.js +0 -20
  74. package/dist/src/executors/module-federation-ssr-dev-server/lib/start-dev-remotes.d.ts +0 -5
  75. package/dist/src/executors/module-federation-ssr-dev-server/lib/start-dev-remotes.js +0 -30
  76. package/dist/src/executors/module-federation-ssr-dev-server/module-federation-ssr-dev-server.impl.d.ts +0 -4
  77. package/dist/src/executors/module-federation-ssr-dev-server/module-federation-ssr-dev-server.impl.js +0 -110
  78. package/dist/src/executors/module-federation-ssr-dev-server/schema.d.ts +0 -17
  79. package/dist/src/executors/module-federation-ssr-dev-server/schema.json +0 -124
  80. package/dist/src/generators/convert-to-with-mf/convert-to-with-mf.d.ts +0 -4
  81. package/dist/src/generators/convert-to-with-mf/convert-to-with-mf.js +0 -36
  82. package/dist/src/generators/convert-to-with-mf/convert-to-with-mf.test-data.d.ts +0 -5
  83. package/dist/src/generators/convert-to-with-mf/convert-to-with-mf.test-data.js +0 -448
  84. package/dist/src/generators/convert-to-with-mf/lib/check-name-matches.d.ts +0 -2
  85. package/dist/src/generators/convert-to-with-mf/lib/check-name-matches.js +0 -22
  86. package/dist/src/generators/convert-to-with-mf/lib/check-shared-npm-packages.d.ts +0 -2
  87. package/dist/src/generators/convert-to-with-mf/lib/check-shared-npm-packages.js +0 -45
  88. package/dist/src/generators/convert-to-with-mf/lib/get-webpack-config-path.d.ts +0 -2
  89. package/dist/src/generators/convert-to-with-mf/lib/get-webpack-config-path.js +0 -18
  90. package/dist/src/generators/convert-to-with-mf/lib/index.d.ts +0 -6
  91. package/dist/src/generators/convert-to-with-mf/lib/index.js +0 -9
  92. package/dist/src/generators/convert-to-with-mf/lib/is-host-remote-config.d.ts +0 -5
  93. package/dist/src/generators/convert-to-with-mf/lib/is-host-remote-config.js +0 -57
  94. package/dist/src/generators/convert-to-with-mf/lib/parse-ast-webpack-config.d.ts +0 -2
  95. package/dist/src/generators/convert-to-with-mf/lib/parse-ast-webpack-config.js +0 -13
  96. package/dist/src/generators/convert-to-with-mf/lib/write-new-webpack-config.d.ts +0 -3
  97. package/dist/src/generators/convert-to-with-mf/lib/write-new-webpack-config.js +0 -50
  98. package/dist/src/generators/convert-to-with-mf/schema.d.ts +0 -4
  99. package/dist/src/generators/convert-to-with-mf/schema.json +0 -33
  100. package/dist/src/generators/federate-module/federate-module.d.ts +0 -4
  101. package/dist/src/generators/federate-module/federate-module.js +0 -49
  102. package/dist/src/generators/federate-module/lib/add-file-to-remote-tsconfig.d.ts +0 -2
  103. package/dist/src/generators/federate-module/lib/add-file-to-remote-tsconfig.js +0 -14
  104. package/dist/src/generators/federate-module/lib/add-path-to-exposes.d.ts +0 -8
  105. package/dist/src/generators/federate-module/lib/add-path-to-exposes.js +0 -77
  106. package/dist/src/generators/federate-module/lib/add-path-to-ts-config.d.ts +0 -8
  107. package/dist/src/generators/federate-module/lib/add-path-to-ts-config.js +0 -11
  108. package/dist/src/generators/federate-module/lib/add-remote.d.ts +0 -7
  109. package/dist/src/generators/federate-module/lib/add-remote.js +0 -42
  110. package/dist/src/generators/federate-module/lib/check-remote-exists.d.ts +0 -2
  111. package/dist/src/generators/federate-module/lib/check-remote-exists.js +0 -21
  112. package/dist/src/generators/federate-module/lib/index.d.ts +0 -4
  113. package/dist/src/generators/federate-module/lib/index.js +0 -7
  114. package/dist/src/generators/federate-module/schema.d.ts +0 -13
  115. package/dist/src/generators/federate-module/schema.json +0 -83
  116. package/dist/src/generators/host/files/common/src/main.server.ts__tmpl__ +0 -78
  117. package/dist/src/generators/host/files/js/webpack.server.config.js__tmpl__ +0 -8
  118. package/dist/src/generators/host/files/ts/webpack.server.config.ts__tmpl__ +0 -9
  119. package/dist/src/generators/host/host.d.ts +0 -4
  120. package/dist/src/generators/host/host.js +0 -133
  121. package/dist/src/generators/host/lib/index.d.ts +0 -2
  122. package/dist/src/generators/host/lib/index.js +0 -5
  123. package/dist/src/generators/host/lib/update-ssr-setup.d.ts +0 -3
  124. package/dist/src/generators/host/lib/update-ssr-setup.js +0 -54
  125. package/dist/src/generators/host/lib/validate-options.d.ts +0 -3
  126. package/dist/src/generators/host/lib/validate-options.js +0 -12
  127. package/dist/src/generators/host/schema.d.ts +0 -36
  128. package/dist/src/generators/host/schema.json +0 -195
  129. package/dist/src/generators/remote/files/base/webpack.server.config.js__tmpl__ +0 -9
  130. package/dist/src/generators/remote/files/base-ts/webpack.server.config.ts__tmpl__ +0 -9
  131. package/dist/src/generators/remote/files/common/src/main.server.ts__tmpl__ +0 -84
  132. package/dist/src/generators/remote/files/standalone/src/bootstrap.server.ts__tmpl__ +0 -12
  133. package/dist/src/generators/remote/lib/find-next-available-port.d.ts +0 -2
  134. package/dist/src/generators/remote/lib/find-next-available-port.js +0 -16
  135. package/dist/src/generators/remote/lib/index.d.ts +0 -3
  136. package/dist/src/generators/remote/lib/index.js +0 -6
  137. package/dist/src/generators/remote/lib/update-ssr-setup.d.ts +0 -9
  138. package/dist/src/generators/remote/lib/update-ssr-setup.js +0 -82
  139. package/dist/src/generators/remote/lib/validate-options.d.ts +0 -3
  140. package/dist/src/generators/remote/lib/validate-options.js +0 -12
  141. package/dist/src/generators/remote/remote.d.ts +0 -4
  142. package/dist/src/generators/remote/remote.js +0 -114
  143. package/dist/src/generators/remote/schema.d.ts +0 -34
  144. package/dist/src/generators/remote/schema.json +0 -184
  145. package/dist/src/generators/setup-mf/files/entry-module-files/__entryModuleFileName__.ts__tmpl__ +0 -18
  146. package/dist/src/generators/setup-mf/files/entry-module-files/entry.routes.ts__tmpl__ +0 -4
  147. package/dist/src/generators/setup-mf/files/entry-module-files/entry__componentFileSuffix__.ts__tmpl__ +0 -10
  148. package/dist/src/generators/setup-mf/files/host-files/__appFileName__.spec.ts__tmpl__ +0 -42
  149. package/dist/src/generators/setup-mf/files/standalone-entry-component-files/entry.routes.ts__tmpl__ +0 -4
  150. package/dist/src/generators/setup-mf/files/standalone-entry-component-files/entry__componentFileSuffix__.ts__tmpl__ +0 -11
  151. package/dist/src/generators/setup-mf/files/ts-webpack/module-federation.config.ts__tmpl__ +0 -27
  152. package/dist/src/generators/setup-mf/files/ts-webpack/tsconfig.lint.json__tmpl__ +0 -12
  153. package/dist/src/generators/setup-mf/files/ts-webpack/webpack.config.ts__tmpl__ +0 -9
  154. package/dist/src/generators/setup-mf/files/ts-webpack/webpack.prod.config.ts__tmpl__ +0 -21
  155. package/dist/src/generators/setup-mf/files/webpack/module-federation.config.js__tmpl__ +0 -23
  156. package/dist/src/generators/setup-mf/files/webpack/webpack.config.js__tmpl__ +0 -9
  157. package/dist/src/generators/setup-mf/files/webpack/webpack.prod.config.js__tmpl__ +0 -21
  158. package/dist/src/generators/setup-mf/lib/add-cypress-workaround.d.ts +0 -3
  159. package/dist/src/generators/setup-mf/lib/add-cypress-workaround.js +0 -52
  160. package/dist/src/generators/setup-mf/lib/add-remote-entry.d.ts +0 -3
  161. package/dist/src/generators/setup-mf/lib/add-remote-entry.js +0 -27
  162. package/dist/src/generators/setup-mf/lib/add-remote-to-host.d.ts +0 -9
  163. package/dist/src/generators/setup-mf/lib/add-remote-to-host.js +0 -127
  164. package/dist/src/generators/setup-mf/lib/change-build-target.d.ts +0 -3
  165. package/dist/src/generators/setup-mf/lib/change-build-target.js +0 -24
  166. package/dist/src/generators/setup-mf/lib/fix-bootstrap.d.ts +0 -3
  167. package/dist/src/generators/setup-mf/lib/fix-bootstrap.js +0 -40
  168. package/dist/src/generators/setup-mf/lib/generate-config.d.ts +0 -6
  169. package/dist/src/generators/setup-mf/lib/generate-config.js +0 -32
  170. package/dist/src/generators/setup-mf/lib/get-remotes-with-ports.d.ts +0 -6
  171. package/dist/src/generators/setup-mf/lib/get-remotes-with-ports.js +0 -20
  172. package/dist/src/generators/setup-mf/lib/index.d.ts +0 -15
  173. package/dist/src/generators/setup-mf/lib/index.js +0 -18
  174. package/dist/src/generators/setup-mf/lib/move-angular-plugin-to-dependencies.d.ts +0 -2
  175. package/dist/src/generators/setup-mf/lib/move-angular-plugin-to-dependencies.js +0 -15
  176. package/dist/src/generators/setup-mf/lib/normalize-options.d.ts +0 -3
  177. package/dist/src/generators/setup-mf/lib/normalize-options.js +0 -26
  178. package/dist/src/generators/setup-mf/lib/remove-dead-code-from-remote.d.ts +0 -3
  179. package/dist/src/generators/setup-mf/lib/remove-dead-code-from-remote.js +0 -61
  180. package/dist/src/generators/setup-mf/lib/setup-host-if-dynamic.d.ts +0 -3
  181. package/dist/src/generators/setup-mf/lib/setup-host-if-dynamic.js +0 -20
  182. package/dist/src/generators/setup-mf/lib/setup-serve-target.d.ts +0 -3
  183. package/dist/src/generators/setup-mf/lib/setup-serve-target.js +0 -39
  184. package/dist/src/generators/setup-mf/lib/setup-tspath-for-remote.d.ts +0 -3
  185. package/dist/src/generators/setup-mf/lib/setup-tspath-for-remote.js +0 -15
  186. package/dist/src/generators/setup-mf/lib/update-host-app-routes.d.ts +0 -3
  187. package/dist/src/generators/setup-mf/lib/update-host-app-routes.js +0 -39
  188. package/dist/src/generators/setup-mf/lib/update-tsconfig.d.ts +0 -3
  189. package/dist/src/generators/setup-mf/lib/update-tsconfig.js +0 -18
  190. package/dist/src/generators/setup-mf/schema.d.ts +0 -35
  191. package/dist/src/generators/setup-mf/schema.json +0 -99
  192. package/dist/src/generators/setup-mf/setup-mf.d.ts +0 -4
  193. package/dist/src/generators/setup-mf/setup-mf.js +0 -90
  194. package/dist/src/generators/utils/add-mf-env-to-inputs.d.ts +0 -2
  195. package/dist/src/generators/utils/add-mf-env-to-inputs.js +0 -36
  196. package/dist/src/generators/utils/assert-mf-utils.d.ts +0 -1
  197. package/dist/src/generators/utils/assert-mf-utils.js +0 -8
  198. package/dist/src/utils/get-mf-projects.d.ts +0 -4
  199. package/dist/src/utils/get-mf-projects.js +0 -31
  200. package/dist/src/utils/module-federation-deprecation.d.ts +0 -4
  201. package/dist/src/utils/module-federation-deprecation.js +0 -29
  202. package/dist/types/nx-angular-mf.d.ts +0 -72
  203. package/dist/types/nx-angular-mf.d.ts.map +0 -1
  204. package/dist/types/nx-angular.d.ts.map +0 -1
@@ -33,7 +33,6 @@ class AngularEslintLintMigrator extends builder_migrator_1.BuilderMigrator {
33
33
  }
34
34
  }
35
35
  async updateTargetConfiguration(targetName, target) {
36
- target.executor = '@nx/eslint:lint';
37
36
  if (!target.options) {
38
37
  this.logger.warn(`The target "${targetName}" is not specifying any options. Skipping updating the target configuration.`);
39
38
  return;
@@ -60,6 +59,18 @@ class AngularEslintLintMigrator extends builder_migrator_1.BuilderMigrator {
60
59
  this.logger.warn(`The lint file pattern "${pattern}" specified in the "${targetName}" target is not contained in the project root or source root. The pattern will not be updated.`);
61
60
  return pattern;
62
61
  });
62
+ // `@nx/eslint:lint` is gone in v24, so the migrated target runs the ESLint
63
+ // CLI directly. Patterns were rebased onto the new project root above.
64
+ const eslintConfig = target.options.eslintConfig && this.newEsLintConfigPath;
65
+ const patterns = target.options.lintFilePatterns ?? [];
66
+ delete target.executor;
67
+ delete target.options;
68
+ target.command = [
69
+ 'eslint',
70
+ ...(eslintConfig ? ['--config', eslintConfig] : []),
71
+ // Quoted so ESLint, not the shell, expands the globs: sh has no globstar.
72
+ ...patterns.map((pattern) => `"${pattern}"`),
73
+ ].join(' ');
63
74
  (0, devkit_1.updateProjectConfiguration)(this.tree, this.project.name, {
64
75
  ...this.projectConfig,
65
76
  });
@@ -223,9 +223,6 @@ class E2eMigrator extends project_migrator_1.ProjectMigrator {
223
223
  tags: [],
224
224
  implicitDependencies: [this.appName],
225
225
  });
226
- const nxJson = (0, devkit_1.readNxJson)(this.tree) ?? {};
227
- const addPlugin = process.env.NX_ADD_PLUGINS !== 'false' &&
228
- nxJson.useInferencePlugins !== false;
229
226
  const { configurationGenerator } = (require('@nx/cypress'));
230
227
  await configurationGenerator(this.tree, {
231
228
  project: this.project.name,
@@ -234,7 +231,6 @@ class E2eMigrator extends project_migrator_1.ProjectMigrator {
234
231
  // any target would do, we replace it later with the target existing in the project being migrated
235
232
  devServerTarget: `${this.appName}:serve`,
236
233
  baseUrl: 'http://localhost:4200',
237
- addPlugin,
238
234
  });
239
235
  const cypressConfigFilePath = this.updateOrCreateCypressConfigFile(oldCypressConfigFilePath);
240
236
  this.updateCypressProjectConfiguration(cypressConfigFilePath);
@@ -284,21 +280,21 @@ class E2eMigrator extends project_migrator_1.ProjectMigrator {
284
280
  });
285
281
  }
286
282
  updateE2eCypressTarget(existingTarget, cypressConfig) {
283
+ // `@nx/cypress:cypress` is gone in v24, so the migrated target runs the
284
+ // Cypress CLI directly against the rebased config. `watch` selected the
285
+ // interactive runner, which is `cypress open`.
286
+ const isInteractive = existingTarget.options?.watch === true;
287
+ if (existingTarget.options?.devServerTarget) {
288
+ this.logger.warn(`The "devServerTarget" option is not supported by the Cypress CLI. Start "${existingTarget.options.devServerTarget}" separately, or set "baseUrl" in "${cypressConfig}".`);
289
+ }
287
290
  const updatedTarget = {
288
291
  ...existingTarget,
289
- executor: '@nx/cypress:cypress',
290
- options: {
291
- ...existingTarget.options,
292
- cypressConfig,
293
- },
292
+ command: `cypress ${isInteractive ? 'open' : 'run'} --e2e --config-file ${(0, path_1.basename)(cypressConfig)}`,
293
+ options: { cwd: (0, path_1.dirname)(cypressConfig) },
294
294
  };
295
- delete updatedTarget.options.configFile;
296
- if (updatedTarget.options.tsConfig) {
297
- updatedTarget.options.tsConfig = (0, devkit_1.joinPathFragments)(this.project.newRoot, 'tsconfig.json');
298
- }
299
- else {
300
- delete updatedTarget.options.tsConfig;
301
- }
295
+ delete updatedTarget.executor;
296
+ delete updatedTarget.configurations;
297
+ delete updatedTarget.defaultConfiguration;
302
298
  return updatedTarget;
303
299
  }
304
300
  cypressConfigGlobToNewGlob(globPattern) {
@@ -156,9 +156,7 @@ function updatePackageJson(tree) {
156
156
  });
157
157
  }
158
158
  async function updateRootEsLintConfig(tree, existingEsLintConfig, unitTestRunner) {
159
- await (0, eslint_1.lintInitGenerator)(tree, {
160
- addPlugin: false,
161
- });
159
+ await (0, eslint_1.lintInitGenerator)(tree, {});
162
160
  if (!existingEsLintConfig) {
163
161
  // There was no eslint config in the root, so we set it up and use it as-is
164
162
  (0, internal_1.setupRootEsLint)(tree, { unitTestRunner });
@@ -13,7 +13,5 @@ async function generateStorybookConfiguration(tree, options) {
13
13
  interactionTests: options.interactionTests,
14
14
  configureStaticServe: options.configureStaticServe,
15
15
  skipFormat: true,
16
- addPlugin: false,
17
- addExplicitTargets: true,
18
16
  });
19
17
  }
@@ -6,6 +6,5 @@ export type AddJestOptions = {
6
6
  strict: boolean;
7
7
  runtimeTsconfigFileName: 'tsconfig.app.json' | 'tsconfig.lib.json';
8
8
  zoneless: boolean;
9
- addPlugin?: boolean;
10
9
  };
11
10
  export declare function addJest(tree: Tree, options: AddJestOptions): Promise<void>;
@@ -28,8 +28,6 @@ async function addJest(tree, options) {
28
28
  skipSerializers: false,
29
29
  skipPackageJson: options.skipPackageJson,
30
30
  skipFormat: true,
31
- addPlugin: options.addPlugin ?? false,
32
- addExplicitTargets: !options.addPlugin,
33
31
  });
34
32
  const setupFile = (0, devkit_1.joinPathFragments)(options.projectRoot, 'src', 'test-setup.ts');
35
33
  if (options.zoneless) {
@@ -12,7 +12,6 @@ export type AddVitestAnalogOptions = {
12
12
  skipPackageJson: boolean;
13
13
  strict: boolean;
14
14
  zoneless: boolean;
15
- addPlugin?: boolean;
16
15
  };
17
16
  export declare function addVitestAngular(tree: Tree, options: AddVitestAngularOptions): Promise<GeneratorCallback>;
18
17
  export declare function addVitestAnalog(tree: Tree, options: AddVitestAnalogOptions): Promise<GeneratorCallback>;
@@ -81,7 +81,6 @@ async function addVitestAnalog(tree, options) {
81
81
  uiFramework: 'angular',
82
82
  testEnvironment: 'jsdom',
83
83
  coverageProvider: 'v8',
84
- addPlugin: options.addPlugin ?? false,
85
84
  skipFormat: options.skipFormat,
86
85
  skipPackageJson: options.skipPackageJson,
87
86
  zoneless: options.zoneless,
@@ -1,10 +1,6 @@
1
1
  import type { Tree } from '@nx/devkit';
2
2
  import type { Schema as ApplicationOptions } from '../application/schema';
3
- import type { Schema as HostOptions } from '../host/schema';
4
3
  import type { Schema as LibraryOptions } from '../library/schema';
5
- import type { Schema as RemoteOptions } from '../remote/schema';
6
4
  export declare function generateTestApplication(tree: Tree, options: ApplicationOptions): Promise<void>;
7
- export declare function generateTestHostApplication(tree: Tree, options: HostOptions): Promise<void>;
8
- export declare function generateTestRemoteApplication(tree: Tree, options: RemoteOptions): Promise<void>;
9
5
  export declare function generateTestLibrary(tree: Tree, options: LibraryOptions): Promise<void>;
10
6
  export declare function createStorybookTestWorkspaceForLib(libName: string): Promise<Tree>;
@@ -1,8 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.generateTestApplication = generateTestApplication;
4
- exports.generateTestHostApplication = generateTestHostApplication;
5
- exports.generateTestRemoteApplication = generateTestRemoteApplication;
6
4
  exports.generateTestLibrary = generateTestLibrary;
7
5
  exports.createStorybookTestWorkspaceForLib = createStorybookTestWorkspaceForLib;
8
6
  const devkit_1 = require("@nx/devkit");
@@ -11,23 +9,13 @@ const internal_1 = require("@nx/js/internal");
11
9
  const test_runners_1 = require("../../utils/test-runners");
12
10
  const application_1 = require("../application/application");
13
11
  const component_1 = require("../component/component");
14
- const host_1 = require("../host/host");
15
12
  const library_1 = require("../library/library");
16
- const remote_1 = require("../remote/remote");
17
13
  async function generateTestApplication(tree, options) {
18
14
  tree.write('.gitignore', '');
19
15
  await (0, application_1.applicationGenerator)(tree, {
20
16
  ...options,
21
17
  });
22
18
  }
23
- async function generateTestHostApplication(tree, options) {
24
- tree.write('.gitignore', '');
25
- await (0, host_1.host)(tree, { ...options });
26
- }
27
- async function generateTestRemoteApplication(tree, options) {
28
- tree.write('.gitignore', '');
29
- await (0, remote_1.remote)(tree, { ...options });
30
- }
31
19
  async function generateTestLibrary(tree, options) {
32
20
  tree.write('.gitignore', '');
33
21
  await (0, library_1.libraryGenerator)(tree, {
@@ -2,8 +2,9 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.default = default_1;
4
4
  const devkit_1 = require("@nx/devkit");
5
+ const internal_1 = require("@nx/devkit/internal");
5
6
  const acknowledge_build_scripts_1 = require("../../generators/utils/acknowledge-build-scripts");
6
- const versions_1 = require("../../utils/versions");
7
+ const version_utils_1 = require("../../generators/utils/version-utils");
7
8
  // The `@nx/angular:application` and `@nx/angular:unit-test` executors import
8
9
  // `@angular/build` directly to run the Angular builders, and any
9
10
  // `@angular/build:*` executor is provided by that package; it is a required
@@ -12,7 +13,8 @@ const versions_1 = require("../../utils/versions");
12
13
  // `@angular-devkit/build-angular`, which isn't reliable (it can be absent from
13
14
  // node_modules, e.g. under Yarn Berry), so `require.resolve('@angular/build')`
14
15
  // fails and the build breaks. Add it as a direct dependency when an executor
15
- // needs it, at the version the application generator installs.
16
+ // needs it. Match the version `@angular-devkit/build-angular` pins it to,
17
+ // because a newer `@angular/build` breaks peers such as `@angular/ssr`.
16
18
  const angularBuildExecutors = [
17
19
  '@nx/angular:application',
18
20
  '@nx/angular:unit-test',
@@ -51,5 +53,7 @@ async function default_1(tree) {
51
53
  return;
52
54
  }
53
55
  (0, acknowledge_build_scripts_1.acknowledgeAngularBuildScripts)(tree);
54
- return (0, devkit_1.addDependenciesToPackageJson)(tree, {}, { '@angular/build': versions_1.angularDevkitVersion }, undefined, true);
56
+ const version = (0, internal_1.getInstalledPackageVersionFromTree)(tree, '@angular-devkit/build-angular') ??
57
+ (0, version_utils_1.getInstalledAngularVersion)(tree);
58
+ return (0, devkit_1.addDependenciesToPackageJson)(tree, {}, { '@angular/build': `~${version}` }, undefined, true);
55
59
  }
@@ -1,6 +1,6 @@
1
1
  #### Add `@angular/build` When Used by an Executor
2
2
 
3
- The `@nx/angular:application` and `@nx/angular:unit-test` executors load the Angular builders by importing `@angular/build` directly, and any `@angular/build:*` executor is provided by that package, so `@angular/build` is a required runtime dependency for workspaces using those targets. Nothing declares it as a direct dependency, though: it has only ever been available transitively as a dependency of `@angular-devkit/build-angular`. That is not reliable (for example, under Yarn Berry it can be missing from `node_modules` even when `@angular-devkit/build-angular` is installed), and when `@angular/build` cannot be resolved the build fails with an error like `The "@angular/build" package is required by "@nx/angular:application" but is not installed`. This migration adds `@angular/build` to `devDependencies` when a project uses one of those executors and it is not already installed, at the version the application generator installs. An existing version is preserved.
3
+ The `@nx/angular:application` and `@nx/angular:unit-test` executors load the Angular builders by importing `@angular/build` directly, and any `@angular/build:*` executor is provided by that package, so `@angular/build` is a required runtime dependency for workspaces using those targets. Nothing declares it as a direct dependency, though: it has only ever been available transitively as a dependency of `@angular-devkit/build-angular`. That is not reliable (for example, under Yarn Berry it can be missing from `node_modules` even when `@angular-devkit/build-angular` is installed), and when `@angular/build` cannot be resolved the build fails with an error like `The "@angular/build" package is required by "@nx/angular:application" but is not installed`. This migration adds `@angular/build` to `devDependencies` when a project uses one of those executors and it is not already installed. It uses the installed `@angular-devkit/build-angular` version, which pins `@angular/build` to the same version. When `@angular-devkit/build-angular` isn't installed, it uses the `@angular/core` version declared in `package.json`, limited to that minor (`^22.1.0` becomes `~22.1.0`). An existing version is preserved.
4
4
 
5
5
  Executor usage is detected on any target using `@nx/angular:application`, `@nx/angular:unit-test`, or an `@angular/build:*` executor. Targets that inherit their executor from an `nx.json` `targetDefaults` entry are detected too.
6
6
 
@@ -32,14 +32,21 @@ async function default_1(tree) {
32
32
  ts.isIdentifier(node.expression) &&
33
33
  (node.expression.text === 'AngularNodeAppEngine' ||
34
34
  node.expression.text === 'AngularAppEngine')) {
35
- if (!node.arguments || node.arguments.length === 0) {
35
+ if (!node.arguments) {
36
+ // `new AngularAppEngine` without parentheses has no argument list.
37
+ recorder ??= new file_change_recorder_1.FileChangeRecorder(tree, path);
38
+ recorder.insertRight(node.end, `({\n ${TODO_COMMENT}\n ${TRUST_PROXY_HEADERS}\n})`);
39
+ }
40
+ else if (node.arguments.length === 0) {
36
41
  // No options object: insert one before the closing parenthesis.
37
42
  recorder ??= new file_change_recorder_1.FileChangeRecorder(tree, path);
38
43
  recorder.insertRight(node.end - 1, `{\n ${TODO_COMMENT}\n ${TRUST_PROXY_HEADERS}\n}`);
39
44
  }
40
45
  else if (ts.isObjectLiteralExpression(node.arguments[0])) {
41
46
  const optionsArg = node.arguments[0];
42
- const hasTrustProxyHeaders = optionsArg.properties.some((prop) => ts.isPropertyAssignment(prop) &&
47
+ // Any member kind counts (shorthand, method, accessor): adding the
48
+ // property next to one would duplicate the key.
49
+ const hasTrustProxyHeaders = optionsArg.properties.some((prop) => prop.name &&
43
50
  (ts.isIdentifier(prop.name) || ts.isStringLiteral(prop.name)) &&
44
51
  prop.name.text === 'trustProxyHeaders');
45
52
  if (!hasTrustProxyHeaders) {
@@ -0,0 +1,5 @@
1
+ import { type Tree } from '@nx/devkit';
2
+ export default function upgradeToAngular222(tree: Tree): Promise<{
3
+ nextSteps: string[];
4
+ agentContext: string[];
5
+ }>;
@@ -0,0 +1,332 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = upgradeToAngular222;
4
+ const devkit_1 = require("@nx/devkit");
5
+ const internal_1 = require("@nx/devkit/internal");
6
+ const internal_2 = require("@nx/js/internal");
7
+ const path_1 = require("path");
8
+ // Keep these versions pinned; versions.ts advances to later Angular versions.
9
+ const ANGULAR_22_2_VERSIONS = {
10
+ '@angular/core': '~22.2.0',
11
+ '@angular/animations': '~22.2.0',
12
+ '@angular/common': '~22.2.0',
13
+ '@angular/compiler': '~22.2.0',
14
+ '@angular/compiler-cli': '~22.2.0',
15
+ '@angular/elements': '~22.2.0',
16
+ '@angular/forms': '~22.2.0',
17
+ '@angular/language-service': '~22.2.0',
18
+ '@angular/localize': '~22.2.0',
19
+ '@angular/platform-browser': '~22.2.0',
20
+ '@angular/platform-browser-dynamic': '~22.2.0',
21
+ '@angular/platform-server': '~22.2.0',
22
+ '@angular/router': '~22.2.0',
23
+ '@angular/service-worker': '~22.2.0',
24
+ '@angular/upgrade': '~22.2.0',
25
+ '@angular/cli': '~22.2.0',
26
+ '@angular/build': '~22.2.0',
27
+ '@angular/pwa': '~22.2.0',
28
+ '@angular/ssr': '~22.2.0',
29
+ '@angular-devkit/build-angular': '~22.2.0',
30
+ '@angular-devkit/core': '~22.2.0',
31
+ '@angular-devkit/schematics': '~22.2.0',
32
+ '@angular-devkit/architect': '~0.2202.0',
33
+ '@angular-devkit/build-webpack': '~0.2202.0',
34
+ '@schematics/angular': '~22.2.0',
35
+ '@angular/aria': '~22.2.0',
36
+ '@angular/cdk': '~22.2.0',
37
+ '@angular/cdk-experimental': '~22.2.0',
38
+ '@angular/google-maps': '~22.2.0',
39
+ '@angular/material': '~22.2.0',
40
+ '@angular/material-date-fns-adapter': '~22.2.0',
41
+ '@angular/material-experimental': '~22.2.0',
42
+ '@angular/material-luxon-adapter': '~22.2.0',
43
+ '@angular/material-moment-adapter': '~22.2.0',
44
+ 'ng-packagr': '~22.2.0',
45
+ 'zone.js': '~0.16.2',
46
+ };
47
+ const COMPONENT_TESTING_SPECIFIER = /^(@?cypress\/angular|@nx\/angular\/plugins\/component-testing$)/;
48
+ const MODULE_FEDERATION_SPECIFIER = /^(@module-federation\/(enhanced|node)|@nx\/module-federation|@nx\/angular\/(mf|module-federation))(\/|$)/;
49
+ const MARKER_TEXT = /cypress\/angular|module-federation|@nx\/angular\/(mf|plugins\/component-testing)/;
50
+ const NX_WEBPACK_EXECUTORS = new Set([
51
+ '@nx/angular:webpack-browser',
52
+ '@nx/angular:webpack-server',
53
+ '@nx/angular:module-federation-dev-server',
54
+ '@nx/angular:module-federation-dev-ssr',
55
+ ]);
56
+ const WEBPACK_CONFIG_FILE = /^(webpack[\w.-]*|module-federation\.config)\.[cm]?[jt]s$/;
57
+ const RESOLVE_EXTENSIONS = ['.ts', '.js', '.mjs', '.cjs', '.mts', '.cts'];
58
+ const DEPENDENCY_FIELDS = [
59
+ 'dependencies',
60
+ 'devDependencies',
61
+ 'optionalDependencies',
62
+ 'peerDependencies',
63
+ ];
64
+ let ts;
65
+ async function upgradeToAngular222(tree) {
66
+ const scan = scanWorkspace(tree);
67
+ const unresolved = [];
68
+ const moduleFederationConfigs = findModuleFederationConfigs(tree, scan, unresolved);
69
+ const reasons = [];
70
+ if (scan.componentTestingFiles.length > 0) {
71
+ reasons.push(`Cypress component testing (${scan.componentTestingFiles.join(', ')}) fails with the webpack-dev-server 6 that Angular 22.2 installs (https://github.com/cypress-io/cypress/issues/34259)`);
72
+ }
73
+ if (moduleFederationConfigs.length > 0) {
74
+ reasons.push(`Module Federation builds (${moduleFederationConfigs.join(', ')}) fail with the webpack 5.111 that Angular 22.2 installs (https://github.com/module-federation/core/issues/5077)`);
75
+ }
76
+ else if (unresolved.length > 0 && scan.moduleFederationFiles.length > 0) {
77
+ reasons.push(`Module Federation fails with the webpack 5.111 that Angular 22.2 installs (https://github.com/module-federation/core/issues/5077). ${scan.moduleFederationFiles.join(', ')} import it, and the migration could not tell whether an Angular webpack build does: ${unresolved.join('; ')}`);
78
+ }
79
+ if (reasons.length > 0) {
80
+ const nextSteps = [
81
+ `Kept Angular 22.1. ${reasons.join('. ')}. A later Nx migration updates Angular once these issues are fixed. To update before then, move the Angular packages to 22.2 by hand and work around the issues.`,
82
+ ];
83
+ return { nextSteps, agentContext: nextSteps };
84
+ }
85
+ const declared = (0, devkit_1.readJson)(tree, 'package.json');
86
+ const { '@angular/core': core, ...others } = ANGULAR_22_2_VERSIONS;
87
+ // `@angular/core` goes to `dependencies` when the root does not declare it.
88
+ (0, devkit_1.addDependenciesToPackageJson)(tree, { '@angular/core': core }, Object.fromEntries(Object.entries(others).filter(([name]) => declared.dependencies?.[name] || declared.devDependencies?.[name])));
89
+ }
90
+ function scanWorkspace(tree) {
91
+ const scan = {
92
+ angularJsonPaths: [],
93
+ workspacePackages: new Set(),
94
+ declaredDependencies: new Map(),
95
+ componentTestingFiles: [],
96
+ moduleFederationFiles: [],
97
+ };
98
+ // Shared support libraries and config helpers can hold the imports, so the
99
+ // whole workspace is scanned.
100
+ (0, devkit_1.visitNotIgnoredFiles)(tree, '.', (filePath) => {
101
+ const fileName = (0, path_1.basename)(filePath);
102
+ if (fileName === 'angular.json') {
103
+ scan.angularJsonPaths.push(filePath);
104
+ return;
105
+ }
106
+ if (fileName === 'package.json') {
107
+ // Installs fail on a workspace package.json that doesn't parse, so
108
+ // skipping one loses no installed or linked package.
109
+ try {
110
+ const packageJson = (0, devkit_1.readJson)(tree, filePath);
111
+ if (typeof packageJson.name === 'string') {
112
+ scan.workspacePackages.add(packageJson.name);
113
+ }
114
+ scan.declaredDependencies.set((0, path_1.dirname)(filePath), new Set(DEPENDENCY_FIELDS.flatMap((field) => Object.keys(packageJson[field] ?? {}))));
115
+ }
116
+ catch { }
117
+ return;
118
+ }
119
+ if (!/\.[cm]?[jt]sx?$/.test(filePath)) {
120
+ return;
121
+ }
122
+ const content = tree.read(filePath, 'utf-8');
123
+ if (!MARKER_TEXT.test(content)) {
124
+ return;
125
+ }
126
+ const { specifiers } = readModuleSpecifiers(filePath, content);
127
+ if (specifiers.some((s) => COMPONENT_TESTING_SPECIFIER.test(s))) {
128
+ scan.componentTestingFiles.push(filePath);
129
+ }
130
+ if (specifiers.some((s) => MODULE_FEDERATION_SPECIFIER.test(s))) {
131
+ scan.moduleFederationFiles.push(filePath);
132
+ }
133
+ });
134
+ return scan;
135
+ }
136
+ // The webpack config files of Angular webpack targets that import Module
137
+ // Federation, following relative imports. An import or config the migration
138
+ // cannot read is recorded in `unresolved`.
139
+ function findModuleFederationConfigs(tree, scan, unresolved) {
140
+ const configs = new Set();
141
+ const visited = new Set();
142
+ const visit = (fromDir, specifier, importer) => {
143
+ if (MODULE_FEDERATION_SPECIFIER.test(specifier)) {
144
+ configs.add(importer);
145
+ return;
146
+ }
147
+ if (specifier.startsWith('.')) {
148
+ const filePath = resolveFile(tree, (0, devkit_1.joinPathFragments)(fromDir, specifier));
149
+ if (!filePath) {
150
+ unresolved.push(`${importer} loads "${specifier}", which is missing`);
151
+ return;
152
+ }
153
+ if (visited.has(filePath)) {
154
+ return;
155
+ }
156
+ visited.add(filePath);
157
+ const { specifiers, computed } = readModuleSpecifiers(filePath, tree.read(filePath, 'utf-8'));
158
+ if (computed) {
159
+ unresolved.push(`${filePath} has a computed require or import`);
160
+ }
161
+ for (const s of specifiers) {
162
+ visit((0, path_1.dirname)(filePath), s, filePath);
163
+ }
164
+ return;
165
+ }
166
+ if (!(0, internal_1.isBuiltinModuleImport)(specifier) &&
167
+ !isInstalledPackage(tree, fromDir, specifier, scan)) {
168
+ unresolved.push(`${importer} loads "${specifier}", which is not an installed package`);
169
+ }
170
+ };
171
+ const projectRoots = new Set();
172
+ const visitTarget = (executor, target, workspaceRoot, projectRoot, label) => {
173
+ if (!isAngularWebpackExecutor(executor)) {
174
+ return;
175
+ }
176
+ projectRoots.add(projectRoot);
177
+ for (const options of [
178
+ target.options,
179
+ ...Object.values(target.configurations ?? {}),
180
+ ]) {
181
+ for (const specifier of getWebpackConfigSpecifiers(executor, options ?? {}, projectRoot)) {
182
+ visit(workspaceRoot, specifier, label);
183
+ }
184
+ }
185
+ };
186
+ const targetDefaults = (0, devkit_1.readNxJson)(tree)?.targetDefaults;
187
+ for (const [projectName, project] of (0, devkit_1.getProjects)(tree)) {
188
+ for (const [targetName, target] of Object.entries(project.targets ?? {})) {
189
+ const defaults = (0, internal_1.readTargetDefaultsForTarget)(targetName, targetDefaults, target.executor, {
190
+ projectName,
191
+ projectNode: {
192
+ name: projectName,
193
+ type: project.projectType === 'application' ? 'app' : 'lib',
194
+ data: project,
195
+ },
196
+ });
197
+ const merged = defaults
198
+ ? (0, internal_1.mergeTargetConfigurations)(target, defaults)
199
+ : target;
200
+ visitTarget(merged.executor, merged, '.', project.root, `${projectName}:${targetName}`);
201
+ }
202
+ }
203
+ for (const angularJsonPath of scan.angularJsonPaths) {
204
+ let angularJson;
205
+ try {
206
+ angularJson = (0, devkit_1.readJson)(tree, angularJsonPath);
207
+ }
208
+ catch {
209
+ unresolved.push(`${angularJsonPath} could not be parsed`);
210
+ continue;
211
+ }
212
+ const workspaceRoot = (0, path_1.dirname)(angularJsonPath);
213
+ for (const [projectName, project] of Object.entries(angularJson.projects ?? {})) {
214
+ const projectRoot = (0, devkit_1.joinPathFragments)(workspaceRoot, project.root ?? '');
215
+ for (const [targetName, target] of Object.entries(project.architect ?? project.targets ?? {})) {
216
+ visitTarget(target.builder, target, workspaceRoot, projectRoot, `${angularJsonPath} ${projectName}:${targetName}`);
217
+ }
218
+ }
219
+ }
220
+ // Configs a target does not reference directly, such as a remote's
221
+ // module-federation.config, are found by name.
222
+ for (const projectRoot of projectRoots) {
223
+ for (const child of tree.children(projectRoot)) {
224
+ if (WEBPACK_CONFIG_FILE.test(child)) {
225
+ visit(projectRoot, `./${child}`, projectRoot);
226
+ }
227
+ }
228
+ }
229
+ return [...configs];
230
+ }
231
+ function isAngularWebpackExecutor(executor) {
232
+ return (!!executor &&
233
+ (NX_WEBPACK_EXECUTORS.has(executor) ||
234
+ executor.startsWith('@angular-builders/custom-webpack:') ||
235
+ executor.startsWith('ngx-build-plus:')));
236
+ }
237
+ // The webpack config modules a target loads, as specifiers relative to the
238
+ // workspace root.
239
+ function getWebpackConfigSpecifiers(executor, options, projectRoot) {
240
+ const toSpecifier = (path) => `./${path
241
+ .replace(/^\{workspaceRoot\}\/?/, '')
242
+ .replace(/\{projectRoot\}/g, projectRoot)}`;
243
+ const { customWebpackConfig, extraWebpackConfig, plugin } = options;
244
+ const specifiers = [];
245
+ if (typeof customWebpackConfig?.path === 'string') {
246
+ specifiers.push(toSpecifier(customWebpackConfig.path));
247
+ }
248
+ else if (customWebpackConfig &&
249
+ executor.startsWith('@angular-builders/custom-webpack:')) {
250
+ specifiers.push('./webpack.config.js');
251
+ }
252
+ if (typeof extraWebpackConfig === 'string') {
253
+ specifiers.push(toSpecifier(extraWebpackConfig));
254
+ }
255
+ // ngx-build-plus loads a `~` plugin path from the workspace root and
256
+ // anything else as a module.
257
+ if (typeof plugin === 'string' && plugin) {
258
+ specifiers.push(plugin.startsWith('~') ? toSpecifier(plugin.slice(1)) : plugin);
259
+ }
260
+ return specifiers;
261
+ }
262
+ function resolveFile(tree, path) {
263
+ return [
264
+ path,
265
+ ...RESOLVE_EXTENSIONS.map((extension) => `${path}${extension}`),
266
+ ...RESOLVE_EXTENSIONS.map((extension) => (0, devkit_1.joinPathFragments)(path, `index${extension}`)),
267
+ ].find((candidate) => tree.isFile(candidate));
268
+ }
269
+ // A package installed in a node_modules folder the importer resolves from, or
270
+ // declared by the importer's nearest package.json for Yarn PnP installs, which
271
+ // have no node_modules. A workspace package or path alias points back into the
272
+ // workspace, so it is not one.
273
+ function isInstalledPackage(tree, fromDir, specifier, scan) {
274
+ const segments = specifier.split('/');
275
+ const packageName = segments
276
+ .slice(0, specifier.startsWith('@') ? 2 : 1)
277
+ .join('/');
278
+ if (scan.workspacePackages.has(packageName)) {
279
+ return false;
280
+ }
281
+ let nearestPackageJsonChecked = false;
282
+ for (let dir = fromDir;; dir = (0, path_1.dirname)(dir)) {
283
+ if (tree.exists((0, devkit_1.joinPathFragments)(dir, 'node_modules', packageName, 'package.json'))) {
284
+ return true;
285
+ }
286
+ const declared = scan.declaredDependencies.get(dir);
287
+ if (declared && !nearestPackageJsonChecked) {
288
+ nearestPackageJsonChecked = true;
289
+ if (declared.has(packageName)) {
290
+ return true;
291
+ }
292
+ }
293
+ if (dir === '.') {
294
+ return false;
295
+ }
296
+ }
297
+ }
298
+ // Specifiers of `import`/`export ... from`, `import x = require()`,
299
+ // `import()` and `require()`. `computed` is set when an `import()` or
300
+ // `require()` takes a value other than a string literal.
301
+ function readModuleSpecifiers(filePath, content) {
302
+ ts ??= (0, internal_2.ensureTypescript)();
303
+ const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
304
+ const specifiers = [];
305
+ let computed = false;
306
+ const visit = (node) => {
307
+ if ((ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) &&
308
+ node.moduleSpecifier &&
309
+ ts.isStringLiteral(node.moduleSpecifier)) {
310
+ specifiers.push(node.moduleSpecifier.text);
311
+ }
312
+ else if (ts.isExternalModuleReference(node) &&
313
+ ts.isStringLiteral(node.expression)) {
314
+ specifiers.push(node.expression.text);
315
+ }
316
+ else if (ts.isCallExpression(node) &&
317
+ (node.expression.kind === ts.SyntaxKind.ImportKeyword ||
318
+ (ts.isIdentifier(node.expression) &&
319
+ node.expression.text === 'require'))) {
320
+ const [argument] = node.arguments;
321
+ if (argument && ts.isStringLiteralLike(argument)) {
322
+ specifiers.push(argument.text);
323
+ }
324
+ else {
325
+ computed = true;
326
+ }
327
+ }
328
+ ts.forEachChild(node, visit);
329
+ };
330
+ visit(sourceFile);
331
+ return { specifiers, computed };
332
+ }
@@ -0,0 +1,46 @@
1
+ #### Upgrade Angular to 22.2
2
+
3
+ Updates the Angular packages of an Angular 22.1 workspace to 22.2, unless the workspace uses Cypress component testing or webpack Module Federation in an Angular project.
4
+
5
+ Angular 22.2 installs webpack 5.111 and webpack-dev-server 6 through `@angular-devkit/build-angular`. Cypress rejects that webpack-dev-server when it starts Angular component tests ([cypress-io/cypress#34259](https://github.com/cypress-io/cypress/issues/34259)). Module Federation builds fail on that webpack ([module-federation/core#5077](https://github.com/module-federation/core/issues/5077)). The migration keeps the workspace on Angular 22.1 and reports why when it finds either of these:
6
+
7
+ - An import from `cypress/angular`, `@cypress/angular` or one of their variants, or from `@nx/angular/plugins/component-testing`, in any file of the workspace.
8
+ - An import from `@module-federation/enhanced`, `@module-federation/node`, `@nx/module-federation`, `@nx/angular/mf` or `@nx/angular/module-federation` in the webpack config of an Angular project.
9
+
10
+ An Angular project is one with an `@nx/angular` webpack or Module Federation executor, an `@angular-builders/custom-webpack` builder or an `ngx-build-plus` builder. Targets are read from `project.json`, including executors inherited from `targetDefaults`, and from every `angular.json`. The migration reads the webpack configs these targets reference, the `webpack*` and `module-federation.config` files in the project root, and every file they import through a relative path. When a config imports something the migration cannot follow, such as a path alias or a workspace package, a Module Federation import anywhere in the workspace also keeps Angular 22.1.
11
+
12
+ Rspack builds, Native Federation and `@angular-architects/module-federation` don't hold the update. The last one uses the container plugin built into webpack, which works with webpack 5.111.
13
+
14
+ The migration updates only the packages that the root `package.json` declares, and a catalog reference is updated in the catalog. `@angular/core` is added to `dependencies` when the root doesn't declare it. A later Nx migration updates a workspace kept on Angular 22.1 once the upstream issues are fixed.
15
+
16
+ #### Examples
17
+
18
+ ##### Before
19
+
20
+ ```jsonc title="package.json"
21
+ {
22
+ "dependencies": {
23
+ "@angular/common": "~22.1.0",
24
+ "@angular/core": "~22.1.0",
25
+ },
26
+ "devDependencies": {
27
+ "@angular/cli": "~22.1.0",
28
+ "@angular-devkit/build-angular": "~22.1.0",
29
+ },
30
+ }
31
+ ```
32
+
33
+ ##### After
34
+
35
+ ```jsonc title="package.json"
36
+ {
37
+ "dependencies": {
38
+ "@angular/common": "~22.2.0",
39
+ "@angular/core": "~22.2.0",
40
+ },
41
+ "devDependencies": {
42
+ "@angular/cli": "~22.2.0",
43
+ "@angular-devkit/build-angular": "~22.2.0",
44
+ },
45
+ }
46
+ ```