diff --git a/docs/generated/cli/affected.md b/docs/generated/cli/affected.md index 3be4ed2e1554ce..3a3cd1087124ad 100644 --- a/docs/generated/cli/affected.md +++ b/docs/generated/cli/affected.md @@ -103,6 +103,7 @@ Print the task graph to the console: | `--parallel` | string | Max number of parallel processes [default is 3]. | | `--runner` | string | This is the name of the tasks runner configured in nx.json. | | `--skipNxCache` | boolean | Rerun the tasks even when the results are available in the cache. (Default: `false`) | +| `--skipSync` | boolean | Skips running the sync generators associated with the tasks. (Default: `false`) | | `--targets` | string | Tasks to run for affected projects. | | `--uncommitted` | boolean | Uncommitted changes. | | `--untracked` | boolean | Untracked changes. | diff --git a/docs/generated/cli/release.md b/docs/generated/cli/release.md index d51c7ebd97da73..08343d1fb55fe7 100644 --- a/docs/generated/cli/release.md +++ b/docs/generated/cli/release.md @@ -128,6 +128,7 @@ nx release publish | `--registry` | string | The registry to publish to. | | `--runner` | string | This is the name of the tasks runner configured in nx.json. | | `--skipNxCache` | boolean | Rerun the tasks even when the results are available in the cache. (Default: `false`) | +| `--skipSync` | boolean | Skips running the sync generators associated with the tasks. (Default: `false`) | | `--tag` | string | The distribution tag to apply to the published package. | | `--verbose` | boolean | Prints additional information about the commands (e.g., stack traces). | | `--version` | boolean | Show version number. | diff --git a/docs/generated/cli/run-many.md b/docs/generated/cli/run-many.md index ea1499b3d3a964..fe120be4bb1999 100644 --- a/docs/generated/cli/run-many.md +++ b/docs/generated/cli/run-many.md @@ -107,6 +107,7 @@ Print the task graph to the console: | `--projects` | string | Projects to run. (comma/space delimited project names and/or patterns). | | `--runner` | string | This is the name of the tasks runner configured in nx.json. | | `--skipNxCache` | boolean | Rerun the tasks even when the results are available in the cache. (Default: `false`) | +| `--skipSync` | boolean | Skips running the sync generators associated with the tasks. (Default: `false`) | | `--targets` | string | Tasks to run for affected projects. | | `--verbose` | boolean | Prints additional information about the commands (e.g., stack traces). | | `--version` | boolean | Show version number. | diff --git a/docs/generated/cli/run.md b/docs/generated/cli/run.md index bec5c2b7498adf..f5dd9237e1fe2f 100644 --- a/docs/generated/cli/run.md +++ b/docs/generated/cli/run.md @@ -81,5 +81,6 @@ Run's a target named build:test for the myapp project. Note the quotes around th | `--project` | string | Target project. | | `--runner` | string | This is the name of the tasks runner configured in nx.json. | | `--skipNxCache` | boolean | Rerun the tasks even when the results are available in the cache. (Default: `false`) | +| `--skipSync` | boolean | Skips running the sync generators associated with the tasks. (Default: `false`) | | `--verbose` | boolean | Prints additional information about the commands (e.g., stack traces). | | `--version` | boolean | Show version number. | diff --git a/docs/generated/packages/nx/documents/affected.md b/docs/generated/packages/nx/documents/affected.md index 3be4ed2e1554ce..3a3cd1087124ad 100644 --- a/docs/generated/packages/nx/documents/affected.md +++ b/docs/generated/packages/nx/documents/affected.md @@ -103,6 +103,7 @@ Print the task graph to the console: | `--parallel` | string | Max number of parallel processes [default is 3]. | | `--runner` | string | This is the name of the tasks runner configured in nx.json. | | `--skipNxCache` | boolean | Rerun the tasks even when the results are available in the cache. (Default: `false`) | +| `--skipSync` | boolean | Skips running the sync generators associated with the tasks. (Default: `false`) | | `--targets` | string | Tasks to run for affected projects. | | `--uncommitted` | boolean | Uncommitted changes. | | `--untracked` | boolean | Untracked changes. | diff --git a/docs/generated/packages/nx/documents/release.md b/docs/generated/packages/nx/documents/release.md index d51c7ebd97da73..08343d1fb55fe7 100644 --- a/docs/generated/packages/nx/documents/release.md +++ b/docs/generated/packages/nx/documents/release.md @@ -128,6 +128,7 @@ nx release publish | `--registry` | string | The registry to publish to. | | `--runner` | string | This is the name of the tasks runner configured in nx.json. | | `--skipNxCache` | boolean | Rerun the tasks even when the results are available in the cache. (Default: `false`) | +| `--skipSync` | boolean | Skips running the sync generators associated with the tasks. (Default: `false`) | | `--tag` | string | The distribution tag to apply to the published package. | | `--verbose` | boolean | Prints additional information about the commands (e.g., stack traces). | | `--version` | boolean | Show version number. | diff --git a/docs/generated/packages/nx/documents/run-many.md b/docs/generated/packages/nx/documents/run-many.md index ea1499b3d3a964..fe120be4bb1999 100644 --- a/docs/generated/packages/nx/documents/run-many.md +++ b/docs/generated/packages/nx/documents/run-many.md @@ -107,6 +107,7 @@ Print the task graph to the console: | `--projects` | string | Projects to run. (comma/space delimited project names and/or patterns). | | `--runner` | string | This is the name of the tasks runner configured in nx.json. | | `--skipNxCache` | boolean | Rerun the tasks even when the results are available in the cache. (Default: `false`) | +| `--skipSync` | boolean | Skips running the sync generators associated with the tasks. (Default: `false`) | | `--targets` | string | Tasks to run for affected projects. | | `--verbose` | boolean | Prints additional information about the commands (e.g., stack traces). | | `--version` | boolean | Show version number. | diff --git a/docs/generated/packages/nx/documents/run.md b/docs/generated/packages/nx/documents/run.md index bec5c2b7498adf..f5dd9237e1fe2f 100644 --- a/docs/generated/packages/nx/documents/run.md +++ b/docs/generated/packages/nx/documents/run.md @@ -81,5 +81,6 @@ Run's a target named build:test for the myapp project. Note the quotes around th | `--project` | string | Target project. | | `--runner` | string | This is the name of the tasks runner configured in nx.json. | | `--skipNxCache` | boolean | Rerun the tasks even when the results are available in the cache. (Default: `false`) | +| `--skipSync` | boolean | Skips running the sync generators associated with the tasks. (Default: `false`) | | `--verbose` | boolean | Prints additional information about the commands (e.g., stack traces). | | `--version` | boolean | Show version number. | diff --git a/docs/shared/reference/environment-variables.md b/docs/shared/reference/environment-variables.md index 434d1fb38e23e7..a1ddfcf87d4a68 100644 --- a/docs/shared/reference/environment-variables.md +++ b/docs/shared/reference/environment-variables.md @@ -2,37 +2,38 @@ The following environment variables are ones that you can set to change the behavior of Nx in different environments. -| Property | Type | Description | -| --------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| NX_ADD_PLUGINS | boolean | If set to `false`, Nx will not add plugins to infer tasks. This is `true` by default. Workspaces created before Nx 18 will have this disabled via a migration for backwards compatibility | -| NX_BASE | string | The default base branch to use when calculating the affected projects. Can be overridden on the command line with `--base`. | -| NX_CACHE_DIRECTORY | string | The cache for task outputs is stored in `.nx/cache` by default. Set this variable to use a different directory. | -| NX_CACHE_PROJECT_GRAPH | boolean | If set to `false`, disables the project graph cache. Most useful when developing a plugin that modifies the project graph. | -| NX_DAEMON | boolean | If set to `false`, disables the Nx daemon process. Disable the daemon to print `console.log` statements in plugin code you are developing. | -| NX_DEFAULT_PROJECT | string | The default project used for commands which require a project. e.g. `nx build`, `nx g component`, etc. | -| NX_HEAD | string | The default head branch to use when calculating the affected projects. Can be overridden on the command line with `--head`. | -| NX_PERF_LOGGING | boolean | If set to `true`, will print debug information useful for for profiling executors and Nx itself | -| NX_PROFILE | string | Prepend `NX_PROFILE=profile.json` before running targets with Nx to generate a file that be [loaded in Chrome dev tools](/troubleshooting/performance-profiling) to visualize the performance of Nx across multiple processes. | -| NX_WORKSPACE_DATA_CACHE_DIRECTORY | string | The project graph cache and some other internal nx caches are stored in `.nx/workspace-data` by default. Set this variable to use a different directory. | -| NX_PROJECT_GRAPH_MAX_WORKERS | number | The number of workers to use when calculating the project graph. | -| NX_PARALLEL | number | The number of tasks Nx should run in parallel. Overrides any configured value inside nx.json | -| NX_RUNNER | string | The name of task runner from the config to use. Can be overridden on the command line with `--runner`. Not read if `NX_TASKS_RUNNER` is set. | -| NX_SKIP_NX_CACHE | boolean | Rerun the tasks even when the results are available in the cache | -| NX_TASKS_RUNNER | string | The name of task runner from the config to use. Can be overridden on the command line with `--runner`. Preferred over `NX_RUNNER`. | -| NX_TASKS_RUNNER_DYNAMIC_OUTPUT | boolean | If set to `false`, will use non-dynamic terminal output strategy (what you see in CI), even when you terminal can support the dynamic version | -| NX_VERBOSE_LOGGING | boolean | If set to `true`, will print debug information useful for troubleshooting | -| NX_DRY_RUN | boolean | If set to `true`, will perform a dry run of the generator. No files will be created and no packages will be installed. | -| NX_INTERACTIVE | boolean | If set to `true`, will allow Nx to prompt you in the terminal to answer some further questions when running generators. | -| NX_GENERATE_QUIET | boolean | If set to `true`, will prevent Nx logging file operations during generate | -| NX_PREFER_TS_NODE | boolean | If set to `true`, Nx will use `ts-node` for local execution of plugins even if `@swc-node/register` is installed. | -| NX_IGNORE_CYCLES | boolean | If set to `true`, Nx will ignore errors created by a task graph circular dependency. Can be overriden on the command line with `--nxIgnoreCycles` | -| NX_BATCH_MODE | boolean | If set to `true`, Nx will run task(s) in batches for executors which support batches. | -| NX_SKIP_LOG_GROUPING | boolean | If set to `true`, Nx will not group command's logs on CI. | -| NX_MIGRATE_CLI_VERSION | string | The version of Nx to use for running the `nx migrate` command. If not set, it defaults to `latest`. | -| NX_LOAD_DOT_ENV_FILES | boolean | If set to 'false', Nx will not load any environment files (e.g. `.local.env`, `.env.local`) | -| NX_NATIVE_FILE_CACHE_DIRECTORY | string | The cache for native `.node` files is stored under a global temp directory by default. Set this variable to use a different directory. This is interpreted as an absolute path. | -| NX_PLUGIN_NO_TIMEOUTS | boolean | If set to `true`, plugin operations will not timeout | -| NX_SOCKET_DIRECTORY | string | Sets the directory that Nx will use when creating sockets to communicate with child processes. May be needed if the derived socket path is too long. | +| Property | Type | Description | +| --------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| NX_ADD_PLUGINS | boolean | If set to `false`, Nx will not add plugins to infer tasks. This is `true` by default. Workspaces created before Nx 18 will have this disabled via a migration for backwards compatibility | +| NX_ADD_TS_PLUGIN | boolean | If set to `false` when creating a new workspace using the `ts` preset, Nx will not add the `@nx/js/typescript` plugin to infer tasks and will not set up the workspace with [TypeScript project references](https://www.typescriptlang.org/docs/handbook/project-references.html). This is `true` by default. | +| NX_BASE | string | The default base branch to use when calculating the affected projects. Can be overridden on the command line with `--base`. | +| NX_CACHE_DIRECTORY | string | The cache for task outputs is stored in `.nx/cache` by default. Set this variable to use a different directory. | +| NX_CACHE_PROJECT_GRAPH | boolean | If set to `false`, disables the project graph cache. Most useful when developing a plugin that modifies the project graph. | +| NX_DAEMON | boolean | If set to `false`, disables the Nx daemon process. Disable the daemon to print `console.log` statements in plugin code you are developing. | +| NX_DEFAULT_PROJECT | string | The default project used for commands which require a project. e.g. `nx build`, `nx g component`, etc. | +| NX_HEAD | string | The default head branch to use when calculating the affected projects. Can be overridden on the command line with `--head`. | +| NX_PERF_LOGGING | boolean | If set to `true`, will print debug information useful for for profiling executors and Nx itself | +| NX_PROFILE | string | Prepend `NX_PROFILE=profile.json` before running targets with Nx to generate a file that be [loaded in Chrome dev tools](/troubleshooting/performance-profiling) to visualize the performance of Nx across multiple processes. | +| NX_WORKSPACE_DATA_CACHE_DIRECTORY | string | The project graph cache and some other internal nx caches are stored in `.nx/workspace-data` by default. Set this variable to use a different directory. | +| NX_PROJECT_GRAPH_MAX_WORKERS | number | The number of workers to use when calculating the project graph. | +| NX_PARALLEL | number | The number of tasks Nx should run in parallel. Overrides any configured value inside nx.json | +| NX_RUNNER | string | The name of task runner from the config to use. Can be overridden on the command line with `--runner`. Not read if `NX_TASKS_RUNNER` is set. | +| NX_SKIP_NX_CACHE | boolean | Rerun the tasks even when the results are available in the cache | +| NX_TASKS_RUNNER | string | The name of task runner from the config to use. Can be overridden on the command line with `--runner`. Preferred over `NX_RUNNER`. | +| NX_TASKS_RUNNER_DYNAMIC_OUTPUT | boolean | If set to `false`, will use non-dynamic terminal output strategy (what you see in CI), even when you terminal can support the dynamic version | +| NX_VERBOSE_LOGGING | boolean | If set to `true`, will print debug information useful for troubleshooting | +| NX_DRY_RUN | boolean | If set to `true`, will perform a dry run of the generator. No files will be created and no packages will be installed. | +| NX_INTERACTIVE | boolean | If set to `true`, will allow Nx to prompt you in the terminal to answer some further questions when running generators. | +| NX_GENERATE_QUIET | boolean | If set to `true`, will prevent Nx logging file operations during generate | +| NX_PREFER_TS_NODE | boolean | If set to `true`, Nx will use `ts-node` for local execution of plugins even if `@swc-node/register` is installed. | +| NX_IGNORE_CYCLES | boolean | If set to `true`, Nx will ignore errors created by a task graph circular dependency. Can be overriden on the command line with `--nxIgnoreCycles` | +| NX_BATCH_MODE | boolean | If set to `true`, Nx will run task(s) in batches for executors which support batches. | +| NX_SKIP_LOG_GROUPING | boolean | If set to `true`, Nx will not group command's logs on CI. | +| NX_MIGRATE_CLI_VERSION | string | The version of Nx to use for running the `nx migrate` command. If not set, it defaults to `latest`. | +| NX_LOAD_DOT_ENV_FILES | boolean | If set to 'false', Nx will not load any environment files (e.g. `.local.env`, `.env.local`) | +| NX_NATIVE_FILE_CACHE_DIRECTORY | string | The cache for native `.node` files is stored under a global temp directory by default. Set this variable to use a different directory. This is interpreted as an absolute path. | +| NX_PLUGIN_NO_TIMEOUTS | boolean | If set to `true`, plugin operations will not timeout | +| NX_SOCKET_DIRECTORY | string | Sets the directory that Nx will use when creating sockets to communicate with child processes. May be needed if the derived socket path is too long. | Nx will set the following environment variables so they can be accessible within the process even outside of executors and generators. diff --git a/e2e/release/src/circular-dependencies.test.ts b/e2e/release/src/circular-dependencies.test.ts index 7e5556225bd79d..225c81355012ab 100644 --- a/e2e/release/src/circular-dependencies.test.ts +++ b/e2e/release/src/circular-dependencies.test.ts @@ -544,7 +544,6 @@ describe('nx release circular dependencies', () => { + # 2.0.0 (YYYY-MM-DD) + - + + ### 🧱 Updated Dependencies + + - Updated {project-name} to 2.0.0 @@ -556,7 +555,6 @@ describe('nx release circular dependencies', () => { + # 2.0.0 (YYYY-MM-DD) + - + + ### 🧱 Updated Dependencies + + - Updated {project-name} to 2.0.0 @@ -684,7 +682,7 @@ describe('nx release circular dependencies', () => { {project-name} 📄 Using the provided version specifier "major". {project-name} ⚠️ Warning, the following packages depend on "{project-name}" but have been filtered out via --projects, and therefore will not be updated: - {project-name} - => You can adjust this behavior by setting \`version.generatorOptions.updateDependents\` to "auto" + => You can adjust this behavior by removing the usage of \`version.generatorOptions.updateDependents\` with "never" {project-name} ✍️ New version 2.0.0 written to {project-name}/package.json @@ -867,7 +865,6 @@ describe('nx release circular dependencies', () => { + # 2.0.0 (YYYY-MM-DD) + - + + ### 🧱 Updated Dependencies + + - Updated {project-name} to 2.0.0 @@ -879,7 +876,6 @@ describe('nx release circular dependencies', () => { + # 2.0.0 (YYYY-MM-DD) + - + + ### 🧱 Updated Dependencies + + - Updated {project-name} to 2.0.0 @@ -1054,7 +1050,6 @@ describe('nx release circular dependencies', () => { + # 2.0.0 (YYYY-MM-DD) + - + + ### 🧱 Updated Dependencies + + - Updated {project-name} to 1.0.1 @@ -1066,7 +1061,6 @@ describe('nx release circular dependencies', () => { + ## 1.0.1 (YYYY-MM-DD) + - + + ### 🧱 Updated Dependencies + + - Updated {project-name} to 2.0.0 diff --git a/e2e/release/src/conventional-commits-config.test.ts b/e2e/release/src/conventional-commits-config.test.ts index 1f081101bbae27..458b25dcfc327a 100644 --- a/e2e/release/src/conventional-commits-config.test.ts +++ b/e2e/release/src/conventional-commits-config.test.ts @@ -364,12 +364,10 @@ describe('nx release conventional commits config', () => { expect(pkg1Changelog).toMatchInlineSnapshot(` # 1.0.0 (YYYY-MM-DD) - ### Custom Type - ⚠️ **{project-name}:** this is a breaking change - ### ⚠️ Breaking Changes - ⚠️ **{project-name}:** this is a breaking change @@ -379,7 +377,6 @@ describe('nx release conventional commits config', () => { expect(pkg2Changelog).toMatchInlineSnapshot(` # 1.0.0 (YYYY-MM-DD) - ### Custom Type - **{project-name}:** this is a custom type @@ -389,7 +386,6 @@ describe('nx release conventional commits config', () => { expect(pkg3Changelog).toMatchInlineSnapshot(` # 1.0.0 (YYYY-MM-DD) - ### Custom Docs Header - this is a doc @@ -408,7 +404,6 @@ describe('nx release conventional commits config', () => { expect(pkg5Changelog).toMatchInlineSnapshot(` # 1.0.0 (YYYY-MM-DD) - ### 🔥 Performance - this is a performance improvement @@ -418,12 +413,10 @@ describe('nx release conventional commits config', () => { expect(pkg6Changelog).toMatchInlineSnapshot(` # 1.0.0 (YYYY-MM-DD) - ### 💅 Refactors - this is refactor - ### 📦 Build - this is a build diff --git a/e2e/release/src/independent-projects.test.ts b/e2e/release/src/independent-projects.test.ts index 80196a8402de68..f630be84be9e40 100644 --- a/e2e/release/src/independent-projects.test.ts +++ b/e2e/release/src/independent-projects.test.ts @@ -190,9 +190,6 @@ describe('nx release - independent projects', () => { {project-name} 🔍 Reading data for package "@proj/{project-name}" from {project-name}/package.json {project-name} 📄 Resolved the current version as 0.0.0 from {project-name}/package.json {project-name} 📄 Using the provided version specifier "999.9.9-package.3". - {project-name} ⚠️ Warning, the following packages depend on "{project-name}" but have been filtered out via --projects, and therefore will not be updated: - - {project-name} - => You can adjust this behavior by setting \`version.generatorOptions.updateDependents\` to "auto" {project-name} ✍️ New version 999.9.9-package.3 written to {project-name}/package.json @@ -202,6 +199,17 @@ describe('nx release - independent projects', () => { "scripts": { + "name": "@proj/{project-name}", + - "version": "999.9.9-package.2", + + "version": "999.9.9", + "scripts": { + + "dependencies": { + - "@proj/{project-name}": "0.0.0" + + "@proj/{project-name}": "999.9.9-package.3" + } + + NX Staging changed files with git @@ -316,7 +324,7 @@ describe('nx release - independent projects', () => { NX Running release version for project: {project-name} {project-name} 🔍 Reading data for package "@proj/{project-name}" from {project-name}/package.json - {project-name} 📄 Resolved the current version as 999.9.9-package.2 from {project-name}/package.json + {project-name} 📄 Resolved the current version as 999.9.9 from {project-name}/package.json {project-name} 📄 Using the provided version specifier "999.9.9-version-git-operations-test.3". {project-name} ✍️ New version 999.9.9-version-git-operations-test.3 written to {project-name}/package.json @@ -335,7 +343,7 @@ describe('nx release - independent projects', () => { "name": "@proj/{project-name}", - - "version": "999.9.9-package.2", + - "version": "999.9.9", + "version": "999.9.9-version-git-operations-test.3", "scripts": { diff --git a/e2e/release/src/release.test.ts b/e2e/release/src/release.test.ts index 62db28b99b9ff4..80ec1cc7fd1572 100644 --- a/e2e/release/src/release.test.ts +++ b/e2e/release/src/release.test.ts @@ -1,4 +1,4 @@ -import { NxJsonConfiguration } from '@nx/devkit'; +import type { NxJsonConfiguration } from '@nx/devkit'; import { cleanupProject, createFile, @@ -6,7 +6,6 @@ import { killProcessAndPorts, newProject, readFile, - readJson, runCLI, runCommandAsync, runCommandUntil, @@ -92,9 +91,6 @@ describe('nx release', () => { `git remote add origin https://github.com/nrwl/fake-repo.git` ); - const pkg1ContentsBeforeVersioning = readFile(`${pkg1}/package.json`); - const pkg2ContentsBeforeVersioning = readFile(`${pkg2}/package.json`); - const versionOutput = runCLI(`release version 999.9.9`); /** @@ -122,50 +118,6 @@ describe('nx release', () => { ).length ).toEqual(3); - // Only one dependency relationship exists, so this log should only match once - const dependencyRelationshipLogMatch = versionOutput.match( - /Applying new version 999.9.9 to 1 package which depends on my-pkg-\d*/g - ); - if ( - !dependencyRelationshipLogMatch || - dependencyRelationshipLogMatch.length !== 1 - ) { - const projectGraphDependencies = readJson( - '.nx/cache/project-graph.json' - ).dependencies; - const firstPartyProjectGraphDependencies = JSON.stringify( - Object.fromEntries( - Object.entries(projectGraphDependencies).filter( - ([key]) => !key.startsWith('npm:') - ) - ) - ); - - // From JamesHenry: explicit warning to assist troubleshooting NXC-143. - console.warn( - ` -WARNING: Expected to find exactly one dependency relationship log line. - -If you are seeing this message then you have been impacted by some flakiness in the test. - -${JSON.stringify( - { - versionOutput, - pkg1Name: pkg1, - pkg2Name: pkg2, - pkg1ContentsBeforeVersioning, - pkg2ContentsBeforeVersioning, - pkg2ContentsAfterVersioning: readFile(`${pkg2}/package.json`), - firstPartyProjectGraphDependencies, - }, - null, - 2 -)}` - ); - } - // TODO: re-enable this assertion once the flakiness documented in NXC-143 is resolved - // expect(dependencyRelationshipLogMatch.length).toEqual(1); - // Generate a changelog for the new version expect(exists('CHANGELOG.md')).toEqual(false); @@ -177,7 +129,6 @@ ${JSON.stringify( + ## 999.9.9 (YYYY-MM-DD) + - + + ### 🚀 Features + + - an awesome new feature ([{COMMIT_SHA}](https://github.com/nrwl/fake-repo/commit/{COMMIT_SHA})) @@ -198,7 +149,6 @@ ${JSON.stringify( expect(readFile('CHANGELOG.md')).toMatchInlineSnapshot(` ## 999.9.9 (YYYY-MM-DD) - ### 🚀 Features - an awesome new feature ([{COMMIT_SHA}](https://github.com/nrwl/fake-repo/commit/{COMMIT_SHA})) @@ -377,14 +327,6 @@ ${JSON.stringify( ).length ).toEqual(3); - // TODO: Also impacted by NXC-143 - // Only one dependency relationship exists, so this log should only match once - // expect( - // versionOutput2.match( - // /Applying new version 1000.0.0-next.0 to 1 package which depends on my-pkg-\d*/g - // ).length - // ).toEqual(1); - // Perform an initial dry-run of the publish to the custom registry (not e2e registry), and a custom dist tag of "next" const publishToNext = `release publish --registry=${customRegistryUrl} --tag=next`; const publishOutput2 = runCLI(`${publishToNext} --dry-run`); @@ -722,7 +664,7 @@ ${JSON.stringify( + ## 999.9.9 (YYYY-MM-DD) - + ### 🚀 Features NX Previewing an entry in {project-name}/CHANGELOG.md for v1000.0.0-next.0 @@ -847,14 +789,6 @@ ${JSON.stringify( ).length ).toEqual(3); - // TODO: Also impacted by NXC-143 - // Only one dependency relationship exists, so this log should only match once - // expect( - // versionOutput3.match( - // /Applying new version 1100.1.0 to 1 package which depends on my-pkg-\d*/g - // ).length - // ).toEqual(1); - createFile( `${pkg1}/my-file.txt`, 'update for conventional-commits testing' diff --git a/e2e/release/src/version-plans.test.ts b/e2e/release/src/version-plans.test.ts index c94bf7a72df09c..5a533c5da1d839 100644 --- a/e2e/release/src/version-plans.test.ts +++ b/e2e/release/src/version-plans.test.ts @@ -174,12 +174,10 @@ Here is another line in the message. + ## 0.1.0 (YYYY-MM-DD) + -+ + ### 🚀 Features + + - Update the fixed packages with a minor release. + -+ + ### ❤️ Thank You + + - Test` @@ -190,12 +188,10 @@ Here is another line in the message. + ## 0.1.0 (YYYY-MM-DD) + -+ + ### 🚀 Features + + - Update the fixed packages with a minor release. + -+ + ### ❤️ Thank You + + - Test` @@ -206,14 +202,12 @@ Here is another line in the message. + ## 0.0.1 (YYYY-MM-DD) + -+ + ### 🩹 Fixes + + - Update the independent packages with a patch, preminor, and prerelease. + + Here is another line in the message. + -+ + ### ❤️ Thank You + + - Test` @@ -225,14 +219,12 @@ Here is another line in the message. + ## 0.1.0-0 (YYYY-MM-DD) + -+ + ### 🚀 Features + + - Update the independent packages with a patch, preminor, and prerelease. + + Here is another line in the message. + -+ + ### ❤️ Thank You + + - Test` @@ -244,14 +236,12 @@ Here is another line in the message. + ## 0.0.1-0 (YYYY-MM-DD) + -+ + ### 🩹 Fixes + + - Update the independent packages with a patch, preminor, and prerelease. + + Here is another line in the message. + -+ + ### ❤️ Thank You + + - Test` @@ -323,17 +313,14 @@ Update packages in both groups with a mix #2 + ## 0.2.0 (YYYY-MM-DD) + -+ + ### 🚀 Features + + - Update packages in both groups with a mix #1 + -+ + ### 🩹 Fixes + + - Update packages in both groups with a mix #2 + -+ + ### ❤️ Thank You + + - Test` @@ -345,12 +332,10 @@ Update packages in both groups with a mix #2 + ## 0.2.0 (YYYY-MM-DD) + -+ + ### 🩹 Fixes + + - Update packages in both groups with a mix #2 + -+ + ### ❤️ Thank You + + - Test @@ -363,12 +348,10 @@ Update packages in both groups with a mix #2 + ## 0.0.2 (YYYY-MM-DD) + -+ + ### 🩹 Fixes + + - Update packages in both groups with a mix #1 + -+ + ### ❤️ Thank You + + - Test` @@ -381,12 +364,10 @@ Update packages in both groups with a mix #2 + ## 0.2.0-0 (YYYY-MM-DD) + -+ + ### 🚀 Features + + - Update packages in both groups with a mix #2 + -+ + ### ❤️ Thank You + + - Test` @@ -399,12 +380,10 @@ Update packages in both groups with a mix #2 + ## 0.0.1 (YYYY-MM-DD) + -+ + ### 🩹 Fixes + + - Update packages in both groups with a mix #2 + -+ + ### ❤️ Thank You + + - Test` @@ -511,12 +490,16 @@ const yargs = require('yargs'); verbose: options.verbose, }); - // The returned number value from releasePublish will be zero if all projects are published successfully, non-zero if not - const publishStatus = await releasePublish({ + const publishProjectsResult = await releasePublish({ dryRun: options.dryRun, verbose: options.verbose, }); - process.exit(publishStatus); + // Derive an overall exit code from the publish projects result + process.exit( + Object.values(publishProjectsResult).every((result) => result.code === 0) + ? 0 + : 1 + ); })(); ` ); @@ -562,12 +545,10 @@ const yargs = require('yargs'); + ## 0.1.0 (YYYY-MM-DD) + -+ + ### 🚀 Features + + - Update the fixed packages with a minor release. + -+ + ### ❤️ Thank You + + - Test` @@ -578,12 +559,10 @@ const yargs = require('yargs'); + ## 0.1.0 (YYYY-MM-DD) + -+ + ### 🚀 Features + + - Update the fixed packages with a minor release. + -+ + ### ❤️ Thank You + + - Test` @@ -594,12 +573,10 @@ const yargs = require('yargs'); + ## 0.0.1 (YYYY-MM-DD) + -+ + ### 🩹 Fixes + + - Update the independent packages with a patch, preminor, and prerelease. + -+ + ### ❤️ Thank You + + - Test` @@ -611,12 +588,10 @@ const yargs = require('yargs'); + ## 0.1.0-0 (YYYY-MM-DD) + -+ + ### 🚀 Features + + - Update the independent packages with a patch, preminor, and prerelease. + -+ + ### ❤️ Thank You + + - Test` @@ -628,12 +603,10 @@ const yargs = require('yargs'); + ## 0.0.1-0 (YYYY-MM-DD) + -+ + ### 🩹 Fixes + + - Update the independent packages with a patch, preminor, and prerelease. + -+ + ### ❤️ Thank You + + - Test` @@ -708,17 +681,14 @@ Update packages in both groups with a mix #2 + ## 0.2.0 (YYYY-MM-DD) + -+ + ### 🚀 Features + + - Update packages in both groups with a mix #1 + -+ + ### 🩹 Fixes + + - Update packages in both groups with a mix #2 + -+ + ### ❤️ Thank You + + - Test` @@ -730,12 +700,10 @@ Update packages in both groups with a mix #2 + ## 0.2.0 (YYYY-MM-DD) + -+ + ### 🩹 Fixes + + - Update packages in both groups with a mix #2 + -+ + ### ❤️ Thank You + + - Test @@ -748,12 +716,10 @@ Update packages in both groups with a mix #2 + ## 0.0.2 (YYYY-MM-DD) + -+ + ### 🩹 Fixes + + - Update packages in both groups with a mix #1 + -+ + ### ❤️ Thank You + + - Test` @@ -766,12 +732,10 @@ Update packages in both groups with a mix #2 + ## 0.2.0-0 (YYYY-MM-DD) + -+ + ### 🚀 Features + + - Update packages in both groups with a mix #2 + -+ + ### ❤️ Thank You + + - Test` @@ -784,12 +748,10 @@ Update packages in both groups with a mix #2 + ## 0.0.1 (YYYY-MM-DD) + -+ + ### 🩹 Fixes + + - Update packages in both groups with a mix #2 + -+ + ### ❤️ Thank You + + - Test` @@ -850,7 +812,6 @@ Update packages in both groups with a mix #2 + ## 0.1.0 (YYYY-MM-DD) + -+ + ### 🚀 Features + + - Update the fixed packages with a minor release.` @@ -861,7 +822,6 @@ Update packages in both groups with a mix #2 + ## 0.1.0 (YYYY-MM-DD) + -+ + ### 🚀 Features + + - Update the fixed packages with a minor release.` diff --git a/nx-dev/ui-pricing/src/lib/plans/enterprise-plan.tsx b/nx-dev/ui-pricing/src/lib/plans/enterprise-plan.tsx index 01d2cf879343c7..e31aeea193dc1d 100644 --- a/nx-dev/ui-pricing/src/lib/plans/enterprise-plan.tsx +++ b/nx-dev/ui-pricing/src/lib/plans/enterprise-plan.tsx @@ -83,6 +83,24 @@ export function EnterprisePlan({ outputs.

+
  • +
  • ); diff --git a/nx-dev/ui-pricing/src/lib/plans/plan-table.tsx b/nx-dev/ui-pricing/src/lib/plans/plan-table.tsx index 43d6f074d51737..b8268bbe7699bf 100644 --- a/nx-dev/ui-pricing/src/lib/plans/plan-table.tsx +++ b/nx-dev/ui-pricing/src/lib/plans/plan-table.tsx @@ -471,7 +471,7 @@ export function PlanTable(): JSX.Element { Nx Agents - : native task distribution solution for CI{' '} + : native task distribution solution for CI yes + + + + Nx Powerpack + + : a suite of premium extensions for the Nx CLI specifically + designed for enterprises + + + Sold separately + + + Sold separately + + + Included + + =14.1.0" - }, - "description": "Update the @angular/cli package version to ~14.1.0.", - "factory": "./src/migrations/update-14-5-2/update-angular-cli" - }, - "update-angular-cli-version-14-2-0": { - "cli": "nx", - "version": "14.6.0-beta.0", - "requires": { - "@angular/core": ">=14.2.0" - }, - "description": "Update the @angular/cli package version to ~14.2.0.", - "factory": "./src/migrations/update-14-6-0/update-angular-cli" - }, - "rename-webpack-server-executor": { - "cli": "nx", - "version": "15.0.0-beta.0", - "description": "Rename @nrwl/angular:webpack-server executor to @nrwl/angular:webpack-dev-server", - "factory": "./src/migrations/update-14-8-0/rename-webpack-server" - }, - "switch-to-jasmine-marbles": { - "cli": "nx", - "version": "15.0.0-beta.0", - "description": "Update the usages of @nrwl/angular/testing to import jasmine-marbles symbols from jasmine-marbles itself.", - "factory": "./src/migrations/update-15-0-0/switch-to-jasmine-marbles" - }, - "add-karma-inputs": { - "cli": "nx", - "version": "15.0.0-beta.1", - "description": "Stop hashing karma spec files and config files for build targets and dependent tasks", - "factory": "./src/migrations/update-15-0-0/add-karma-inputs" - }, - "update-angular-cli-version-15-0-0": { - "cli": "nx", - "version": "15.2.0-beta.0", - "requires": { - "@angular/core": ">=15.0.0" - }, - "description": "Update the @angular/cli package version to ~15.0.0.", - "factory": "./src/migrations/update-15-2-0/update-angular-cli" - }, - "remove-browserlist-config": { - "cli": "nx", - "version": "15.2.0-beta.0", - "requires": { - "@angular/core": ">=15.0.0" - }, - "description": "Remove browserslist config as it's handled by build-angular", - "factory": "./src/migrations/update-15-2-0/remove-browserlist-config" - }, - "update-typescript-target": { - "cli": "nx", - "version": "15.2.0-beta.0", - "requires": { - "@angular/core": ">=15.0.0" - }, - "description": "Update typescript target to ES2022", - "factory": "./src/migrations/update-15-2-0/update-typescript-target" - }, - "update-workspace-config": { - "cli": "nx", - "version": "15.2.0-beta.0", - "requires": { - "@angular/core": ">=15.0.0" - }, - "description": "Remove bundleDependencies from server targets", - "factory": "./src/migrations/update-15-2-0/update-workspace-config" - }, - "update-platform-server-exports": { - "cli": "nx", - "version": "15.2.0-beta.0", - "requires": { - "@angular/core": ">=15.0.0" - }, - "description": "Remove exported `@angular/platform-server` `renderModule` method. The `renderModule` method is now exported by the Angular CLI.", - "factory": "./src/migrations/update-15-2-0/remove-platform-server-exports" - }, - "update-karma-main-file": { - "cli": "nx", - "version": "15.2.0-beta.0", - "requires": { - "@angular/core": ">=15.0.0" - }, - "description": "Remove no longer needed require calls in Karma builder main file.", - "factory": "./src/migrations/update-15-2-0/update-karma-main-file" - }, - "update-angular-cli-version-15-1-0": { - "cli": "nx", - "version": "15.5.0-beta.0", - "requires": { - "@angular/core": ">=15.1.0" - }, - "description": "Update the @angular/cli package version to ~15.1.0.", - "factory": "./src/migrations/update-15-5-0/update-angular-cli" - }, - "update-angular-cli-version-15-2-0": { - "cli": "nx", - "version": "15.8.0-beta.4", - "requires": { - "@angular/core": ">=15.2.0" - }, - "description": "Update the @angular/cli package version to ~15.2.0.", - "factory": "./src/migrations/update-15-8-0/update-angular-cli" - }, - "update-tsconfig-spec-jest": { - "cli": "nx", - "version": "15.9.0-beta.3", - "description": "Update the tsconfig.spec.json to use target es2016 for jest-preset-angular v13", - "factory": "./src/migrations/update-15-9-0/update-testing-tsconfig" - }, - "update-file-server-executor": { - "cli": "nx", - "version": "15.9.0-beta.9", - "description": "Update the file-server executor to use @nrwl/web:file-server", - "factory": "./src/migrations/update-15-9-0/update-file-server-executor" - }, "remove-library-generator-simple-module-name-option": { "cli": "nx", "version": "16.0.0-beta.1", @@ -437,819 +269,6 @@ } }, "packageJsonUpdates": { - "14.1.8": { - "version": "14.1.8-beta.0", - "packages": { - "postcss-import": { - "version": "~14.1.0", - "alwaysAddToPackageJson": false - }, - "postcss-preset-env": { - "version": "~7.5.0", - "alwaysAddToPackageJson": false - }, - "postcss-url": { - "version": "~10.1.3", - "alwaysAddToPackageJson": false - } - } - }, - "14.2.0": { - "version": "14.2.0-beta.6", - "packages": { - "@angular-devkit/architect": { - "version": "~0.1400.0", - "alwaysAddToPackageJson": false - }, - "@angular-devkit/build-angular": { - "version": "~14.0.0", - "alwaysAddToPackageJson": false - }, - "@angular-devkit/build-webpack": { - "version": "~0.1400.0", - "alwaysAddToPackageJson": false - }, - "@angular-devkit/core": { - "version": "~14.0.0", - "alwaysAddToPackageJson": false - }, - "@angular-devkit/schematics": { - "version": "~14.0.0", - "alwaysAddToPackageJson": false - }, - "@schematics/angular": { - "version": "~14.0.0", - "alwaysAddToPackageJson": false - }, - "@angular/pwa": { - "version": "~14.0.0", - "alwaysAddToPackageJson": false - }, - "@angular/core": { - "version": "~14.0.0", - "alwaysAddToPackageJson": true - }, - "@angular/common": { - "version": "~14.0.0", - "alwaysAddToPackageJson": false - }, - "@angular/forms": { - "version": "~14.0.0", - "alwaysAddToPackageJson": false - }, - "@angular/elements": { - "version": "~14.0.0", - "alwaysAddToPackageJson": false - }, - "@angular/compiler": { - "version": "~14.0.0", - "alwaysAddToPackageJson": false - }, - "@angular/compiler-cli": { - "version": "~14.0.0", - "alwaysAddToPackageJson": false - }, - "@angular/localize": { - "version": "~14.0.0", - "alwaysAddToPackageJson": false - }, - "@angular/platform-browser": { - "version": "~14.0.0", - "alwaysAddToPackageJson": false - }, - "@angular/platform-browser-dynamic": { - "version": "~14.0.0", - "alwaysAddToPackageJson": false - }, - "@angular/platform-server": { - "version": "~14.0.0", - "alwaysAddToPackageJson": false - }, - "@angular/router": { - "version": "~14.0.0", - "alwaysAddToPackageJson": false - }, - "@angular/upgrade": { - "version": "~14.0.0", - "alwaysAddToPackageJson": false - }, - "@angular/language-service": { - "version": "~14.0.0", - "alwaysAddToPackageJson": false - }, - "@angular/animations": { - "version": "~14.0.0", - "alwaysAddToPackageJson": false - }, - "@angular/service-worker": { - "version": "~14.0.0", - "alwaysAddToPackageJson": false - }, - "@angular/material": { - "version": "~14.0.0", - "alwaysAddToPackageJson": false - }, - "@angular/cdk": { - "version": "~14.0.0", - "alwaysAddToPackageJson": false - }, - "ng-packagr": { - "version": "~14.0.0", - "alwaysAddToPackageJson": false - }, - "@angular-eslint/eslint-plugin": { - "version": "~13.2.1", - "alwaysAddToPackageJson": false - }, - "@angular-eslint/eslint-plugin-template": { - "version": "~13.2.1", - "alwaysAddToPackageJson": false - }, - "@angular-eslint/template-parser": { - "version": "~13.2.1", - "alwaysAddToPackageJson": false - }, - "@ngrx/store": { - "version": "~13.2.0", - "alwaysAddToPackageJson": false - }, - "@ngrx/effects": { - "version": "~13.2.0", - "alwaysAddToPackageJson": false - }, - "@ngrx/entity": { - "version": "~13.2.0", - "alwaysAddToPackageJson": false - }, - "@ngrx/router-store": { - "version": "~13.2.0", - "alwaysAddToPackageJson": false - }, - "@ngrx/schematics": { - "version": "~13.2.0", - "alwaysAddToPackageJson": false - }, - "@ngrx/store-devtools": { - "version": "~13.2.0", - "alwaysAddToPackageJson": false - }, - "@ngrx/component-store": { - "version": "~13.2.0", - "alwaysAddToPackageJson": false - }, - "jest-preset-angular": { - "version": "~11.1.2", - "alwaysAddToPackageJson": false - }, - "karma-jasmine": { - "version": "~5.0.0", - "alwaysAddToPackageJson": false - }, - "jasmine-core": { - "version": "~4.1.0", - "alwaysAddToPackageJson": false - }, - "jasmine-spec-reporter": { - "version": "~7.0.0", - "alwaysAddToPackageJson": false - }, - "@types/jasmine": { - "version": "~4.0.0", - "alwaysAddToPackageJson": false - } - } - }, - "14.3.7": { - "version": "14.3.7-beta.0", - "requires": { - "@angular/core": "^14.0.0" - }, - "packages": { - "@ngrx/store": { - "version": "~14.0.0", - "alwaysAddToPackageJson": false - }, - "@ngrx/effects": { - "version": "~14.0.0", - "alwaysAddToPackageJson": false - }, - "@ngrx/entity": { - "version": "~14.0.0", - "alwaysAddToPackageJson": false - }, - "@ngrx/router-store": { - "version": "~14.0.0", - "alwaysAddToPackageJson": false - }, - "@ngrx/schematics": { - "version": "~14.0.0", - "alwaysAddToPackageJson": false - }, - "@ngrx/store-devtools": { - "version": "~14.0.0", - "alwaysAddToPackageJson": false - }, - "@ngrx/component-store": { - "version": "~14.0.0" - } - } - }, - "14.4.0": { - "version": "14.4.0-beta.1", - "requires": { - "eslint": "^7.0.0 || ^8.0.0", - "@angular/core": ">=14.0.0 <15.0.0" - }, - "packages": { - "@angular-eslint/eslint-plugin": { - "version": "~14.0.0", - "alwaysAddToPackageJson": false - }, - "@angular-eslint/eslint-plugin-template": { - "version": "~14.0.0", - "alwaysAddToPackageJson": false - }, - "@angular-eslint/template-parser": { - "version": "~14.0.0", - "alwaysAddToPackageJson": false - } - } - }, - "14.5.2": { - "version": "14.5.2-beta.0", - "x-prompt": "Do you want to update the Angular version to v14.1?", - "requires": { - "@angular/core": ">=14.0.0 <14.1.0" - }, - "packages": { - "@angular-devkit/architect": { - "version": "~0.1401.0", - "alwaysAddToPackageJson": false - }, - "@angular-devkit/build-angular": { - "version": "~14.1.0", - "alwaysAddToPackageJson": false - }, - "@angular-devkit/build-webpack": { - "version": "~0.1401.0", - "alwaysAddToPackageJson": false - }, - "@angular-devkit/core": { - "version": "~14.1.0", - "alwaysAddToPackageJson": false - }, - "@angular-devkit/schematics": { - "version": "~14.1.0", - "alwaysAddToPackageJson": false - }, - "@angular/pwa": { - "version": "~14.1.0", - "alwaysAddToPackageJson": false - }, - "@schematics/angular": { - "version": "~14.1.0", - "alwaysAddToPackageJson": false - }, - "@angular/core": { - "version": "~14.1.0", - "alwaysAddToPackageJson": true - }, - "@angular/material": { - "version": "~14.1.0", - "alwaysAddToPackageJson": false - }, - "ng-packagr": { - "version": "~14.1.0", - "alwaysAddToPackageJson": false - }, - "karma": { - "version": "~6.4.0", - "alwaysAddToPackageJson": false - }, - "karma-jasmine": { - "version": "~5.1.0", - "alwaysAddToPackageJson": false - }, - "karma-jasmine-html-reporter": { - "version": "~2.0.0", - "alwaysAddToPackageJson": false - }, - "jasmine-core": { - "version": "~4.2.0", - "alwaysAddToPackageJson": false - } - } - }, - "14.5.3": { - "version": "14.5.3-beta.0", - "requires": { - "@angular/core": "14.1.0" - }, - "packages": { - "@angular-devkit/architect": { - "version": "~0.1401.1", - "alwaysAddToPackageJson": false - }, - "@angular-devkit/build-angular": { - "version": "~14.1.1", - "alwaysAddToPackageJson": false - }, - "@angular-devkit/build-webpack": { - "version": "~0.1401.1", - "alwaysAddToPackageJson": false - }, - "@angular-devkit/core": { - "version": "~14.1.1", - "alwaysAddToPackageJson": false - }, - "@angular-devkit/schematics": { - "version": "~14.1.1", - "alwaysAddToPackageJson": false - }, - "@angular/pwa": { - "version": "~14.1.1", - "alwaysAddToPackageJson": false - }, - "@schematics/angular": { - "version": "~14.1.1", - "alwaysAddToPackageJson": false - }, - "@angular/core": { - "version": "~14.1.1", - "alwaysAddToPackageJson": true - }, - "@angular/material": { - "version": "~14.1.1", - "alwaysAddToPackageJson": false - }, - "@angular/cdk": { - "version": "~14.1.1", - "alwaysAddToPackageJson": false - } - } - }, - "14.5.5": { - "version": "14.5.5-beta.0", - "packages": { - "ts-node": { - "version": "10.9.1", - "alwaysAddToPackageJson": false - } - } - }, - "14.6.0-angular": { - "version": "14.6.0-beta.0", - "x-prompt": "Do you want to update the Angular version to v14.2?", - "requires": { - "@angular/core": ">=14.1.0 <14.2.0" - }, - "packages": { - "@angular-devkit/architect": { - "version": "~0.1402.0", - "alwaysAddToPackageJson": false - }, - "@angular-devkit/build-angular": { - "version": "~14.2.0", - "alwaysAddToPackageJson": false - }, - "@angular-devkit/build-webpack": { - "version": "~0.1402.0", - "alwaysAddToPackageJson": false - }, - "@angular-devkit/core": { - "version": "~14.2.0", - "alwaysAddToPackageJson": false - }, - "@angular-devkit/schematics": { - "version": "~14.2.0", - "alwaysAddToPackageJson": false - }, - "@angular/pwa": { - "version": "~14.2.0", - "alwaysAddToPackageJson": false - }, - "@schematics/angular": { - "version": "~14.2.0", - "alwaysAddToPackageJson": false - }, - "@angular/core": { - "version": "~14.2.0", - "alwaysAddToPackageJson": true - }, - "@angular/material": { - "version": "~14.2.0", - "alwaysAddToPackageJson": false - }, - "@angular/cdk": { - "version": "~14.2.0", - "alwaysAddToPackageJson": false - }, - "ng-packagr": { - "version": "~14.2.0", - "alwaysAddToPackageJson": false - } - } - }, - "14.6.0-jest-preset-angular": { - "version": "14.6.0-beta.0", - "requires": { - "@angular-devkit/build-angular": ">=0.1102.19 <15.0.0", - "@angular/compiler-cli": ">=11.2.14 <15.0.0", - "@angular/core": ">=11.2.14 <15.0.0", - "@angular/platform-browser-dynamic": ">=11.2.14 <15.0.0", - "jest": "^28.0.0" - }, - "packages": { - "jest-preset-angular": { - "version": "12.2.0", - "alwaysAddToPackageJson": false - } - } - }, - "14.6.0-rxjs": { - "version": "14.6.0-beta.0", - "requires": { - "rxjs": ">=7.0.0 <7.5.0" - }, - "packages": { - "rxjs": { - "version": "~7.5.0", - "alwaysAddToPackageJson": false - } - } - }, - "14.8.0-angular-eslint": { - "version": "14.8.0-beta.0", - "requires": { - "eslint": "^7.0.0 || ^8.0.0", - "@angular/core": ">=14.0.0 <15.0.0" - }, - "packages": { - "@angular-eslint/eslint-plugin": { - "version": "~14.0.4", - "alwaysAddToPackageJson": false - }, - "@angular-eslint/eslint-plugin-template": { - "version": "~14.0.4", - "alwaysAddToPackageJson": false - }, - "@angular-eslint/template-parser": { - "version": "~14.0.4", - "alwaysAddToPackageJson": false - } - } - }, - "14.8.0-jest-preset-angular": { - "version": "14.8.0-beta.0", - "requires": { - "@angular-devkit/build-angular": ">=0.1102.19 <15.0.0", - "@angular/compiler-cli": ">=11.2.14 <15.0.0", - "@angular/core": ">=11.2.14 <15.0.0", - "@angular/platform-browser-dynamic": ">=11.2.14 <15.0.0", - "jest": "^28.0.0" - }, - "packages": { - "jest-preset-angular": { - "version": "12.2.2", - "alwaysAddToPackageJson": false - } - } - }, - "15.2.0": { - "version": "15.2.0-beta.0", - "x-prompt": "Do you want to update the Angular version to v15?", - "requires": { - "@angular/core": "^14.2.0" - }, - "packages": { - "@angular-devkit/architect": { - "version": "~0.1500.0", - "alwaysAddToPackageJson": false - }, - "@angular-devkit/build-angular": { - "version": "~15.0.0", - "alwaysAddToPackageJson": false - }, - "@angular-devkit/build-webpack": { - "version": "~0.1500.0", - "alwaysAddToPackageJson": false - }, - "@angular-devkit/core": { - "version": "~15.0.0", - "alwaysAddToPackageJson": false - }, - "@angular-devkit/schematics": { - "version": "~15.0.0", - "alwaysAddToPackageJson": false - }, - "@angular/pwa": { - "version": "~15.0.0", - "alwaysAddToPackageJson": false - }, - "@schematics/angular": { - "version": "~15.0.0", - "alwaysAddToPackageJson": false - }, - "@angular/core": { - "version": "~15.0.0", - "alwaysAddToPackageJson": true - }, - "@angular/material": { - "version": "~15.0.0", - "alwaysAddToPackageJson": false - }, - "@angular/cdk": { - "version": "~15.0.0", - "alwaysAddToPackageJson": false - }, - "@nguniversal/common": { - "version": "~15.0.0", - "alwaysAddToPackageJson": false - }, - "@nguniversal/express-engine": { - "version": "~15.0.0", - "alwaysAddToPackageJson": false - }, - "@nguniversal/builders": { - "version": "~15.0.0", - "alwaysAddToPackageJson": false - }, - "ng-packagr": { - "version": "~15.0.0", - "alwaysAddToPackageJson": false - } - } - }, - "15.2.2-angular-eslint": { - "version": "15.2.2-beta.0", - "requires": { - "eslint": "^7.20.0 || ^8.0.0", - "@angular/core": ">=15.0.0 <16.0.0" - }, - "packages": { - "@angular-eslint/eslint-plugin": { - "version": "~15.0.0", - "alwaysAddToPackageJson": false - }, - "@angular-eslint/eslint-plugin-template": { - "version": "~15.0.0", - "alwaysAddToPackageJson": false - }, - "@angular-eslint/template-parser": { - "version": "~15.0.0", - "alwaysAddToPackageJson": false - } - } - }, - "15.2.2-jest": { - "version": "15.2.2-beta.0", - "requires": { - "@angular-devkit/build-angular": ">=12.2.18 <16.0.0", - "@angular/compiler-cli": ">=12.2.16 <16.0.0", - "@angular/core": ">=12.2.16 <16.0.0", - "@angular/platform-browser-dynamic": ">=12.2.16 <16.0.0", - "jest": "^28.0.0" - }, - "packages": { - "jest-preset-angular": { - "version": "12.2.3", - "alwaysAddToPackageJson": false - } - } - }, - "15.3.1": { - "version": "15.3.1-beta.0", - "requires": { - "@angular/core": "^15.0.0" - }, - "packages": { - "@ngrx/store": { - "version": "~15.0.0", - "alwaysAddToPackageJson": false - }, - "@ngrx/effects": { - "version": "~15.0.0", - "alwaysAddToPackageJson": false - }, - "@ngrx/entity": { - "version": "~15.0.0", - "alwaysAddToPackageJson": false - }, - "@ngrx/router-store": { - "version": "~15.0.0", - "alwaysAddToPackageJson": false - }, - "@ngrx/schematics": { - "version": "~15.0.0", - "alwaysAddToPackageJson": false - }, - "@ngrx/store-devtools": { - "version": "~15.0.0", - "alwaysAddToPackageJson": false - }, - "@ngrx/component-store": { - "version": "~15.0.0" - } - } - }, - "15.5.0": { - "version": "15.5.0-beta.0", - "x-prompt": "Do you want to update the Angular version to v15.1?", - "requires": { - "@angular/core": ">=15.0.0 <15.1.0" - }, - "packages": { - "@angular-devkit/architect": { - "version": "~0.1501.0", - "alwaysAddToPackageJson": false - }, - "@angular-devkit/build-angular": { - "version": "~15.1.0", - "alwaysAddToPackageJson": false - }, - "@angular-devkit/build-webpack": { - "version": "~0.1501.0", - "alwaysAddToPackageJson": false - }, - "@angular-devkit/core": { - "version": "~15.1.0", - "alwaysAddToPackageJson": false - }, - "@angular-devkit/schematics": { - "version": "~15.1.0", - "alwaysAddToPackageJson": false - }, - "@angular/pwa": { - "version": "~15.1.0", - "alwaysAddToPackageJson": false - }, - "@angular/core": { - "version": "~15.1.0", - "alwaysAddToPackageJson": true - }, - "@angular/material": { - "version": "~15.1.0", - "alwaysAddToPackageJson": false - }, - "@angular/cdk": { - "version": "~15.1.0", - "alwaysAddToPackageJson": false - }, - "@schematics/angular": { - "version": "~15.1.0", - "alwaysAddToPackageJson": false - }, - "ng-packagr": { - "version": "~15.1.0", - "alwaysAddToPackageJson": false - } - } - }, - "15.5.2": { - "version": "15.5.2-beta.0", - "requires": { - "@angular-devkit/build-angular": ">=15.0.0 <16.0.0" - }, - "packages": { - "@nguniversal/builders": { - "version": "~15.1.0", - "alwaysAddToPackageJson": false - }, - "@nguniversal/express-engine": { - "version": "~15.1.0", - "alwaysAddToPackageJson": false - } - } - }, - "15.8.0": { - "version": "15.8.0-beta.4", - "x-prompt": "Do you want to update the Angular version to v15.2?", - "requires": { - "@angular/core": ">=15.1.0 <15.2.0" - }, - "packages": { - "@angular-devkit/architect": { - "version": "~0.1502.0", - "alwaysAddToPackageJson": false - }, - "@angular-devkit/build-angular": { - "version": "~15.2.0", - "alwaysAddToPackageJson": false - }, - "@angular-devkit/build-webpack": { - "version": "~0.1502.0", - "alwaysAddToPackageJson": false - }, - "@angular-devkit/core": { - "version": "~15.2.0", - "alwaysAddToPackageJson": false - }, - "@angular-devkit/schematics": { - "version": "~15.2.0", - "alwaysAddToPackageJson": false - }, - "@angular/pwa": { - "version": "~15.2.0", - "alwaysAddToPackageJson": false - }, - "@angular/core": { - "version": "~15.2.0", - "alwaysAddToPackageJson": true - }, - "@angular/material": { - "version": "~15.2.0", - "alwaysAddToPackageJson": false - }, - "@angular/cdk": { - "version": "~15.2.0", - "alwaysAddToPackageJson": false - }, - "@schematics/angular": { - "version": "~15.2.0", - "alwaysAddToPackageJson": false - }, - "@nguniversal/express-engine": { - "version": "~15.2.0", - "alwaysAddToPackageJson": false - }, - "@nguniversal/build-angular": { - "version": "~15.2.0", - "alwaysAddToPackageJson": false - }, - "ng-packagr": { - "version": "~15.2.2", - "alwaysAddToPackageJson": false - }, - "zone.js": { - "version": "~0.12.0", - "alwaysAddToPackageJson": false - } - } - }, - "15.8.0-jest": { - "version": "15.8.0-beta.0", - "requires": { - "@angular-devkit/build-angular": ">=13.0.0 <16.0.0", - "@angular/compiler-cli": ">=13.0.0 <16.0.0", - "@angular/core": ">=13.0.0 <16.0.0", - "@angular/platform-browser-dynamic": ">=13.0.0 <16.0.0", - "jest": "^29.0.0" - }, - "packages": { - "jest-preset-angular": { - "version": "13.0.0", - "alwaysAddToPackageJson": false - } - } - }, - "15.8.0-ngrx": { - "version": "15.8.0-beta.6", - "requires": { - "@angular/core": "^15.0.0" - }, - "packages": { - "@ngrx/store": { - "version": "~15.3.0", - "alwaysAddToPackageJson": false - }, - "@ngrx/effects": { - "version": "~15.3.0", - "alwaysAddToPackageJson": false - }, - "@ngrx/entity": { - "version": "~15.3.0", - "alwaysAddToPackageJson": false - }, - "@ngrx/router-store": { - "version": "~15.3.0", - "alwaysAddToPackageJson": false - }, - "@ngrx/schematics": { - "version": "~15.3.0", - "alwaysAddToPackageJson": false - }, - "@ngrx/store-devtools": { - "version": "~15.3.0", - "alwaysAddToPackageJson": false - }, - "@ngrx/component-store": { - "version": "~15.3.0", - "alwaysAddToPackageJson": false - } - } - }, - "15.8.6-rxjs": { - "version": "15.8.6-beta.0", - "requires": { - "rxjs": ">=7.5.0 <7.6.0" - }, - "packages": { - "rxjs": { - "version": "~7.8.0", - "alwaysAddToPackageJson": false - } - } - }, "16.1.0": { "version": "16.1.0-beta.1", "x-prompt": "Do you want to update the Angular version to v16?", diff --git a/packages/angular/src/generators/application/application.ts b/packages/angular/src/generators/application/application.ts index 3acf8b95ebea7c..8a4390e628c96e 100644 --- a/packages/angular/src/generators/application/application.ts +++ b/packages/angular/src/generators/application/application.ts @@ -7,7 +7,9 @@ import { Tree, updateNxJson, } from '@nx/devkit'; +import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command'; import { initGenerator as jsInitGenerator } from '@nx/js'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { angularInitGenerator } from '../init/init'; import { setupSsr } from '../setup-ssr/setup-ssr'; import { setupTailwindGenerator } from '../setup-tailwind/setup-tailwind'; @@ -27,12 +29,13 @@ import { updateEditorTsConfig, } from './lib'; import type { Schema } from './schema'; -import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command'; export async function applicationGenerator( tree: Tree, schema: Partial ): Promise { + assertNotUsingTsSolutionSetup(tree, 'angular', 'application'); + const options = await normalizeOptions(tree, schema); const rootOffset = offsetFromRoot(options.appProjectRoot); diff --git a/packages/angular/src/generators/host/host.ts b/packages/angular/src/generators/host/host.ts index c181eea3f1a546..35b41d2afee49f 100644 --- a/packages/angular/src/generators/host/host.ts +++ b/packages/angular/src/generators/host/host.ts @@ -9,16 +9,19 @@ import { determineProjectNameAndRootOptions, ensureProjectName, } from '@nx/devkit/src/generators/project-name-and-root-utils'; +import { isValidVariable } from '@nx/js'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { E2eTestRunner } from '../../utils/test-runners'; import applicationGenerator from '../application/application'; import remoteGenerator from '../remote/remote'; import { setupMf } from '../setup-mf/setup-mf'; +import { addMfEnvToTargetDefaultInputs } from '../utils/add-mf-env-to-inputs'; import { updateSsrSetup } from './lib'; import type { Schema } from './schema'; -import { addMfEnvToTargetDefaultInputs } from '../utils/add-mf-env-to-inputs'; -import { isValidVariable } from '@nx/js'; export async function host(tree: Tree, schema: Schema) { + assertNotUsingTsSolutionSetup(tree, 'angular', 'host'); + const { typescriptConfiguration = true, ...options }: Schema = schema; options.standalone = options.standalone ?? true; diff --git a/packages/angular/src/generators/init/init.ts b/packages/angular/src/generators/init/init.ts index 4cae47914c4736..4641dac634bfbf 100755 --- a/packages/angular/src/generators/init/init.ts +++ b/packages/angular/src/generators/init/init.ts @@ -9,14 +9,17 @@ import { type Tree, } from '@nx/devkit'; import { addPlugin } from '@nx/devkit/src/utils/add-plugin'; -import { getInstalledPackageVersion, versions } from '../utils/version-utils'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { createNodesV2 } from '../../plugins/plugin'; +import { getInstalledPackageVersion, versions } from '../utils/version-utils'; import { Schema } from './schema'; export async function angularInitGenerator( tree: Tree, options: Schema ): Promise { + assertNotUsingTsSolutionSetup(tree, 'angular', 'init'); + ignoreAngularCacheDirectory(tree); const installTask = installAngularDevkitCoreIfMissing(tree, options); diff --git a/packages/angular/src/generators/library/library.ts b/packages/angular/src/generators/library/library.ts index 5955ca38cf8e19..af46e11472c676 100644 --- a/packages/angular/src/generators/library/library.ts +++ b/packages/angular/src/generators/library/library.ts @@ -30,11 +30,14 @@ import { addJest } from '../utils/add-jest'; import { setGeneratorDefaults } from './lib/set-generator-defaults'; import { ensureAngularDependencies } from '../utils/ensure-angular-dependencies'; import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; export async function libraryGenerator( tree: Tree, schema: Schema ): Promise { + assertNotUsingTsSolutionSetup(tree, 'angular', 'library'); + // Do some validation checks if (!schema.routing && schema.lazy) { throw new Error(`To use "--lazy" option, "--routing" must also be set.`); diff --git a/packages/angular/src/generators/remote/remote.ts b/packages/angular/src/generators/remote/remote.ts index 3d26a6821fe00a..f8c8f4197275cd 100644 --- a/packages/angular/src/generators/remote/remote.ts +++ b/packages/angular/src/generators/remote/remote.ts @@ -9,15 +9,18 @@ import { determineProjectNameAndRootOptions, ensureProjectName, } from '@nx/devkit/src/generators/project-name-and-root-utils'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; +import { swcHelpersVersion } from '@nx/js/src/utils/versions'; import { E2eTestRunner } from '../../utils/test-runners'; import { applicationGenerator } from '../application/application'; import { setupMf } from '../setup-mf/setup-mf'; +import { addMfEnvToTargetDefaultInputs } from '../utils/add-mf-env-to-inputs'; import { findNextAvailablePort, updateSsrSetup } from './lib'; import type { Schema } from './schema'; -import { swcHelpersVersion } from '@nx/js/src/utils/versions'; -import { addMfEnvToTargetDefaultInputs } from '../utils/add-mf-env-to-inputs'; export async function remote(tree: Tree, schema: Schema) { + assertNotUsingTsSolutionSetup(tree, 'angular', 'remote'); + const { typescriptConfiguration = true, ...options }: Schema = schema; options.standalone = options.standalone ?? true; diff --git a/packages/angular/src/utils/mf/with-module-federation-ssr.ts b/packages/angular/src/utils/mf/with-module-federation-ssr.ts index e017d134588347..e5918a9d019349 100644 --- a/packages/angular/src/utils/mf/with-module-federation-ssr.ts +++ b/packages/angular/src/utils/mf/with-module-federation-ssr.ts @@ -40,7 +40,7 @@ export async function withModuleFederationForSSR( ...(config.plugins ?? []), new (require('@module-federation/enhanced').ModuleFederationPlugin)( { - name: options.name, + name: options.name.replace(/-/g, '_'), filename: 'remoteEntry.js', exposes: options.exposes, remotes: mappedRemotes, diff --git a/packages/angular/src/utils/mf/with-module-federation.ts b/packages/angular/src/utils/mf/with-module-federation.ts index 8bdb757a92008d..1845d6ac8893f8 100644 --- a/packages/angular/src/utils/mf/with-module-federation.ts +++ b/packages/angular/src/utils/mf/with-module-federation.ts @@ -42,7 +42,7 @@ export async function withModuleFederation( plugins: [ ...(config.plugins ?? []), new ModuleFederationPlugin({ - name: options.name, + name: options.name.replace(/-/g, '_'), filename: 'remoteEntry.mjs', exposes: options.exposes, remotes: mappedRemotes, diff --git a/packages/create-nx-workspace/bin/create-nx-workspace.ts b/packages/create-nx-workspace/bin/create-nx-workspace.ts index a215be4bf1d192..44487ddf21b56e 100644 --- a/packages/create-nx-workspace/bin/create-nx-workspace.ts +++ b/packages/create-nx-workspace/bin/create-nx-workspace.ts @@ -397,7 +397,7 @@ async function determineStack( name: `none`, message: process.env.NX_ADD_PLUGINS !== 'false' && - process.env.NX_ADD_TS_PLUGIN === 'true' + process.env.NX_ADD_TS_PLUGIN !== 'false' ? `None: Configures a TypeScript/JavaScript monorepo.` : `None: Configures a TypeScript/JavaScript project with minimal structure.`, }, @@ -447,8 +447,9 @@ async function determineNoneOptions( parsedArgs: yargs.Arguments ): Promise> { if ( + (!parsedArgs.preset || parsedArgs.preset === Preset.TS) && process.env.NX_ADD_PLUGINS !== 'false' && - process.env.NX_ADD_TS_PLUGIN === 'true' + process.env.NX_ADD_TS_PLUGIN !== 'false' ) { const reply = await enquirer.prompt<{ prettier: 'Yes' | 'No' }>([ { diff --git a/packages/cypress/migrations.json b/packages/cypress/migrations.json index 0b38ab249fe7d5..fc1647b55a3a7f 100644 --- a/packages/cypress/migrations.json +++ b/packages/cypress/migrations.json @@ -1,29 +1,5 @@ { "generators": { - "update-16-0-0-add-nx-packages": { - "cli": "nx", - "version": "16.0.0-beta.1", - "description": "Replace @nrwl/cypress with @nx/cypress", - "implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages" - }, - "update-16-2-0-normalize-tsconfigs": { - "cli": "nx", - "version": "16.2.0-beta.0", - "description": "Normalize tsconfig.cy.json files to be located at '/cypress/tsconfig.json'", - "implementation": "./src/migrations/update-16-2-0/update-cy-tsconfig" - }, - "update-16-3-0-remove-old-tsconfigs": { - "cli": "nx", - "version": "16.4.0-beta.10", - "description": "Remove tsconfig.e2e.json and add settings to project tsconfig.json. tsConfigs executor option is now deprecated. The project level tsconfig.json file should be used instead.", - "implementation": "./src/migrations/update-16-4-0/tsconfig-sourcemaps" - }, - "update-16-8-0-cypress-13": { - "cli": "nx", - "version": "16.8.0-beta.4", - "description": "Update to Cypress v13. Most noteable change is video recording is off by default. This migration will only update if the workspace is already on Cypress v12. https://docs.cypress.io/guides/references/migration-guide#Migrating-to-Cypress-130", - "implementation": "./src/migrations/update-16-8-0/cypress-13" - }, "update-cypress-version-13-6-6": { "cli": "nx", "version": "18.1.0-beta.3", @@ -38,39 +14,6 @@ } }, "packageJsonUpdates": { - "16.1.0": { - "version": "16.1.0-beta.0", - "requires": { - "cypress": ">=12.0.0 <12.11.0" - }, - "packages": { - "cypress": { - "version": "^12.11.0", - "alwaysAddToPackageJson": false - } - } - }, - "16.5.0": { - "version": "16.5.0-beta.0", - "requires": { - "cypress": ">=12.0.0 <12.16.0" - }, - "packages": { - "cypress": { - "version": "^12.16.0", - "alwaysAddToPackageJson": false - } - } - }, - "16.7.0": { - "version": "16.7.0-beta.3", - "packages": { - "eslint-plugin-cypress": { - "version": "^2.13.4", - "alwaysAddToPackageJson": false - } - } - }, "17.2.0-beta.2": { "version": "17.2.0-beta.2", "packages": { diff --git a/packages/cypress/src/generators/component-configuration/component-configuration.ts b/packages/cypress/src/generators/component-configuration/component-configuration.ts index 6d4078c297992e..9407684d86054e 100644 --- a/packages/cypress/src/generators/component-configuration/component-configuration.ts +++ b/packages/cypress/src/generators/component-configuration/component-configuration.ts @@ -14,6 +14,7 @@ import { runTasksInSerial, GeneratorCallback, } from '@nx/devkit'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { installedCypressVersion } from '../../utils/cypress-version'; import { @@ -42,6 +43,8 @@ export async function componentConfigurationGeneratorInternal( tree: Tree, options: CypressComponentConfigurationSchema ) { + assertNotUsingTsSolutionSetup(tree, 'cypress', 'component-configuration'); + const tasks: GeneratorCallback[] = []; const opts = normalizeOptions(tree, options); diff --git a/packages/cypress/src/generators/configuration/configuration.ts b/packages/cypress/src/generators/configuration/configuration.ts index f5f4ec06baedec..e05b8d51622cb8 100644 --- a/packages/cypress/src/generators/configuration/configuration.ts +++ b/packages/cypress/src/generators/configuration/configuration.ts @@ -17,18 +17,19 @@ import { updateJson, updateProjectConfiguration, } from '@nx/devkit'; +import { Linter, LinterType } from '@nx/eslint'; import { getRelativePathToRootTsConfig, initGenerator as jsInitGenerator, } from '@nx/js'; -import { Linter, LinterType } from '@nx/eslint'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { join } from 'path'; import { addLinterToCyProject } from '../../utils/add-linter'; import { addDefaultE2EConfig } from '../../utils/config'; import { installedCypressVersion } from '../../utils/cypress-version'; import { typesNodeVersion, viteVersion } from '../../utils/versions'; -import cypressInitGenerator, { addPlugin } from '../init/init'; import { addBaseCypressSetup } from '../base-setup/base-setup'; +import cypressInitGenerator, { addPlugin } from '../init/init'; export interface CypressE2EConfigSchema { project: string; @@ -67,6 +68,8 @@ export async function configurationGeneratorInternal( tree: Tree, options: CypressE2EConfigSchema ) { + assertNotUsingTsSolutionSetup(tree, 'cypress', 'configuration'); + const opts = normalizeOptions(tree, options); opts.addPlugin ??= process.env.NX_ADD_PLUGINS !== 'false'; const tasks: GeneratorCallback[] = []; diff --git a/packages/cypress/src/generators/init/init.ts b/packages/cypress/src/generators/init/init.ts index b8deed06a0569e..89a2d2495a53c9 100644 --- a/packages/cypress/src/generators/init/init.ts +++ b/packages/cypress/src/generators/init/init.ts @@ -11,6 +11,7 @@ import { updateNxJson, } from '@nx/devkit'; import { addPlugin as _addPlugin } from '@nx/devkit/src/utils/add-plugin'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { createNodesV2 } from '../../plugins/plugin'; import { cypressVersion, nxVersion } from '../../utils/versions'; import { Schema } from './schema'; @@ -105,6 +106,8 @@ export async function cypressInitGeneratorInternal( tree: Tree, options: Schema ) { + assertNotUsingTsSolutionSetup(tree, 'cypress', 'init'); + updateProductionFileset(tree); const nxJson = readNxJson(tree); diff --git a/packages/cypress/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts b/packages/cypress/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts deleted file mode 100644 index ac8681ec340117..00000000000000 --- a/packages/cypress/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Tree, readJson, updateJson } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import replacePackage from './update-16-0-0-add-nx-packages'; - -describe('update-16-0-0-add-nx-packages', () => { - let tree: Tree; - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - - updateJson(tree, 'package.json', (json) => { - json.devDependencies['@nrwl/cypress'] = '16.0.0'; - return json; - }); - }); - - it('should remove the dependency on @nrwl/cypress', async () => { - await replacePackage(tree); - - expect( - readJson(tree, 'package.json').dependencies['@nrwl/cypress'] - ).not.toBeDefined(); - expect( - readJson(tree, 'package.json').devDependencies['@nrwl/cypress'] - ).not.toBeDefined(); - }); - - it('should add a dependency on @nx/cypress', async () => { - await replacePackage(tree); - - const packageJson = readJson(tree, 'package.json'); - const newDependencyVersion = - packageJson.devDependencies['@nx/cypress'] ?? - packageJson.dependencies['@nx/cypress']; - - expect(newDependencyVersion).toBeDefined(); - }); -}); diff --git a/packages/cypress/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts b/packages/cypress/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts deleted file mode 100644 index e3edbbb93e6fd5..00000000000000 --- a/packages/cypress/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Tree, formatFiles } from '@nx/devkit'; -import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package'; - -export default async function replacePackage(tree: Tree): Promise { - await replaceNrwlPackageWithNxPackage(tree, '@nrwl/cypress', '@nx/cypress'); - - await formatFiles(tree); -} diff --git a/packages/cypress/src/migrations/update-16-2-0/update-cy-tsconfig.spec.ts b/packages/cypress/src/migrations/update-16-2-0/update-cy-tsconfig.spec.ts deleted file mode 100644 index 672e613f3508c2..00000000000000 --- a/packages/cypress/src/migrations/update-16-2-0/update-cy-tsconfig.spec.ts +++ /dev/null @@ -1,250 +0,0 @@ -import 'nx/src/internal-testing-utils/mock-project-graph'; - -import { - Tree, - readJson, - readProjectConfiguration, - updateJson, - updateProjectConfiguration, -} from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from 'nx/src/devkit-testing-exports'; -import { normalizeCyTsConfigNames } from './update-cy-tsconfig'; -import { libraryGenerator } from '@nx/js'; - -describe('Cypress Migration - update-cy-tsconfig', () => { - let tree: Tree; - - beforeEach(() => { - tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); - }); - it('should do nothing if cypress/tsconfig.json exists', async () => { - await libraryGenerator(tree, { directory: 'libs/my-lib' }); - addCyExecutor(tree, 'my-lib'); - const tsconfig = { - extends: '../tsconfig.json', - compilerOptions: { - sourceMap: false, - outDir: '../../../dist/out-tsc', - allowJs: true, - types: ['cypress', 'node'], - }, - include: ['**/*.ts', '**/*.js', '../cypress.config.ts'], - }; - - tree.write( - 'libs/my-lib/cypress/tsconfig.json', - JSON.stringify(tsconfig, null, 2) - ); - updateJson(tree, 'libs/my-lib/tsconfig.json', (json) => { - json.references ??= []; - json.references.push({ path: './cypress/tsconfig.json' }); - return json; - }); - - await normalizeCyTsConfigNames(tree); - expect(readJson(tree, 'libs/my-lib/tsconfig.json').references).toEqual( - expect.arrayContaining([{ path: './cypress/tsconfig.json' }]) - ); - expect(readJson(tree, 'libs/my-lib/cypress/tsconfig.json')).toEqual( - tsconfig - ); - }); - - it('should move cypress/tsconfig.cy.json to cypress/tsconfig.json', async () => { - await libraryGenerator(tree, { directory: 'libs/my-lib' }); - addCyExecutor(tree, 'my-lib'); - const tsconfig = { - extends: '../tsconfig.json', - compilerOptions: { - outDir: '../../../dist/out-tsc', - module: 'commonjs', - types: ['cypress', 'node'], - sourceMap: false, - }, - include: [ - 'support/**/*.ts', - '../cypress.config.ts', - '../**/*.cy.ts', - '../**/*.cy.tsx', - '../**/*.cy.js', - '../**/*.cy.jsx', - '../**/*.d.ts', - ], - }; - - tree.write( - 'libs/my-lib/cypress/tsconfig.cy.json', - JSON.stringify(tsconfig, null, 2) - ); - - updateJson(tree, 'libs/my-lib/tsconfig.json', (json) => { - json.references ??= []; - json.references.push({ path: './cypress/tsconfig.cy.json' }); - return json; - }); - - await normalizeCyTsConfigNames(tree); - expect(tree.exists('libs/my-lib/cypress/tsconfig.cy.json')).toBeFalsy(); - expect(readJson(tree, 'libs/my-lib/tsconfig.json').references).toEqual( - expect.arrayContaining([{ path: './cypress/tsconfig.json' }]) - ); - expect(readJson(tree, 'libs/my-lib/cypress/tsconfig.json')).toEqual( - tsconfig - ); - }); - - it('should move tsconfig.cy.json to cypress/tsconfig.json', async () => { - await libraryGenerator(tree, { directory: 'libs/my-lib' }); - addCyExecutor(tree, 'my-lib'); - const tsconfig = { - extends: './tsconfig.json', - compilerOptions: { - outDir: '../../dist/out-tsc', - module: 'commonjs', - types: ['cypress', 'node'], - sourceMap: false, - }, - include: [ - 'cypress/support/**/*.ts', - 'cypress.config.ts', - '**/*.cy.ts', - '**/*.cy.tsx', - '**/*.cy.js', - '**/*.cy.jsx', - '**/*.d.ts', - ], - }; - - tree.write( - 'libs/my-lib/tsconfig.cy.json', - JSON.stringify(tsconfig, null, 2) - ); - updateJson(tree, 'libs/my-lib/tsconfig.json', (json) => { - json.references ??= []; - json.references.push({ path: './tsconfig.cy.json' }); - return json; - }); - - await normalizeCyTsConfigNames(tree); - expect(tree.exists('libs/my-lib/tsconfig.cy.json')).toBeFalsy(); - expect(readJson(tree, 'libs/my-lib/tsconfig.json').references).toEqual( - expect.arrayContaining([{ path: './cypress/tsconfig.json' }]) - ); - expect(readJson(tree, 'libs/my-lib/cypress/tsconfig.json')).toEqual({ - extends: '../tsconfig.json', - compilerOptions: { - outDir: '../../../dist/out-tsc', - module: 'commonjs', - types: ['cypress', 'node'], - sourceMap: false, - }, - include: [ - 'support/**/*.ts', - '../cypress.config.ts', - '../**/*.cy.ts', - '../**/*.cy.tsx', - '../**/*.cy.js', - '../**/*.cy.jsx', - '../**/*.d.ts', - ], - }); - }); - - it('should be idepotent', async () => { - await libraryGenerator(tree, { directory: 'libs/my-lib' }); - addCyExecutor(tree, 'my-lib'); - const tsconfig = { - extends: './tsconfig.json', - compilerOptions: { - outDir: '../../dist/out-tsc', - module: 'commonjs', - types: ['cypress', 'node'], - sourceMap: false, - }, - include: [ - 'cypress/support/**/*.ts', - 'cypress.config.ts', - '**/*.cy.ts', - '**/*.cy.tsx', - '**/*.cy.js', - '**/*.cy.jsx', - '**/*.d.ts', - ], - }; - - tree.write( - 'libs/my-lib/tsconfig.cy.json', - JSON.stringify(tsconfig, null, 2) - ); - updateJson(tree, 'libs/my-lib/tsconfig.json', (json) => { - json.references ??= []; - json.references.push({ path: './tsconfig.cy.json' }); - return json; - }); - - await normalizeCyTsConfigNames(tree); - expect(tree.exists('libs/my-lib/tsconfig.cy.json')).toBeFalsy(); - expect(readJson(tree, 'libs/my-lib/tsconfig.json').references).toEqual( - expect.arrayContaining([{ path: './cypress/tsconfig.json' }]) - ); - expect(readJson(tree, 'libs/my-lib/cypress/tsconfig.json')).toEqual({ - extends: '../tsconfig.json', - compilerOptions: { - outDir: '../../../dist/out-tsc', - module: 'commonjs', - types: ['cypress', 'node'], - sourceMap: false, - }, - include: [ - 'support/**/*.ts', - '../cypress.config.ts', - '../**/*.cy.ts', - '../**/*.cy.tsx', - '../**/*.cy.js', - '../**/*.cy.jsx', - '../**/*.d.ts', - ], - }); - - await normalizeCyTsConfigNames(tree); - expect(tree.exists('libs/my-lib/tsconfig.cy.json')).toBeFalsy(); - expect(readJson(tree, 'libs/my-lib/tsconfig.json').references).toEqual([ - { path: './tsconfig.lib.json' }, - { path: './tsconfig.spec.json' }, - { path: './cypress/tsconfig.json' }, - ]); - expect(readJson(tree, 'libs/my-lib/cypress/tsconfig.json')).toEqual({ - extends: '../tsconfig.json', - compilerOptions: { - outDir: '../../../dist/out-tsc', - module: 'commonjs', - types: ['cypress', 'node'], - sourceMap: false, - }, - include: [ - 'support/**/*.ts', - '../cypress.config.ts', - '../**/*.cy.ts', - '../**/*.cy.tsx', - '../**/*.cy.js', - '../**/*.cy.jsx', - '../**/*.d.ts', - ], - }); - }); -}); - -function addCyExecutor(tree: Tree, projectName: string) { - const pc = readProjectConfiguration(tree, projectName); - - pc.targets['e2e'] = { - executor: '@nx/cypress:cypress', - options: { - testingType: 'e2e', - devServerTarget: `${projectName}:serve`, - cypressConfig: `${projectName}/cypress.config.ts`, - }, - }; - - updateProjectConfiguration(tree, projectName, pc); -} diff --git a/packages/cypress/src/migrations/update-16-2-0/update-cy-tsconfig.ts b/packages/cypress/src/migrations/update-16-2-0/update-cy-tsconfig.ts deleted file mode 100644 index 21c4b091f599a9..00000000000000 --- a/packages/cypress/src/migrations/update-16-2-0/update-cy-tsconfig.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { - ProjectConfiguration, - Tree, - formatFiles, - getProjects, - joinPathFragments, - updateJson, -} from '@nx/devkit'; -import { forEachExecutorOptions } from '@nx/devkit/src/generators/executor-options-utils'; - -export async function normalizeCyTsConfigNames(tree: Tree) { - const projects = getProjects(tree); - - forEachExecutorOptions(tree, '@nx/cypress:cypress', (_, projectName) => { - const projectConfig = projects.get(projectName); - const newTsConfigPath = joinPathFragments( - projectConfig.root, - 'cypress', - 'tsconfig.json' - ); - - // if there is already a tsconfig.json in the cypress folder, then assume things are setup already - if (!tree.exists(newTsConfigPath)) { - moveProjectTsCyConfig(tree, projectConfig, newTsConfigPath); - moveCyDirTsCyConfig(tree, projectConfig, newTsConfigPath); - updateCyDirTsConfigReferences(tree, projectConfig); - } - }); - - await formatFiles(tree); -} - -function moveProjectTsCyConfig( - tree: Tree, - projectConfig: ProjectConfiguration, - newTsConfigPath: string -) { - if (tree.exists(joinPathFragments(projectConfig.root, 'tsconfig.cy.json'))) { - tree.rename( - joinPathFragments(projectConfig.root, 'tsconfig.cy.json'), - newTsConfigPath - ); - updateJson(tree, newTsConfigPath, (json) => { - json.extends = '../tsconfig.json'; - - json.compilerOptions ??= {}; - json.compilerOptions = { - ...json.compilerOptions, - sourceMap: false, - outDir: '../../../dist/out-tsc', - }; - - json.include ??= []; - json.include = json.include.map((p) => { - if (p.startsWith('cypress/')) { - return p.replace('cypress/', ''); - } - return `../${p}`; - }); - return json; - }); - } -} - -function moveCyDirTsCyConfig( - tree: Tree, - projectConfig: ProjectConfiguration, - newTsConfigPath: string -) { - if ( - tree.exists( - joinPathFragments(projectConfig.root, 'cypress', 'tsconfig.cy.json') - ) - ) { - tree.rename( - joinPathFragments(projectConfig.root, 'cypress', 'tsconfig.cy.json'), - newTsConfigPath - ); - updateJson(tree, newTsConfigPath, (json) => { - json.compilerOptions ??= {}; - json.compilerOptions = { - ...json.compilerOptions, - sourceMap: false, - }; - - return json; - }); - } -} - -function updateCyDirTsConfigReferences( - tree: Tree, - projectConfig: ProjectConfiguration -) { - if ( - !tree.exists( - joinPathFragments(projectConfig.root, 'cypress', 'tsconfig.json') - ) - ) { - return; - } - updateJson( - tree, - joinPathFragments(projectConfig.root, 'tsconfig.json'), - (json) => { - json.references ??= []; - if (!json.references) { - return json; - } - const cyFile = json.references.find((p) => - p.path.includes('tsconfig.cy.json') - ); - - if (cyFile) { - json.references.splice(json.references.indexOf(cyFile), 1); - } - - if (!json.references.some((r) => r.path === './cypress/tsconfig.json')) { - json.references.push({ - path: './cypress/tsconfig.json', - }); - } - return json; - } - ); -} - -export default normalizeCyTsConfigNames; diff --git a/packages/cypress/src/migrations/update-16-4-0/tsconfig-sourcemaps.spec.ts b/packages/cypress/src/migrations/update-16-4-0/tsconfig-sourcemaps.spec.ts deleted file mode 100644 index 307c1ae56645a3..00000000000000 --- a/packages/cypress/src/migrations/update-16-4-0/tsconfig-sourcemaps.spec.ts +++ /dev/null @@ -1,175 +0,0 @@ -import { - Tree, - addProjectConfiguration, - readJson, - readProjectConfiguration, - updateJson, - updateProjectConfiguration, -} from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from 'nx/src/devkit-testing-exports'; -import { fixLegacyCypressTsconfig } from './tsconfig-sourcemaps'; - -describe('Cypress Migration: tsconfig-sourcemaps', () => { - let tree: Tree; - - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - }); - - it('should remove tsconfig.e2e.json and update tsconfig.json', async () => { - addLegacyProject(tree); - - await fixLegacyCypressTsconfig(tree); - expect(readProjectConfiguration(tree, 'legacy-e2e').targets.e2e) - .toMatchInlineSnapshot(` - { - "configurations": { - "production": { - "devServerTarget": "legacy-e2e:serve:production", - }, - }, - "executor": "@nx/cypress:cypress", - "options": { - "cypressConfig": "apps/legacy-e2e/cypress.config.ts", - "devServerTarget": "legacy-e2e:serve", - "testingType": "e2e", - }, - } - `); - expect(readJson(tree, 'apps/legacy-e2e/tsconfig.json')) - .toMatchInlineSnapshot(` - { - "compilerOptions": { - "outDir": "../../dist/out-tsc", - "resolveJsonModule": true, - "sourceMap": false, - "strict": true, - "types": [ - "cypress", - "node", - ], - }, - "exclude": [], - "extends": "../../tsconfig.base.json", - "files": [], - "include": [ - "cypress.ci.1.config.ts", - "cypress.ci.2.config.ts", - "cypress.ci.3.config.ts", - "cypress.ci.4.config.ts", - "src/**/*.ts", - "cypress.config.ts", - ], - "references": [], - } - `); - expect(tree.exists('apps/legacy-e2e/tsconfig.e2e.json')).toBeFalsy(); - expect(tree.exists('apps/legacy-e2e/tsconfig.e2e.prod.json')).toBeFalsy(); - }); - - it('should do nothing if tsconfig option is not used', async () => { - addLegacyProject(tree); - - tree.delete('apps/legacy-e2e/tsconfig.e2e.json'); - tree.delete('apps/legacy-e2e/tsconfig.e2e.prod.json'); - const pc = readProjectConfiguration(tree, 'legacy-e2e'); - - delete pc.targets.e2e.options.tsConfig; - delete pc.targets.e2e.configurations; - - const existingProjectConfig = pc.targets.e2e; - - updateProjectConfiguration(tree, 'legacy-e2e', pc); - - updateJson(tree, 'apps/legacy-e2e/tsconfig.json', (json) => { - json.references = []; - return json; - }); - - const existingTsConfig = readJson(tree, 'apps/legacy-e2e/tsconfig.json'); - - await fixLegacyCypressTsconfig(tree); - - expect(readProjectConfiguration(tree, 'legacy-e2e').targets.e2e).toEqual( - existingProjectConfig - ); - expect(readJson(tree, 'apps/legacy-e2e/tsconfig.json')).toEqual( - existingTsConfig - ); - }); -}); - -function addLegacyProject(tree: Tree) { - addProjectConfiguration(tree, 'legacy-e2e', { - root: 'apps/legacy-e2e', - sourceRoot: 'apps/legacy-e2e/src', - targets: { - e2e: { - executor: '@nx/cypress:cypress', - options: { - cypressConfig: 'apps/legacy-e2e/cypress.config.ts', - tsConfig: 'apps/legacy-e2e/tsconfig.e2e.json', - devServerTarget: 'legacy-e2e:serve', - testingType: 'e2e', - }, - configurations: { - production: { - devServerTarget: 'legacy-e2e:serve:production', - tsConfig: 'apps/legacy-e2e/tsconfig.e2e.prod.json', - }, - }, - }, - }, - }); - - tree.write( - 'apps/legacy-e2e/tsconfig.e2e.json', - JSON.stringify({ - extends: './tsconfig.json', - compilerOptions: { - sourceMap: false, - outDir: '../../dist/out-tsc', - types: ['cypress', 'node'], - }, - include: ['src/**/*.ts', 'cypress.config.ts'], - }) - ); - tree.write( - 'apps/legacy-e2e/tsconfig.e2e.prod.json', - JSON.stringify({ - extends: './tsconfig.e2e.json', - compilerOptions: { - sourceMap: false, - outDir: '../../dist/out-tsc', - types: ['cypress', 'node'], - strict: true, - }, - include: ['src/**/*.ts', 'cypress.config.ts'], - }) - ); - tree.write( - 'apps/legacy-e2e/tsconfig.json', - JSON.stringify({ - extends: '../../tsconfig.base.json', - compilerOptions: { - types: ['cypress', 'node'], - resolveJsonModule: true, - }, - include: [ - 'cypress.ci.1.config.ts', - 'cypress.ci.2.config.ts', - 'cypress.ci.3.config.ts', - 'cypress.ci.4.config.ts', - ], - files: [], - references: [ - { - path: './tsconfig.e2e.json', - }, - { - path: './tsconfig.e2e.prod.json', - }, - ], - }) - ); -} diff --git a/packages/cypress/src/migrations/update-16-4-0/tsconfig-sourcemaps.ts b/packages/cypress/src/migrations/update-16-4-0/tsconfig-sourcemaps.ts deleted file mode 100644 index a90982d8b74ed2..00000000000000 --- a/packages/cypress/src/migrations/update-16-4-0/tsconfig-sourcemaps.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { forEachExecutorOptions } from '@nx/devkit/src/generators/executor-options-utils'; -import { CypressExecutorOptions } from '../../executors/cypress/cypress.impl'; -import { - updateJson, - Tree, - getProjects, - joinPathFragments, - readJson, - updateProjectConfiguration, - formatFiles, -} from '@nx/devkit'; -import { posix } from 'path'; - -export async function fixLegacyCypressTsconfig(tree: Tree) { - const projects = getProjects(tree); - forEachExecutorOptions( - tree, - '@nx/cypress:cypress', - (options, projectName, targetName, configName) => { - const projectConfig = projects.get(projectName); - - if ( - options.testingType !== 'e2e' && - projectConfig.targets[targetName]?.options?.testingType !== 'e2e' - ) { - return; - } - - const tsconfigToRemove = - options.tsConfig ?? - joinPathFragments(projectConfig.root, 'tsconfig.e2e.json'); - - const projectLevelConfigPath = joinPathFragments( - projectConfig.root, - 'tsconfig.json' - ); - - if ( - !tree.exists(projectLevelConfigPath) || - !tree.exists(tsconfigToRemove) - ) { - return; - } - - if (tsconfigToRemove === projectLevelConfigPath) { - updateJson(tree, projectLevelConfigPath, (json) => { - json.compilerOptions = { - sourceMap: false, - ...json.compilerOptions, - }; - return json; - }); - } else { - const e2eConfig = readJson(tree, tsconfigToRemove); - - updateJson(tree, projectLevelConfigPath, (json) => { - json.compilerOptions = { - sourceMap: false, - ...json.compilerOptions, - ...e2eConfig.compilerOptions, - }; - json.files = Array.from( - new Set([...(json.files ?? []), ...(e2eConfig.files ?? [])]) - ); - json.include = Array.from( - new Set([...(json.include ?? []), ...(e2eConfig.include ?? [])]) - ); - json.exclude = Array.from( - new Set([...(json.exclude ?? []), ...(e2eConfig.exclude ?? [])]) - ); - - // these paths will always be 'unix style' - // and on windows relative will not work on these paths - const tsConfigFromProjRoot = posix.relative( - projectConfig.root, - tsconfigToRemove - ); - - json.references = (json.references ?? []).filter( - ({ path }) => !path.includes(tsConfigFromProjRoot) - ); - return json; - }); - - tree.delete(tsconfigToRemove); - } - - if (configName) { - delete projectConfig.targets[targetName].configurations[configName] - .tsConfig; - } else { - delete projectConfig.targets[targetName].options.tsConfig; - } - - updateProjectConfiguration(tree, projectName, projectConfig); - } - ); - - await formatFiles(tree); -} - -export default fixLegacyCypressTsconfig; diff --git a/packages/cypress/src/migrations/update-16-8-0/cypress-13.spec.ts b/packages/cypress/src/migrations/update-16-8-0/cypress-13.spec.ts deleted file mode 100644 index 75f90593f0e7e0..00000000000000 --- a/packages/cypress/src/migrations/update-16-8-0/cypress-13.spec.ts +++ /dev/null @@ -1,243 +0,0 @@ -import { Tree, addProjectConfiguration, readJson } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from 'nx/src/devkit-testing-exports'; -import { updateToCypress13 } from './cypress-13'; - -describe('Cypress 13', () => { - let tree: Tree; - beforeEach(() => { - tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); - }); - - it('should update deps to cypress v13', async () => { - setup(tree, { name: 'my-app' }); - - await updateToCypress13(tree); - expect(readJson(tree, 'package.json').devDependencies.cypress).toEqual( - '^13.0.0' - ); - }); - - it('should update videoUploadOnPasses from config w/setupNodeEvents', async () => { - setup(tree, { name: 'my-app-video-upload-on-passes' }); - await updateToCypress13(tree); - expect( - tree.read('apps/my-app-video-upload-on-passes/cypress.config.ts', 'utf-8') - ).toMatchInlineSnapshot(` - "import fs from 'fs'; - - import { defineConfig } from 'cypress'; - import { nxE2EPreset } from '@nx/cypress/plugins/cypress-preset'; - import { nxComponentTestingPreset } from '@nx/react/plugins/component-testing'; - - export default defineConfig({ - something: 'blah', - // nodeVersion: 'system', - // videoUploadOnPasses: false , - e2e: { - ...nxE2EPreset(__filename), - setupNodeEvents(on, config) { - const a = ''; - removePassedSpecs(on); - }, - }, - component: { - ...nxComponentTestingPreset(__filename), - setupNodeEvents: (on, config) => { - const b = ''; - removePassedSpecs(on); - }, - }, - }); - - /** - * Delete videos for specs that do not contain failing or retried tests. - * This function is to be used in the 'setupNodeEvents' configuration option as a replacement to - * 'videoUploadOnPasses' which has been removed. - * - * https://docs.cypress.io/guides/guides/screenshots-and-videos#Delete-videos-for-specs-without-failing-or-retried-tests - **/ - function removePassedSpecs(on) { - on('after:spec', (spec, results) => { - if (results && results.vide) { - const hasFailures = results.tests.some((t) => - t.attempts.some((a) => a.state === 'failed') - ); - - if (!hasFailures) { - fs.unlinkSync(results.video); - } - } - }); - } - " - `); - }); - it('should remove nodeVersion from config', async () => { - setup(tree, { name: 'my-app-node-version' }); - await updateToCypress13(tree); - expect(tree.read('apps/my-app-node-version/cypress.config.ts', 'utf-8')) - .toMatchInlineSnapshot(` - "import fs from 'fs'; - - import { defineConfig } from 'cypress'; - import { nxE2EPreset } from '@nx/cypress/plugins/cypress-preset'; - import { nxComponentTestingPreset } from '@nx/react/plugins/component-testing'; - - export default defineConfig({ - something: 'blah', - // nodeVersion: 'system', - // videoUploadOnPasses: false , - e2e: { - ...nxE2EPreset(__filename), - setupNodeEvents(on, config) { - const a = ''; - removePassedSpecs(on); - }, - }, - component: { - ...nxComponentTestingPreset(__filename), - setupNodeEvents: (on, config) => { - const b = ''; - removePassedSpecs(on); - }, - }, - }); - - /** - * Delete videos for specs that do not contain failing or retried tests. - * This function is to be used in the 'setupNodeEvents' configuration option as a replacement to - * 'videoUploadOnPasses' which has been removed. - * - * https://docs.cypress.io/guides/guides/screenshots-and-videos#Delete-videos-for-specs-without-failing-or-retried-tests - **/ - function removePassedSpecs(on) { - on('after:spec', (spec, results) => { - if (results && results.vide) { - const hasFailures = results.tests.some((t) => - t.attempts.some((a) => a.state === 'failed') - ); - - if (!hasFailures) { - fs.unlinkSync(results.video); - } - } - }); - } - " - `); - }); - - it('should comment about overriding readFile command', async () => { - setup(tree, { name: 'my-app-read-file' }); - const testContent = `describe('something', () => { - it('should do the thing', () => { - cy.readFile('my-data.json').its('name').should('eq', 'Nx'); - }); -}); -`; - tree.write('apps/my-app-read-file/src/something.cy.ts', testContent); - - tree.write( - 'apps/my-app-read-file/cypress/support/commands.ts', - `declare namespace Cypress { - interface Chainable { - login(email: string, password: string): void; - } -} -// -// -- This is a parent command -- -Cypress.Commands.add('login', (email, password) => { - console.log('Custom command example: Login', email, password); -}); -Cypress.Commands.overwrite('readFile', () => {}); - -` - ); - await updateToCypress13(tree); - - expect( - tree.read('apps/my-app-read-file/src/something.cy.ts', 'utf-8') - ).toEqual(testContent); - expect( - tree.read('apps/my-app-read-file/cypress/support/commands.ts', 'utf-8') - ).toMatchInlineSnapshot(` - "declare namespace Cypress { - interface Chainable { - login(email: string, password: string): void; - } - } - // - // -- This is a parent command -- - Cypress.Commands.add('login', (email, password) => { - console.log('Custom command example: Login', email, password); - }); - /** - * TODO(@nx/cypress): This command can no longer be overridden - * Consider using a different name like 'custom_readFile' - * More info: https://docs.cypress.io/guides/references/migration-guide#readFile-can-no-longer-be-overwritten-with-CypressCommandsoverwrite - **/ - Cypress.Commands.overwrite('readFile', () => {}); - " - `); - }); -}); - -function setup(tree: Tree, options: { name: string }) { - tree.write( - `apps/${options.name}/cypress.config.ts`, - ` -import { defineConfig} from 'cypress'; -import { nxE2EPreset } from '@nx/cypress/plugins/cypress-preset'; -import { nxComponentTestingPreset } from '@nx/react/plugins/component-testing'; - -export default defineConfig({ - something: 'blah', - nodeVersion: 'system', - videoUploadOnPasses: false, - e2e: { - ...nxE2EPreset(__filename), - videoUploadOnPasses: false, - nodeVersion: 'bundled', - setupNodeEvents(on, config) { - const a = ''; - }, - }, - component: { - ...nxComponentTestingPreset(__filename), - videoUploadOnPasses: false, - nodeVersion: 'something', - setupNodeEvents: (on, config) => { - const b = ''; - } - }, -}) -` - ); - tree.write( - 'package.json', - JSON.stringify({ devDependencies: { cypress: '^12.16.0' } }) - ); - addProjectConfiguration(tree, options.name, { - root: `apps/${options.name}`, - sourceRoot: `apps/${options.name}/src`, - targets: { - e2e: { - executor: '@nx/cypress:cypress', - options: { - testingType: 'e2e', - cypressConfig: `apps/${options.name}/cypress.config.ts`, - devServerTarget: 'app:serve', - }, - }, - 'component-test': { - executor: '@nx/cypress:cypress', - options: { - testingType: 'component', - cypressConfig: `apps/${options.name}/ct-cypress.config.ts`, - skipServe: true, - devServerTarget: 'app:build', - }, - }, - }, - }); -} diff --git a/packages/cypress/src/migrations/update-16-8-0/cypress-13.ts b/packages/cypress/src/migrations/update-16-8-0/cypress-13.ts deleted file mode 100644 index 2320473555e766..00000000000000 --- a/packages/cypress/src/migrations/update-16-8-0/cypress-13.ts +++ /dev/null @@ -1,246 +0,0 @@ -import { - updateJson, - installPackagesTask, - getProjects, - visitNotIgnoredFiles, - formatFiles, - type Tree, -} from '@nx/devkit'; -import { installedCypressVersion } from '../../utils/cypress-version'; -import { - isObjectLiteralExpression, - isCallExpression, - type CallExpression, - type MethodDeclaration, - type PropertyAccessExpression, - type PropertyAssignment, -} from 'typescript'; -import { tsquery } from '@phenomnomnominal/tsquery'; -import { forEachExecutorOptions } from '@nx/devkit/src/generators/executor-options-utils'; -import type { CypressExecutorOptions } from '../../executors/cypress/cypress.impl'; - -const JS_TS_FILE_MATCHER = /\.[jt]sx?$/; - -export async function updateToCypress13(tree: Tree) { - if (installedCypressVersion() < 12) { - return; - } - - const projects = getProjects(tree); - - forEachExecutorOptions( - tree, - '@nx/cypress:cypress', - (options, projectName) => { - if (!options.cypressConfig || !tree.exists(options.cypressConfig)) { - return; - } - const projectConfig = projects.get(projectName); - - removeNodeVersionOption(tree, options.cypressConfig); - removeVideoUploadOnPassesOption(tree, options.cypressConfig); - - visitNotIgnoredFiles(tree, projectConfig.root, (filePath) => { - if (!JS_TS_FILE_MATCHER.test(filePath)) { - return; - } - shouldNotOverrideReadFile(tree, filePath); - }); - } - ); - - updateJson(tree, 'package.json', (json) => { - json.devDependencies ??= {}; - json.devDependencies.cypress = '^13.0.0'; - return json; - }); - - await formatFiles(tree); -} - -function removeVideoUploadOnPassesOption(tree: Tree, configPath: string) { - const config = tree.read(configPath, 'utf-8'); - const isUsingDeprecatedOption = - tsquery.query(config, getPropertyQuery('videoUploadOnPasses'))?.length > 0; - - if (!isUsingDeprecatedOption) { - return; - } - - const importStatement = configPath.endsWith('.ts') - ? "import fs from 'fs';" - : "const fs = require('fs');"; - - const replacementFunction = `/** -* Delete videos for specs that do not contain failing or retried tests. -* This function is to be used in the 'setupNodeEvents' configuration option as a replacement to -* 'videoUploadOnPasses' which has been removed. -* -* https://docs.cypress.io/guides/guides/screenshots-and-videos#Delete-videos-for-specs-without-failing-or-retried-tests -**/ -function removePassedSpecs(on) { - on('after:spec', (spec, results) => { - if(results && results.vide) { - const hasFailures = results.tests.some(t => t.attempts.some(a => a.state === 'failed')); - - if(!hasFailures) { - fs.unlinkSync(results.video); - } - } - }) -}`; - - const withReplacementFn = `${importStatement}\n${config}\n${replacementFunction}`; - - // setupNodeEvents can be a property or method. - const setupNodeEventsQuery = - 'ExportAssignment ObjectLiteralExpression > :matches(PropertyAssignment:has(Identifier[name="setupNodeEvents"]), MethodDeclaration:has(Identifier[name="setupNodeEvents"]))'; - - const hasSetupNodeEvents = - tsquery.query(withReplacementFn, setupNodeEventsQuery)?.length > 0; - - let updatedWithSetupNodeEvents = withReplacementFn; - if (hasSetupNodeEvents) { - // if have setupNodeEvents, update existing fn to use removePassedSpecs helper and remove videoUploadOnPasses - const noVideoUploadOption = tsquery.replace( - withReplacementFn, - getPropertyQuery('videoUploadOnPasses'), - (node: PropertyAssignment) => { - if (isObjectLiteralExpression(node.initializer)) { - // is a nested config object - const key = node.name.getText().trim(); - const listOfProperties = node.initializer.properties - .map((j) => j.getText()) - .filter((j) => !j.includes('videoUploadOnPasses')) - .join(',\n'); - - return `${key}: { - ${listOfProperties} -} - `; - } else { - if (isPropertyTopLevel(node)) { - return `// ${node.getText()} `; - } - } - } - ); - - updatedWithSetupNodeEvents = tsquery.replace( - noVideoUploadOption, - `${setupNodeEventsQuery} Block`, - (node: PropertyAssignment | MethodDeclaration) => { - const blockWithoutBraces = node - .getFullText() - .trim() - .slice(1, -1) - .trim(); - return `{ - ${blockWithoutBraces} - removePassedSpecs(on); -} -`; - }, - { visitAllChildren: false } - ); - } else { - // if don't have setupNodeEvents, replace videoUploadOnPasses with setupNodeEvents method - updatedWithSetupNodeEvents = tsquery.replace( - withReplacementFn, - getPropertyQuery('videoUploadOnPasses'), - () => { - return `setupNodeEvents(on, config) { - removePassedSpecs(on); -}`; - } - ); - } - - tree.write(configPath, updatedWithSetupNodeEvents); -} - -/** - * remove the nodeVersion option from the config file - **/ -function removeNodeVersionOption(tree: Tree, configPath: string) { - const config = tree.read(configPath, 'utf-8'); - - const updated = tsquery.replace( - config, - getPropertyQuery('nodeVersion'), - (node: PropertyAssignment) => { - if (isObjectLiteralExpression(node.initializer)) { - // is a nested config object - const key = node.name.getText().trim(); - const listOfProperties = node.initializer.properties - .map((j) => j.getFullText()) - .filter((j) => !j.includes('nodeVersion')) - .join(', '); - return `${key}: { - ${listOfProperties} - }`; - } else { - if (isPropertyTopLevel(node)) { - return `// ${node.getText()}`; - } - } - } - ); - - if (updated !== config) { - tree.write(configPath, updated); - } -} - -/** - * leave a comment on all usages of overriding built-ins that are now banned - **/ -export function shouldNotOverrideReadFile(tree: Tree, filePath: string) { - const content = tree.read(filePath, 'utf-8'); - const markedOverrideUsage = tsquery.replace( - content, - 'PropertyAccessExpression:has(Identifier[name="overwrite"]):has(Identifier[name="Cypress"])', - (node: PropertyAccessExpression) => { - if (isAlreadyCommented(node)) { - return; - } - const expression = node.expression.getText().trim(); - // prevent grabbing other Cypress..defaults - - if (expression === 'Cypress.Commands') { - // get value. - const overwriteExpression = node.parent as CallExpression; - - const command = (overwriteExpression.arguments?.[0] as any)?.text; // need string without quotes - if (command === 'readFile') { - // overwrite - return `/** -* TODO(@nx/cypress): This command can no longer be overridden -* Consider using a different name like 'custom_${command}' -* More info: https://docs.cypress.io/guides/references/migration-guide#readFile-can-no-longer-be-overwritten-with-CypressCommandsoverwrite -**/ -${node.getText()}`; - } - } - } - ); - tree.write(filePath, markedOverrideUsage); -} - -function isAlreadyCommented(node: PropertyAccessExpression) { - return node.getFullText().includes('TODO(@nx/cypress)'); -} - -function isPropertyTopLevel(node: PropertyAssignment) { - return ( - node.parent && - isObjectLiteralExpression(node.parent) && - node.parent.parent && - isCallExpression(node.parent.parent) - ); -} - -const getPropertyQuery = (propertyName: string) => - `ExportAssignment ObjectLiteralExpression > PropertyAssignment:has(Identifier[name="${propertyName}"])`; - -export default updateToCypress13; diff --git a/packages/detox/migrations.json b/packages/detox/migrations.json index 38634c3853c0a6..ac23a57d3b6a62 100644 --- a/packages/detox/migrations.json +++ b/packages/detox/migrations.json @@ -1,69 +1,6 @@ { - "generators": { - "update-16-0-0-add-nx-packages": { - "cli": "nx", - "version": "16.0.0-beta.1", - "description": "Replace @nrwl/detox with @nx/detox", - "implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages" - }, - "update-16-0-0-update-detoxrc": { - "cli": "nx", - "version": "16.0.0-beta.3", - "description": "Update .detoxrc.json and jest.config.json for detox 20", - "implementation": "./src/migrations/update-16-0-0/update-detoxrc-json" - }, - "update-detoxrc-json-expo-16-1-4": { - "cli": "nx", - "version": "16.1.4-beta.0", - "description": "Update .detoxrc.json for expo", - "implementation": "./src/migrations/update-16-1-4/update-detoxrc-json-expo" - } - }, + "generators": {}, "packageJsonUpdates": { - "16.0.0": { - "version": "16.0.0-beta.3", - "packages": { - "detox": { - "version": "~20.7.0", - "alwaysAddToPackageJson": false - } - } - }, - "16.1.1": { - "version": "16.1.1-beta.0", - "packages": { - "detox": { - "version": "~20.8.0", - "alwaysAddToPackageJson": false - }, - "@config-plugins/detox": { - "version": "~5.0.1", - "alwaysAddToPackageJson": false - } - } - }, - "16.1.5": { - "version": "16.1.5-beta.0", - "packages": { - "detox": { - "version": "^20.9.0", - "alwaysAddToPackageJson": false - } - } - }, - "16.6.0": { - "version": "16.6.0-beta.6", - "packages": { - "detox": { - "version": "^20.11.1", - "alwaysAddToPackageJson": false - }, - "@config-plugins/detox": { - "version": "~6.0.0", - "alwaysAddToPackageJson": false - } - } - }, "18.0.0": { "version": "18.0.0-beta.0", "packages": { diff --git a/packages/detox/src/generators/application/application.ts b/packages/detox/src/generators/application/application.ts index b71cf5cc3bef60..3cd37e4d9998d7 100644 --- a/packages/detox/src/generators/application/application.ts +++ b/packages/detox/src/generators/application/application.ts @@ -1,4 +1,5 @@ import { formatFiles, runTasksInSerial, Tree } from '@nx/devkit'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import detoxInitGenerator from '../init/init'; import { addGitIgnoreEntry } from './lib/add-git-ignore-entry'; @@ -20,6 +21,8 @@ export async function detoxApplicationGeneratorInternal( host: Tree, schema: Schema ) { + assertNotUsingTsSolutionSetup(host, 'detox', 'application'); + const options = await normalizeOptions(host, schema); const initTask = await detoxInitGenerator(host, { diff --git a/packages/detox/src/generators/init/init.ts b/packages/detox/src/generators/init/init.ts index 543ea76ed86f9c..a66360be9f4f24 100644 --- a/packages/detox/src/generators/init/init.ts +++ b/packages/detox/src/generators/init/init.ts @@ -9,6 +9,7 @@ import { Tree, } from '@nx/devkit'; import { addPluginV1 } from '@nx/devkit/src/utils/add-plugin'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { createNodes } from '../../plugins/plugin'; import { detoxVersion, nxVersion } from '../../utils/versions'; import { Schema } from './schema'; @@ -18,6 +19,8 @@ export function detoxInitGenerator(host: Tree, schema: Schema) { } export async function detoxInitGeneratorInternal(host: Tree, schema: Schema) { + assertNotUsingTsSolutionSetup(host, 'detox', 'init'); + const tasks: GeneratorCallback[] = []; const nxJson = readNxJson(host); diff --git a/packages/detox/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts b/packages/detox/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts deleted file mode 100644 index 40759f32eab5b1..00000000000000 --- a/packages/detox/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Tree, readJson, updateJson } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import replacePackage from './update-16-0-0-add-nx-packages'; - -describe('update-16-0-0-add-nx-packages', () => { - let tree: Tree; - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - - updateJson(tree, 'package.json', (json) => { - json.devDependencies['@nrwl/detox'] = '16.0.0'; - return json; - }); - }); - - it('should remove the dependency on @nrwl/detox', async () => { - await replacePackage(tree); - - expect( - readJson(tree, 'package.json').dependencies['@nrwl/detox'] - ).not.toBeDefined(); - expect( - readJson(tree, 'package.json').devDependencies['@nrwl/detox'] - ).not.toBeDefined(); - }); - - it('should add a dependency on @nx/detox', async () => { - await replacePackage(tree); - - const packageJson = readJson(tree, 'package.json'); - const newDependencyVersion = - packageJson.devDependencies['@nx/detox'] ?? - packageJson.dependencies['@nx/detox']; - - expect(newDependencyVersion).toBeDefined(); - }); -}); diff --git a/packages/detox/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts b/packages/detox/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts deleted file mode 100644 index d549f91ae55477..00000000000000 --- a/packages/detox/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Tree, formatFiles } from '@nx/devkit'; -import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package'; - -export default async function replacePackage(tree: Tree): Promise { - replaceNrwlPackageWithNxPackage(tree, '@nrwl/detox', '@nx/detox'); - - await formatFiles(tree); -} diff --git a/packages/detox/src/migrations/update-16-0-0/update-detoxrc-json.spec.ts b/packages/detox/src/migrations/update-16-0-0/update-detoxrc-json.spec.ts deleted file mode 100644 index 95f1221b3e998b..00000000000000 --- a/packages/detox/src/migrations/update-16-0-0/update-detoxrc-json.spec.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { addProjectConfiguration, readJson, Tree } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; - -import update from './update-detoxrc-json'; - -describe('Update detoxrc for detox 20', () => { - let tree: Tree; - - beforeEach(async () => { - tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); - addProjectConfiguration(tree, 'products', { - root: 'apps/products', - sourceRoot: 'apps/products/src', - targets: { - 'test-ios': { - executor: '@nx/detox:test', - }, - }, - }); - tree.write('apps/products/jest.config.json', `{"transform": {}}`); - tree.write('apps/products/.detoxrc.json', '{}'); - }); - - it(`should update jest.config.json`, async () => { - await update(tree); - - const jestConfig = readJson(tree, 'apps/products/jest.config.json'); - expect(jestConfig).toEqual({ - rootDir: '.', - testMatch: [ - '/src/**/*.test.ts?(x)', - '/src/**/*.spec.ts?(x)', - ], - globalSetup: 'detox/runners/jest/globalSetup', - globalTeardown: 'detox/runners/jest/globalTeardown', - reporter: ['detox/runners/jest/reporter'], - verbose: true, - }); - }); - - it(`should update .detoxrc.json`, async () => { - await update(tree); - - const detoxrcJson = readJson(tree, 'apps/products/.detoxrc.json'); - expect(detoxrcJson).toEqual({ - testRunner: { - args: { - $0: 'jest', - config: './jest.config.json', - }, - jest: { - setupTimeout: 120000, - }, - }, - }); - }); -}); diff --git a/packages/detox/src/migrations/update-16-0-0/update-detoxrc-json.ts b/packages/detox/src/migrations/update-16-0-0/update-detoxrc-json.ts deleted file mode 100644 index e588cc3bf6722b..00000000000000 --- a/packages/detox/src/migrations/update-16-0-0/update-detoxrc-json.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { - Tree, - formatFiles, - getProjects, - updateJson, - ProjectConfiguration, -} from '@nx/devkit'; - -/** - * Update .detoxrc.json under detox project: - * - remove deprecated keys: testRunner - * - update keys: runnerConfig - * Update jest.config.json under detox project: - * - remove key: transform - * - add key: rootDir, testMatch, reporter, globalSetup, globalTeardown, verbose - */ -export default async function update(tree: Tree) { - const projects = getProjects(tree); - - projects.forEach((project) => { - if (project.targets?.['test-ios']?.executor !== '@nx/detox:test') return; - updateDetoxrcJson(tree, project); - updateJestConfigJson(tree, project); - }); - - await formatFiles(tree); -} - -function updateDetoxrcJson(host: Tree, project: ProjectConfiguration) { - const detoxConfigPath = `${project.root}/.detoxrc.json`; - if (!host.exists(detoxConfigPath)) return; - updateJson(host, detoxConfigPath, (json) => { - json.testRunner = { - args: { - $0: 'jest', - config: './jest.config.json', - }, - jest: { - setupTimeout: 120000, - }, - }; - if (json.runnerConfig) { - delete json.runnerConfig; - } - return json; - }); -} - -function updateJestConfigJson(host: Tree, project: ProjectConfiguration) { - const jestConfigPath = `${project.root}/jest.config.json`; - if (!host.exists(jestConfigPath)) return; - updateJson(host, jestConfigPath, (json) => { - if (json.transform) { - delete json.transform; - } - if (!json.rootDir) { - json.rootDir = '.'; - } - if (!json.testMatch) { - json.testMatch = [ - '/src/**/*.test.ts?(x)', - '/src/**/*.spec.ts?(x)', - ]; - } - json.reporter = ['detox/runners/jest/reporter']; - json.globalSetup = 'detox/runners/jest/globalSetup'; - json.globalTeardown = 'detox/runners/jest/globalTeardown'; - json.verbose = true; - return json; - }); -} diff --git a/packages/detox/src/migrations/update-16-1-4/update-detoxrc-json-expo.spec.ts b/packages/detox/src/migrations/update-16-1-4/update-detoxrc-json-expo.spec.ts deleted file mode 100644 index 9a6121b47dcd9a..00000000000000 --- a/packages/detox/src/migrations/update-16-1-4/update-detoxrc-json-expo.spec.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { addProjectConfiguration, readJson, Tree } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; - -import update from './update-detoxrc-json-expo'; - -describe('Update detoxrc for expo projects', () => { - let tree: Tree; - - beforeEach(async () => { - tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); - addProjectConfiguration(tree, 'products', { - root: 'apps/products', - sourceRoot: 'apps/products/src', - targets: { - 'test-ios': { - executor: '@nx/detox:test', - options: { - detoxConfiguration: 'ios.sim.eas', - }, - }, - 'build-ios': { - executor: '@nx/detox:build', - options: { - detoxConfiguration: 'random value', - }, - }, - 'test-android': { - executor: '@nx/detox:test', - options: { - detoxConfiguration: 'android.sim.eas', - }, - }, - 'build-android': { - executor: '@nx/detox:build', - options: { - detoxConfiguration: 'random value', - }, - }, - }, - }); - tree.write('apps/products/jest.config.json', `{"transform": {}}`); - tree.write( - 'apps/products/.detoxrc.json', - `{"apps": {"ios.eas": {}, "android.eas": {}, "ios.local": {}, "android.local": {}}}` - ); - }); - - it(`should update .detoxrc.json`, async () => { - await update(tree); - - const detoxrcJson = readJson(tree, 'apps/products/.detoxrc.json'); - expect(detoxrcJson).toEqual({ - apps: { - 'ios.eas': { - build: - 'npx nx run products:download --platform ios --distribution simulator --output=../../apps/products/dist/', - }, - 'android.eas': { - build: - 'npx nx run products:download --platform android --distribution simulator --output=../../apps/products/dist/', - type: 'android.apk', - }, - 'ios.local': { - build: - 'npx nx run products:build --platform ios --profile preview --wait --local --no-interactive --output=../../apps/products/dist/Products.tar.gz', - }, - 'android.local': { - build: - 'npx nx run products:build --platform android --profile preview --wait --local --no-interactive --output=../../apps/products/dist/Products.apk', - type: 'android.apk', - }, - }, - }); - }); - - it(`should update project.json`, async () => { - await update(tree); - - const projectJson = readJson(tree, 'apps/products/project.json'); - expect(projectJson).toEqual({ - $schema: '../../node_modules/nx/schemas/project-schema.json', - name: 'products', - sourceRoot: 'apps/products/src', - targets: { - 'build-android': { - executor: '@nx/detox:build', - options: { - detoxConfiguration: 'android.sim.eas', - }, - }, - 'build-ios': { - executor: '@nx/detox:build', - options: { - detoxConfiguration: 'ios.sim.eas', - }, - }, - 'test-android': { - configurations: { - bare: { - buildTarget: 'products:build-android:bare', - detoxConfiguration: 'android.emu.debug', - }, - local: { - buildTarget: 'products:build-android:local', - detoxConfiguration: 'android.emu.local', - }, - production: { - buildTarget: 'products:build-android:production', - detoxConfiguration: 'android.emu.release', - }, - }, - executor: '@nx/detox:test', - options: { - buildTarget: 'products:build-android', - detoxConfiguration: 'android.sim.eas', - }, - }, - 'test-ios': { - executor: '@nx/detox:test', - options: { - detoxConfiguration: 'ios.sim.eas', - }, - }, - }, - }); - }); -}); diff --git a/packages/detox/src/migrations/update-16-1-4/update-detoxrc-json-expo.ts b/packages/detox/src/migrations/update-16-1-4/update-detoxrc-json-expo.ts deleted file mode 100644 index 8f4bdf951dd86e..00000000000000 --- a/packages/detox/src/migrations/update-16-1-4/update-detoxrc-json-expo.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { - Tree, - formatFiles, - getProjects, - updateJson, - ProjectConfiguration, - offsetFromRoot, - detectPackageManager, - getPackageManagerCommand, - names, - updateProjectConfiguration, -} from '@nx/devkit'; - -/** - * Update .detoxrc.json under detox project for expo: - * - fix the eas build command - * - fix the local build command - * - update project.json targets - */ -export default async function update(tree: Tree) { - const projects = getProjects(tree); - - projects.forEach((project) => { - if (project.targets?.['test-ios']?.executor !== '@nx/detox:test') return; - updateDetoxrcJson(tree, project); - updateProjectJson(tree, project); - }); - - await formatFiles(tree); -} - -function updateDetoxrcJson(host: Tree, project: ProjectConfiguration) { - const detoxConfigPath = `${project.root}/.detoxrc.json`; - const projectName = project.name?.endsWith('-e2e') - ? project.name.substring(0, project.name.indexOf('-e2e')) - : project.name; - const appRoot = getProjects(host).get(projectName)?.root; - const appName = names(projectName).className; - const offset = offsetFromRoot(project.root); - const exec = getPackageManagerCommand(detectPackageManager(host.root)).exec; - if (!host.exists(detoxConfigPath)) return; - updateJson(host, detoxConfigPath, (json) => { - if (json.apps?.['ios.eas']) { - json.apps[ - 'ios.eas' - ].build = `${exec} nx run ${projectName}:download --platform ios --distribution simulator --output=${offset}${appRoot}/dist/`; - } - if (json.apps?.['android.eas']) { - json.apps[ - 'android.eas' - ].build = `${exec} nx run ${projectName}:download --platform android --distribution simulator --output=${offset}${appRoot}/dist/`; - json.apps['android.eas'].type = 'android.apk'; - } - if (json.apps?.['ios.local']) { - json.apps[ - 'ios.local' - ].build = `${exec} nx run ${projectName}:build --platform ios --profile preview --wait --local --no-interactive --output=${offset}${appRoot}/dist/${appName}.tar.gz`; - } - if (json.apps?.['android.local']) { - json.apps[ - 'android.local' - ].build = `${exec} nx run ${projectName}:build --platform android --profile preview --wait --local --no-interactive --output=${offset}${appRoot}/dist/${appName}.apk`; - json.apps['android.local'].type = 'android.apk'; - } - return json; - }); -} - -function updateProjectJson(host: Tree, project: ProjectConfiguration) { - if ( - project.targets?.['test-ios']?.options?.detoxConfiguration == 'ios.sim.eas' - ) { - project.targets['build-ios'].options.detoxConfiguration = 'ios.sim.eas'; - } - if ( - project.targets?.['test-android']?.options?.detoxConfiguration == - 'android.sim.eas' - ) { - project.targets['build-android'].options.detoxConfiguration = - 'android.sim.eas'; - project.targets['test-android'] = { - executor: '@nx/detox:test', - options: { - detoxConfiguration: 'android.sim.eas', - buildTarget: `${project.name}:build-android`, - }, - configurations: { - local: { - detoxConfiguration: 'android.emu.local', - buildTarget: `${project.name}:build-android:local`, - }, - bare: { - detoxConfiguration: 'android.emu.debug', - buildTarget: `${project.name}:build-android:bare`, - }, - production: { - detoxConfiguration: 'android.emu.release', - buildTarget: `${project.name}:build-android:production`, - }, - }, - }; - } - updateProjectConfiguration(host, project.name, project); -} diff --git a/packages/devkit/migrations.json b/packages/devkit/migrations.json index 8b14bc3d2bf767..c0b5008c37383c 100644 --- a/packages/devkit/migrations.json +++ b/packages/devkit/migrations.json @@ -1,18 +1,5 @@ { - "generators": { - "update-16-0-0-add-nx-packages": { - "cli": "nx", - "version": "16.0.0-beta.1", - "description": "Replace @nrwl/devkit with @nx/devkit", - "implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages" - }, - "update-16-9-0-migrate-mf-usage-to-webpack": { - "cli": "nx", - "version": "16.9.0-beta.1", - "description": "Replace imports of Module Federation utils frm @nx/devkit to @nx/webpack", - "implementation": "./src/migrations/update-16-9-0/migrate-mf-util-usage" - } - }, + "generators": {}, "packageJsonUpdates": {}, "version": "0.1" } diff --git a/packages/devkit/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts b/packages/devkit/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts deleted file mode 100644 index 545633098521d6..00000000000000 --- a/packages/devkit/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { assertRunsAgainstNxRepo } from 'nx/src/internal-testing-utils/run-migration-against-this-workspace'; -import { createTreeWithEmptyWorkspace } from 'nx/src/generators/testing-utils/create-tree-with-empty-workspace'; -import { Tree } from 'nx/src/generators/tree'; -import { readJson, updateJson } from 'nx/src/generators/utils/json'; -import replacePackage from './update-16-0-0-add-nx-packages'; - -describe('update-16-0-0-add-nx-packages', () => { - let tree: Tree; - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - - updateJson(tree, 'package.json', (json) => { - json.devDependencies['@nrwl/devkit'] = '16.0.0'; - return json; - }); - }); - - it('should remove the dependency on @nrwl/devkit', async () => { - await replacePackage(tree); - - expect( - readJson(tree, 'package.json').dependencies['@nrwl/devkit'] - ).not.toBeDefined(); - expect( - readJson(tree, 'package.json').devDependencies['@nrwl/devkit'] - ).not.toBeDefined(); - }); - - it('should add a dependency on @nx/devkit', async () => { - await replacePackage(tree); - - const packageJson = readJson(tree, 'package.json'); - const newDependencyVersion = - packageJson.devDependencies['@nx/devkit'] ?? - packageJson.dependencies['@nx/devkit']; - - expect(newDependencyVersion).toBeDefined(); - }); - - assertRunsAgainstNxRepo(replacePackage); -}); diff --git a/packages/devkit/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts b/packages/devkit/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts deleted file mode 100644 index 6a74372f31a65e..00000000000000 --- a/packages/devkit/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { Tree } from 'nx/src/devkit-exports'; -import { formatFiles } from '../../generators/format-files'; -import { replaceNrwlPackageWithNxPackage } from '../../utils/replace-package'; - -export default async function replacePackage(tree: Tree): Promise { - await replaceNrwlPackageWithNxPackage(tree, '@nrwl/devkit', '@nx/devkit'); - - await formatFiles(tree); -} diff --git a/packages/devkit/src/migrations/update-16-9-0/migrate-mf-util-usage.spec.ts b/packages/devkit/src/migrations/update-16-9-0/migrate-mf-util-usage.spec.ts deleted file mode 100644 index 7342e281af0065..00000000000000 --- a/packages/devkit/src/migrations/update-16-9-0/migrate-mf-util-usage.spec.ts +++ /dev/null @@ -1,231 +0,0 @@ -import { createTreeWithEmptyWorkspace } from 'nx/src/generators/testing-utils/create-tree-with-empty-workspace'; -import { stripIndents } from 'nx/src/utils/strip-indents'; -import { readJson } from 'nx/src/generators/utils/json'; - -import migrateMfUtilUsage from './migrate-mf-util-usage'; - -describe('migrate-mf-util-usage', () => { - it('should do nothing if it does not find files using the mf public api', async () => { - // ARRANGE - const testFileContents = `${stripIndents`import { readFileSync } from 'fs'; - const file = readFileSync('test.ts');`}\n`; - - const tree = createTreeWithEmptyWorkspace(); - tree.write('test.ts', testFileContents); - - // ACT - await migrateMfUtilUsage(tree); - - // ASSERT - expect(tree.read('test.ts', 'utf-8')).toEqual(testFileContents); - }); - - it('should do nothing if it does not find files using the mf public api even if they use devkit', async () => { - // ARRANGE - const testFileContents = `${stripIndents`import { readJson } from '@nx/devkit'; - const file = readJson('test.json');`}\n`; - - const tree = createTreeWithEmptyWorkspace(); - tree.write('test.ts', testFileContents); - - // ACT - await migrateMfUtilUsage(tree); - - // ASSERT - expect(tree.read('test.ts', 'utf-8')).toEqual(testFileContents); - }); - - it('should replace imports to utils from devkit with webpack', async () => { - // ARRANGE - const testFileContents = stripIndents`import {ModuleFederationConfig} from '@nx/devkit'; - const config: ModuleFederationConfig = {}; - `; - const expectedTestFileContents = `${stripIndents`import { ModuleFederationConfig } from '@nx/webpack'; - const config: ModuleFederationConfig = {};`}\n`; - - const tree = createTreeWithEmptyWorkspace(); - tree.write('test.ts', testFileContents); - - // ACT - await migrateMfUtilUsage(tree); - - // ASSERT - expect(tree.read('test.ts', 'utf-8')).toEqual(expectedTestFileContents); - expect( - readJson(tree, 'package.json').devDependencies['@nx/webpack'] - ).toBeDefined(); - }); - - it('should extract imports to utils from devkit and replace with imports from webpack', async () => { - // ARRANGE - const testFileContents = stripIndents`import {joinPathFragments, ModuleFederationConfig} from '@nx/devkit'; - const config: ModuleFederationConfig = {}; - `; - const expectedTestFileContents = `${stripIndents`import { joinPathFragments } from '@nx/devkit'; - import { ModuleFederationConfig } from '@nx/webpack'; - const config: ModuleFederationConfig = {};`}\n`; - - const tree = createTreeWithEmptyWorkspace(); - tree.write('test.ts', testFileContents); - - // ACT - await migrateMfUtilUsage(tree); - - // ASSERT - expect(tree.read('test.ts', 'utf-8')).toEqual(expectedTestFileContents); - expect( - readJson(tree, 'package.json').devDependencies['@nx/webpack'] - ).toBeDefined(); - }); - - it('should extract imports to utils from devkit and replace with imports from webpack, even with multiple devkit imports', async () => { - // ARRANGE - const testFileContents = stripIndents`import {joinPathFragments, ModuleFederationConfig} from '@nx/devkit'; - import {readJson, WorkspaceLibrary} from '@nx/devkit'; - const config: ModuleFederationConfig = {}; - `; - const expectedTestFileContents = `${stripIndents`import { joinPathFragments } from '@nx/devkit'; - import { readJson } from '@nx/devkit'; - import { ModuleFederationConfig, WorkspaceLibrary } from '@nx/webpack'; - const config: ModuleFederationConfig = {};`}\n`; - - const tree = createTreeWithEmptyWorkspace(); - tree.write('test.ts', testFileContents); - - // ACT - await migrateMfUtilUsage(tree); - - // ASSERT - expect(tree.read('test.ts', 'utf-8')).toEqual(expectedTestFileContents); - expect( - readJson(tree, 'package.json').devDependencies['@nx/webpack'] - ).toBeDefined(); - }); - - describe('require()', () => { - it('should do nothing if it does not find files using the mf public api', async () => { - // ARRANGE - const testFileContents = `${stripIndents`const { readFileSync } = require('fs'); - const file = readFileSync('test.ts');`}\n`; - - const tree = createTreeWithEmptyWorkspace(); - tree.write('test.ts', testFileContents); - - // ACT - await migrateMfUtilUsage(tree); - - // ASSERT - expect(tree.read('test.ts', 'utf-8')).toEqual(testFileContents); - }); - - it('should do nothing if it does not find files using the mf public api even if they use devkit', async () => { - // ARRANGE - const testFileContents = `${stripIndents`const { readJson } = require('@nx/devkit'); - const file = readJson('test.json');`}\n`; - - const tree = createTreeWithEmptyWorkspace(); - tree.write('test.ts', testFileContents); - - // ACT - await migrateMfUtilUsage(tree); - - // ASSERT - expect(tree.read('test.ts', 'utf-8')).toEqual(testFileContents); - }); - - it('should replace imports to utils from devkit with webpack', async () => { - // ARRANGE - const testFileContents = stripIndents`const {ModuleFederationConfig} = require('@nx/devkit'); - const config: ModuleFederationConfig = {}; - `; - const expectedTestFileContents = `${stripIndents`const { ModuleFederationConfig } = require('@nx/webpack'); - const config: ModuleFederationConfig = {};`}\n`; - - const tree = createTreeWithEmptyWorkspace(); - tree.write('test.ts', testFileContents); - - // ACT - await migrateMfUtilUsage(tree); - - // ASSERT - expect(tree.read('test.ts', 'utf-8')).toEqual(expectedTestFileContents); - expect( - readJson(tree, 'package.json').devDependencies['@nx/webpack'] - ).toBeDefined(); - }); - - it('should extract imports to utils from devkit and replace with imports from webpack', async () => { - // ARRANGE - const testFileContents = stripIndents`const {joinPathFragments, ModuleFederationConfig} = require("@nx/devkit"); - const config: ModuleFederationConfig = {}; - `; - const expectedTestFileContents = `${stripIndents`const { joinPathFragments } = require('@nx/devkit'); - const { ModuleFederationConfig } = require('@nx/webpack'); - const config: ModuleFederationConfig = {};`}\n`; - - const tree = createTreeWithEmptyWorkspace(); - tree.write('test.ts', testFileContents); - - // ACT - await migrateMfUtilUsage(tree); - - // ASSERT - expect(tree.read('test.ts', 'utf-8')).toEqual(expectedTestFileContents); - expect( - readJson(tree, 'package.json').devDependencies['@nx/webpack'] - ).toBeDefined(); - }); - - it('should extract imports to utils from devkit and replace with imports from webpack, even with multiple devkit imports', async () => { - // ARRANGE - const testFileContents = stripIndents`const {joinPathFragments, ModuleFederationConfig} = require('@nx/devkit'); - const {readJson, WorkspaceLibrary} = require('@nx/devkit'); - const config: ModuleFederationConfig = {}; - `; - const expectedTestFileContents = `${stripIndents`const { joinPathFragments } = require('@nx/devkit'); - const { readJson } = require('@nx/devkit'); - const { ModuleFederationConfig, WorkspaceLibrary } = require('@nx/webpack'); - const config: ModuleFederationConfig = {};`}\n`; - - const tree = createTreeWithEmptyWorkspace(); - tree.write('test.ts', testFileContents); - - // ACT - await migrateMfUtilUsage(tree); - - // ASSERT - expect(tree.read('test.ts', 'utf-8')).toEqual(expectedTestFileContents); - expect( - readJson(tree, 'package.json').devDependencies['@nx/webpack'] - ).toBeDefined(); - }); - }); - - it('should replace imports to utils from devkit with webpack in JSDoc comments', async () => { - // ARRANGE - const testFileContents = stripIndents` - /** - * @type {import('@nx/devkit').ModuleFederationConfig} - **/ - const config = {}; - `; - - const tree = createTreeWithEmptyWorkspace(); - tree.write('test.js', testFileContents); - - // ACT - await migrateMfUtilUsage(tree); - - // ASSERT - expect(tree.read('test.js', 'utf-8')).toMatchInlineSnapshot(` - "/** - * @type {import('@nx/webpack').ModuleFederationConfig} - **/ - const config = {}; - " - `); - expect( - readJson(tree, 'package.json').devDependencies['@nx/webpack'] - ).toBeDefined(); - }); -}); diff --git a/packages/devkit/src/migrations/update-16-9-0/migrate-mf-util-usage.ts b/packages/devkit/src/migrations/update-16-9-0/migrate-mf-util-usage.ts deleted file mode 100644 index ec28fd55167729..00000000000000 --- a/packages/devkit/src/migrations/update-16-9-0/migrate-mf-util-usage.ts +++ /dev/null @@ -1,321 +0,0 @@ -import type { Node, SyntaxKind } from 'typescript'; -import { visitNotIgnoredFiles } from '../../generators/visit-not-ignored-files'; -import { formatFiles } from '../../generators/format-files'; -import { - addDependenciesToPackageJson, - ensurePackage, -} from '../../utils/package-json'; -import { typescriptVersion } from '../../utils/versions'; - -import { GeneratorCallback, readJson, Tree } from 'nx/src/devkit-exports'; - -let tsModule: typeof import('typescript'); - -const MODULE_FEDERATION_PUBLIC_TOKENS = [ - 'AdditionalSharedConfig', - 'ModuleFederationConfig', - 'SharedLibraryConfig', - 'SharedWorkspaceLibraryConfig', - 'WorkspaceLibrary', - 'SharedFunction', - 'WorkspaceLibrarySecondaryEntryPoint', - 'Remotes', - 'ModuleFederationLibrary', - 'applySharedFunction', - 'applyAdditionalShared', - 'getNpmPackageSharedConfig', - 'shareWorkspaceLibraries', - 'sharePackages', - 'mapRemotes', - 'mapRemotesForSSR', - 'getDependentPackagesForProject', - 'readRootPackageJson', -]; - -export default async (tree: Tree): Promise => { - let hasFileToMigrate = false; - visitNotIgnoredFiles(tree, '/', (path) => { - if (!path.endsWith('.ts') && !path.endsWith('.js')) { - return; - } - - let fileContents = tree.read(path, 'utf-8'); - if ( - MODULE_FEDERATION_PUBLIC_TOKENS.every( - (token) => !fileContents.includes(token) - ) - ) { - return; - } - - hasFileToMigrate = true; - - fileContents = replaceTSImports(tree, path, fileContents); - fileContents = replaceRequireCalls(tree, path, fileContents); - fileContents = replaceJSDoc(tree, path, fileContents); - tree.write(path, fileContents); - }); - - if (hasFileToMigrate) { - await formatFiles(tree); - - const pkgJson = readJson(tree, 'package.json'); - const nxVersion = - pkgJson.devDependencies?.['nx'] ?? - pkgJson.dependencies?.['nx'] ?? - '17.0.0'; - return addDependenciesToPackageJson(tree, {}, { '@nx/webpack': nxVersion }); - } -}; - -function replaceJSDoc(tree: Tree, path: string, fileContents: string) { - let newFileContents = fileContents; - for (const token of MODULE_FEDERATION_PUBLIC_TOKENS) { - newFileContents = newFileContents.replaceAll( - new RegExp( - `(@type)+\\s({)+(\\s)*(import\\(('|")+@nx\/devkit('|")+\\)\.)+(${token})+\\s*(})+`, - 'g' - ), - `@type {import('@nx/webpack').${token}}` - ); - } - - return newFileContents; -} - -function replaceRequireCalls( - tree: Tree, - path: string, - fileContents: string -): string { - if (!tsModule) { - tsModule = ensurePackage('typescript', typescriptVersion); - } - - const sourceFile = tsModule.createSourceFile( - path, - fileContents, - tsModule.ScriptTarget.Latest, - true - ); - - const allDevkitRequires = findNodes( - sourceFile, - tsModule.SyntaxKind.VariableStatement - ) - .filter((node) => - [`require("@nx/devkit")`, `require('@nx/devkit')`].some((r) => - node.getText().includes(r) - ) - ) - .filter( - (node) => findNodes(node, tsModule.SyntaxKind.ObjectBindingPattern).length - ); - - const mfUtilRequires = allDevkitRequires.filter((node) => - MODULE_FEDERATION_PUBLIC_TOKENS.some((token) => - node.getText().includes(token) - ) - ); - - if (!mfUtilRequires.length) { - return fileContents; - } - - const mfUtilTokens = mfUtilRequires.map((node) => { - const allTokens = findNodes(node, tsModule.SyntaxKind.BindingElement); - const mfTokens = allTokens.filter((node) => - MODULE_FEDERATION_PUBLIC_TOKENS.some((token) => node.getText() === token) - ); - - return { - requireNode: node, - onlyMf: allTokens.length === mfTokens.length, - mfTokens, - }; - }); - - const changes: { - startPosition: number; - endPosition?: number; - content: string; - }[] = []; - for (const mfUtilRequireData of mfUtilTokens) { - if (mfUtilRequireData.onlyMf) { - changes.push({ - startPosition: mfUtilRequireData.requireNode.getStart(), - endPosition: mfUtilRequireData.requireNode.getEnd(), - content: '', - }); - } else { - for (const mfToken of mfUtilRequireData.mfTokens) { - const replaceTrailingComma = - mfToken.getText().charAt(mfToken.getEnd() + 1) === ','; - changes.push({ - startPosition: mfToken.getStart(), - endPosition: replaceTrailingComma - ? mfToken.getEnd() + 1 - : mfToken.getEnd(), - content: '', - }); - } - } - } - - changes.push({ - startPosition: mfUtilTokens[mfUtilTokens.length - 1].requireNode.getEnd(), - content: `\nconst { ${mfUtilTokens - .map((mfUtilToken) => mfUtilToken.mfTokens.map((node) => node.getText())) - .join(', ')} } = require('@nx/webpack');`, - }); - - let newFileContents = fileContents; - while (changes.length) { - const change = changes.pop(); - newFileContents = `${newFileContents.substring(0, change.startPosition)}${ - change.content - }${newFileContents.substring( - change.endPosition ? change.endPosition : change.startPosition - )}`; - } - - return newFileContents; -} - -function replaceTSImports( - tree: Tree, - path: string, - fileContents: string -): string { - if (!tsModule) { - tsModule = ensurePackage('typescript', typescriptVersion); - } - - const sourceFile = tsModule.createSourceFile( - path, - fileContents, - tsModule.ScriptTarget.Latest, - true - ); - - const allImports = findNodes( - sourceFile, - tsModule.SyntaxKind.ImportDeclaration - ); - const devkitImports = allImports.filter((i) => - i.getText().includes(`'@nx/devkit';`) - ); - const mfUtilsImports = devkitImports.filter((i) => - MODULE_FEDERATION_PUBLIC_TOKENS.some((token) => i.getText().includes(token)) - ); - - if (!mfUtilsImports.length) { - return fileContents; - } - - const mfUtilsWithMultipleImports = mfUtilsImports.map((i) => { - const importSpecifierNodes = findNodes( - i, - tsModule.SyntaxKind.ImportSpecifier - ); - const mfImportSpecifierNodes = importSpecifierNodes.filter((node) => - MODULE_FEDERATION_PUBLIC_TOKENS.some((token) => - node.getText().includes(token) - ) - ); - - return { - importDeclarationNode: i, - onlyMf: mfImportSpecifierNodes.length === importSpecifierNodes.length, - mfImportSpecifierNodes, - }; - }); - - const changes: { - startPosition: number; - endPosition?: number; - content: string; - }[] = []; - for (const importDeclaration of mfUtilsWithMultipleImports) { - if (importDeclaration.onlyMf) { - changes.push({ - startPosition: importDeclaration.importDeclarationNode.getStart(), - endPosition: importDeclaration.importDeclarationNode.getEnd(), - content: '', - }); - } else { - for (const mfImportSpecifierNodes of importDeclaration.mfImportSpecifierNodes) { - const replaceTrailingComma = - importDeclaration.importDeclarationNode - .getText() - .charAt(mfImportSpecifierNodes.getEnd() + 1) === ','; - changes.push({ - startPosition: mfImportSpecifierNodes.getStart(), - endPosition: replaceTrailingComma - ? mfImportSpecifierNodes.getEnd() + 1 - : mfImportSpecifierNodes.getEnd(), - content: '', - }); - } - } - } - - changes.push({ - startPosition: - mfUtilsWithMultipleImports[ - mfUtilsWithMultipleImports.length - 1 - ].importDeclarationNode.getEnd(), - content: `\nimport { ${mfUtilsWithMultipleImports - .map((importDeclaration) => - importDeclaration.mfImportSpecifierNodes.map((node) => node.getText()) - ) - .join(', ')} } from '@nx/webpack';`, - }); - - let newFileContents = fileContents; - while (changes.length) { - const change = changes.pop(); - newFileContents = `${newFileContents.substring(0, change.startPosition)}${ - change.content - }${newFileContents.substring( - change.endPosition ? change.endPosition : change.startPosition - )}`; - } - - return newFileContents; -} - -function findNodes( - node: Node, - kind: SyntaxKind | SyntaxKind[], - max = Infinity -): Node[] { - if (!node || max == 0) { - return []; - } - - const arr: Node[] = []; - const hasMatch = Array.isArray(kind) - ? kind.includes(node.kind) - : node.kind === kind; - if (hasMatch) { - arr.push(node); - max--; - } - if (max > 0) { - for (const child of node.getChildren()) { - findNodes(child, kind, max).forEach((node) => { - if (max > 0) { - arr.push(node); - } - max--; - }); - - if (max <= 0) { - break; - } - } - } - - return arr; -} diff --git a/packages/esbuild/migrations.json b/packages/esbuild/migrations.json index 722387067d0aa6..f9d34cef28c2cd 100644 --- a/packages/esbuild/migrations.json +++ b/packages/esbuild/migrations.json @@ -1,36 +1,4 @@ { - "generators": { - "update-16-0-0-add-nx-packages": { - "cli": "nx", - "version": "16.0.0-beta.1", - "description": "Replace @nrwl/esbuild with @nx/esbuild", - "implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages" - }, - "update-16-0-1-set-thirdparty-true": { - "version": "16.0.1-beta.0", - "description": "Set thirdParty to true to maintain the existing behavior of bundling dependencies.", - "cli": "nx", - "implementation": "./src/migrations/update-16-0-1-set-thirdparty-true/update-16-0-1-set-thirdparty-true" - } - }, - "packageJsonUpdates": { - "16.0.0": { - "version": "16.0.0-beta.5", - "packages": { - "esbuild": { - "version": "0.17.17", - "alwaysAddToPackageJson": false - } - } - }, - "16.8.0": { - "version": "16.8.0-beta.2", - "packages": { - "esbuild": { - "version": "^0.19.2", - "alwaysAddToPackageJson": false - } - } - } - } + "generators": {}, + "packageJsonUpdates": {} } diff --git a/packages/esbuild/src/generators/configuration/configuration.ts b/packages/esbuild/src/generators/configuration/configuration.ts index f838f143ded4aa..51e6329e6884b2 100644 --- a/packages/esbuild/src/generators/configuration/configuration.ts +++ b/packages/esbuild/src/generators/configuration/configuration.ts @@ -8,6 +8,7 @@ import { } from '@nx/devkit'; import { getImportPath } from '@nx/js/src/utils/get-import-path'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { esbuildInitGenerator } from '../init/init'; import { EsBuildExecutorOptions } from '../../executors/esbuild/schema'; @@ -18,6 +19,8 @@ export async function configurationGenerator( tree: Tree, options: EsBuildProjectSchema ) { + assertNotUsingTsSolutionSetup(tree, 'esbuild', 'configuration'); + const task = await esbuildInitGenerator(tree, { ...options, skipFormat: true, diff --git a/packages/esbuild/src/generators/init/init.ts b/packages/esbuild/src/generators/init/init.ts index 591459de95b499..a6543e7fa1fedc 100644 --- a/packages/esbuild/src/generators/init/init.ts +++ b/packages/esbuild/src/generators/init/init.ts @@ -4,11 +4,14 @@ import { GeneratorCallback, Tree, } from '@nx/devkit'; -import { Schema } from './schema'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { esbuildVersion } from '@nx/js/src/utils/versions'; import { nxVersion } from '../../utils/versions'; +import { Schema } from './schema'; export async function esbuildInitGenerator(tree: Tree, schema: Schema) { + assertNotUsingTsSolutionSetup(tree, 'esbuild', 'init'); + let installTask: GeneratorCallback = () => {}; if (!schema.skipPackageJson) { installTask = addDependenciesToPackageJson( diff --git a/packages/esbuild/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts b/packages/esbuild/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts deleted file mode 100644 index 463bcdcc06a4db..00000000000000 --- a/packages/esbuild/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Tree, readJson, updateJson } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import replacePackage from './update-16-0-0-add-nx-packages'; - -describe('update-16-0-0-add-nx-packages', () => { - let tree: Tree; - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - - updateJson(tree, 'package.json', (json) => { - json.devDependencies['@nrwl/esbuild'] = '16.0.0'; - return json; - }); - }); - - it('should remove the dependency on @nrwl/esbuild', async () => { - await replacePackage(tree); - - expect( - readJson(tree, 'package.json').dependencies['@nrwl/esbuild'] - ).not.toBeDefined(); - expect( - readJson(tree, 'package.json').devDependencies['@nrwl/esbuild'] - ).not.toBeDefined(); - }); - - it('should add a dependency on @nx/esbuild', async () => { - await replacePackage(tree); - - const packageJson = readJson(tree, 'package.json'); - const newDependencyVersion = - packageJson.devDependencies['@nx/esbuild'] ?? - packageJson.dependencies['@nx/esbuild']; - - expect(newDependencyVersion).toBeDefined(); - }); -}); diff --git a/packages/esbuild/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts b/packages/esbuild/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts deleted file mode 100644 index 0f2fee0d7609d6..00000000000000 --- a/packages/esbuild/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Tree, formatFiles } from '@nx/devkit'; -import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package'; - -export default async function replacePackage(tree: Tree): Promise { - await replaceNrwlPackageWithNxPackage(tree, '@nrwl/esbuild', '@nx/esbuild'); - - await formatFiles(tree); -} diff --git a/packages/esbuild/src/migrations/update-16-0-1-set-thirdparty-true/update-16-0-1-set-thirdparty-true.spec.ts b/packages/esbuild/src/migrations/update-16-0-1-set-thirdparty-true/update-16-0-1-set-thirdparty-true.spec.ts deleted file mode 100644 index 7da77d511fa281..00000000000000 --- a/packages/esbuild/src/migrations/update-16-0-1-set-thirdparty-true/update-16-0-1-set-thirdparty-true.spec.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import { - addProjectConfiguration, - readProjectConfiguration, - Tree, -} from '@nx/devkit'; - -import update from './update-16-0-1-set-thirdparty-true'; - -describe('update-16-0-1-set-thirdparty-true', () => { - let tree: Tree; - - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - }); - - it('should skip migration targets are not set on the project', async () => { - addProjectConfiguration(tree, 'myapp', { - root: 'myapp', - }); - await update(tree); - - const config = readProjectConfiguration(tree, 'myapp'); - - expect(config.targets).toBeUndefined(); - }); - - it('should add thirdParty property if bundling is enabled implicitly', async () => { - addProjectConfiguration(tree, 'myapp', { - root: 'myapp', - targets: { - build: { - executor: '@nx/esbuild:esbuild', - }, - }, - }); - await update(tree); - - const config = readProjectConfiguration(tree, 'myapp'); - - expect(config.targets.build.options).toEqual({ - thirdParty: true, - }); - }); - - it('should add thirdParty property if bundling is enabled explicitly', async () => { - addProjectConfiguration(tree, 'myapp', { - root: 'myapp', - targets: { - build: { - executor: '@nx/esbuild:esbuild', - options: { - bundle: true, - }, - }, - }, - }); - await update(tree); - - const config = readProjectConfiguration(tree, 'myapp'); - - expect(config.targets.build.options).toEqual({ - bundle: true, - thirdParty: true, - }); - }); - - it('should not add thirdParty property if bundling is disabled', async () => { - addProjectConfiguration(tree, 'myapp', { - root: 'myapp', - targets: { - build: { - executor: '@nx/esbuild:esbuild', - options: { - bundle: false, - }, - }, - }, - }); - await update(tree); - - const config = readProjectConfiguration(tree, 'myapp'); - - expect(config.targets.build.options).toEqual({ - bundle: false, - }); - }); - - it('should not set thirdParty property if it was already set', async () => { - addProjectConfiguration(tree, 'myapp', { - root: 'myapp', - targets: { - build: { - executor: '@nx/esbuild:esbuild', - options: { - thirdParty: false, - }, - }, - }, - }); - await update(tree); - - const config = readProjectConfiguration(tree, 'myapp'); - - expect(config.targets.build.options).toEqual({ - thirdParty: false, - }); - }); -}); diff --git a/packages/esbuild/src/migrations/update-16-0-1-set-thirdparty-true/update-16-0-1-set-thirdparty-true.ts b/packages/esbuild/src/migrations/update-16-0-1-set-thirdparty-true/update-16-0-1-set-thirdparty-true.ts deleted file mode 100644 index e1e3973dd1f240..00000000000000 --- a/packages/esbuild/src/migrations/update-16-0-1-set-thirdparty-true/update-16-0-1-set-thirdparty-true.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { - formatFiles, - getProjects, - Tree, - updateProjectConfiguration, -} from '@nx/devkit'; - -export default async function update(host: Tree) { - const projects = getProjects(host); - - projects.forEach((projectConfig, projectName) => { - if (!projectConfig.targets) return; - - let shouldUpdate = false; - - Object.entries(projectConfig.targets).forEach( - ([targetName, targetConfig]) => { - if ( - targetConfig.executor === '@nrwl/esbuild:esbuild' || - targetConfig.executor === '@nx/esbuild:esbuild' - ) { - projectConfig.targets[targetName].options ??= {}; - if (projectConfig.targets[targetName].options.bundle !== false) { - shouldUpdate = true; - - projectConfig.targets[targetName].options.thirdParty ??= true; - } - } - } - ); - - if (shouldUpdate) { - updateProjectConfiguration(host, projectName, projectConfig); - } - }); - - await formatFiles(host); -} diff --git a/packages/eslint-plugin/migrations.json b/packages/eslint-plugin/migrations.json index 14c0760e50ca0b..73b5e7315e3725 100644 --- a/packages/eslint-plugin/migrations.json +++ b/packages/eslint-plugin/migrations.json @@ -1,11 +1,5 @@ { "generators": { - "update-16-0-0-add-nx-packages": { - "cli": "nx", - "version": "16.0.0-beta.1", - "description": "Replace @nrwl/eslint-plugin-nx with @nx/eslint-plugin", - "implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages" - }, "update-17-2-6-rename-workspace-rules": { "cli": "nx", "version": "17.2.6-beta.1", diff --git a/packages/eslint-plugin/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts b/packages/eslint-plugin/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts deleted file mode 100644 index f75974eea62df7..00000000000000 --- a/packages/eslint-plugin/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { Tree, readJson, updateJson, writeJson } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import replacePackage from './update-16-0-0-add-nx-packages'; - -describe('update-16-0-0-add-nx-packages', () => { - let tree: Tree; - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - - updateJson(tree, 'package.json', (json) => { - json.devDependencies['@nrwl/eslint-plugin-nx'] = '16.0.0'; - return json; - }); - }); - - it('should remove the dependency on @nrwl/eslint-plugin-nx', async () => { - await replacePackage(tree); - - expect( - readJson(tree, 'package.json').dependencies['@nrwl/eslint-plugin-nx'] - ).not.toBeDefined(); - expect( - readJson(tree, 'package.json').devDependencies['@nrwl/eslint-plugin-nx'] - ).not.toBeDefined(); - }); - - it('should add a dependency on @nx/eslint-plugin', async () => { - await replacePackage(tree); - - const packageJson = readJson(tree, 'package.json'); - const newDependencyVersion = - packageJson.devDependencies['@nx/eslint-plugin'] ?? - packageJson.dependencies['@nx/eslint-plugin']; - - expect(newDependencyVersion).toBeDefined(); - }); - - it('should replace the eslint plugin', async () => { - writeJson(tree, '.eslintrc.json', { - plugins: ['@nrwl/nx'], - rules: { - '@nrwl/nx/enforce-module-boundaries': ['error', {}], - }, - }); - - await replacePackage(tree); - - expect(readJson(tree, '.eslintrc.json')).toMatchInlineSnapshot(` - { - "plugins": [ - "@nx", - ], - "rules": { - "@nx/enforce-module-boundaries": [ - "error", - {}, - ], - }, - } - `); - }); - - it('should replace eslint-ignore comments', async () => { - tree.write( - 'ignored-file.ts', - '// eslint-disable-next-line @nrwl/nx/enforce-module-boundaries\n /*\n* eslint-disable @nrwl/nx/enforce-module-boundaries\n*/\n // eslint-disable-line @nrwl/nx/enforce-module-boundaries' - ); - tree.write('plugin.ts', `import * as p from '@nrwl/nx-plugin'`); - - await replacePackage(tree); - - expect(tree.read('ignored-file.ts').toString()).toMatchInlineSnapshot(` - "// eslint-disable-next-line @nx/enforce-module-boundaries - /* - * eslint-disable @nx/enforce-module-boundaries - */ - // eslint-disable-line @nx/enforce-module-boundaries" - `); - expect(tree.read('plugin.ts').toString()).toMatchInlineSnapshot( - `"import * as p from '@nrwl/nx-plugin'"` - ); - }); -}); diff --git a/packages/eslint-plugin/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts b/packages/eslint-plugin/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts deleted file mode 100644 index 19dc743a80c482..00000000000000 --- a/packages/eslint-plugin/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Tree, formatFiles, visitNotIgnoredFiles } from '@nx/devkit'; -import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package'; - -import { basename } from 'path'; -import { isBinaryPath } from '@nx/devkit/src/utils/binary-extensions'; - -const eslintFileNames = [ - '.eslintrc', - '.eslintrc.js', - '.eslintrc.cjs', - '.eslintrc.yaml', - '.eslintrc.yml', - '.eslintrc.json', - 'eslint.config.js', // new format that requires `ESLINT_USE_FLAT_CONFIG=true` -]; - -export default async function replacePackage(tree: Tree): Promise { - await replaceNrwlPackageWithNxPackage( - tree, - '@nrwl/eslint-plugin-nx', - '@nx/eslint-plugin' - ); - - /** - * Matches: - * * // eslint-disable-next-line @nrwl/nx/... - * * // eslint-disable-line @nrwl/nx/... - * * /* eslint-disable @nrwl/nx/... - */ - const ignoreLineRegex = /(eslint-disable(?:(?:-next)?-line)?\s*)@nrwl\/nx/g; - visitNotIgnoredFiles(tree, '.', (path) => { - if (isBinaryPath(path)) { - return; - } - - let contents = tree.read(path).toString(); - if (eslintFileNames.includes(basename(path))) { - if (!contents.includes('@nrwl/nx')) { - return; - } - - contents = contents.replace(new RegExp('@nrwl/nx', 'g'), '@nx'); - } - if (ignoreLineRegex.test(contents)) { - contents = contents.replace(ignoreLineRegex, '$1@nx'); - } - tree.write(path, contents); - }); - - await formatFiles(tree); -} diff --git a/packages/eslint/migrations.json b/packages/eslint/migrations.json index 05c0b881859a4b..7db3c058f72a6d 100644 --- a/packages/eslint/migrations.json +++ b/packages/eslint/migrations.json @@ -1,16 +1,5 @@ { "generators": { - "update-16-0-0-add-nx-packages": { - "cli": "nx", - "version": "16.0.0-beta.1", - "description": "Replace @nrwl/linter with @nx/linter", - "implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages" - }, - "update-16-8-0-add-ignored-files": { - "version": "16.8.0", - "description": "update-16-8-0-add-ignored-files", - "implementation": "./src/migrations/update-16-8-0-add-ignored-files/update-16-8-0-add-ignored-files" - }, "update-17-0-0-rename-to-eslint": { "version": "17.0.0-beta.7", "description": "update-17-0-0-rename-to-eslint", @@ -33,51 +22,6 @@ } }, "packageJsonUpdates": { - "16.0.0": { - "version": "16.0.0-beta.0", - "packages": { - "@typescript-eslint/parser": { - "version": "^5.58.0" - }, - "@typescript-eslint/eslint-plugin": { - "version": "^5.58.0" - }, - "@typescript-eslint/utils": { - "version": "^5.58.0" - } - } - }, - "16.5.0": { - "version": "16.5.0-beta.2", - "packages": { - "@typescript-eslint/parser": { - "version": "^5.60.1" - }, - "@typescript-eslint/eslint-plugin": { - "version": "^5.60.1" - }, - "@typescript-eslint/utils": { - "version": "^5.60.1" - } - } - }, - "16.7.0": { - "version": "16.7.0-beta.2", - "packages": { - "eslint": { - "version": "~8.46.0" - }, - "@typescript-eslint/parser": { - "version": "^5.60.1" - }, - "@typescript-eslint/eslint-plugin": { - "version": "^5.60.1" - }, - "@typescript-eslint/utils": { - "version": "^5.60.1" - } - } - }, "17.0.0": { "version": "17.0.0-rc.2", "packages": { diff --git a/packages/eslint/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts b/packages/eslint/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts deleted file mode 100644 index 1c66d74de0c4e8..00000000000000 --- a/packages/eslint/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Tree, readJson, updateJson } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import replacePackage from './update-16-0-0-add-nx-packages'; - -describe('update-16-0-0-add-nx-packages', () => { - let tree: Tree; - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - - updateJson(tree, 'package.json', (json) => { - json.devDependencies['@nrwl/linter'] = '16.0.0'; - return json; - }); - }); - - it('should remove the dependency on @nrwl/linter', async () => { - await replacePackage(tree); - - expect( - readJson(tree, 'package.json').dependencies['@nrwl/linter'] - ).not.toBeDefined(); - expect( - readJson(tree, 'package.json').devDependencies['@nrwl/linter'] - ).not.toBeDefined(); - }); - - it('should add a dependency on @nx/linter', async () => { - await replacePackage(tree); - - const packageJson = readJson(tree, 'package.json'); - const newDependencyVersion = - packageJson.devDependencies['@nx/linter'] ?? - packageJson.dependencies['@nx/linter']; - - expect(newDependencyVersion).toBeDefined(); - }); -}); diff --git a/packages/eslint/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts b/packages/eslint/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts deleted file mode 100644 index 318e1816ffba8c..00000000000000 --- a/packages/eslint/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Tree, formatFiles } from '@nx/devkit'; -import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package'; - -export default async function replacePackage(tree: Tree): Promise { - await replaceNrwlPackageWithNxPackage(tree, '@nrwl/linter', '@nx/linter'); - - await formatFiles(tree); -} diff --git a/packages/eslint/src/migrations/update-16-8-0-add-ignored-files/update-16-8-0-add-ignored-files.spec.ts b/packages/eslint/src/migrations/update-16-8-0-add-ignored-files/update-16-8-0-add-ignored-files.spec.ts deleted file mode 100644 index 48e1252014f21d..00000000000000 --- a/packages/eslint/src/migrations/update-16-8-0-add-ignored-files/update-16-8-0-add-ignored-files.spec.ts +++ /dev/null @@ -1,194 +0,0 @@ -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import { addProjectConfiguration, readJson, Tree, writeJson } from '@nx/devkit'; - -import update from './update-16-8-0-add-ignored-files'; - -describe('update-16-8-0-add-ignored-files migration', () => { - let tree: Tree; - - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - tree.write('.eslintrc.json', '{}'); - }); - - it('should run successfully when eslint config is not present', async () => { - addProjectConfiguration(tree, 'my-pkg', { - root: 'packages/my-pkg', - sourceRoot: 'packages/my-pkg/src', - projectType: 'library', - targets: { - build: { - executor: '@nx/vite:build', - options: {}, - }, - }, - }); - - expect(() => update(tree)).not.toThrow(); - }); - - it.each` - executor | expectedPattern - ${'@nx/vite:build'} | ${'{projectRoot}/vite.config.{js,ts,mjs,mts}'} - ${'@nx/vite:test'} | ${'{projectRoot}/vite.config.{js,ts,mjs,mts}'} - ${'@nx/esbuild:esbuild'} | ${'{projectRoot}/esbuild.config.{js,ts,mjs,mts}'} - ${'@nx/rollup:rollup'} | ${'{projectRoot}/rollup.config.{js,ts,mjs,mts}'} - `( - 'should add ignoredFiles to projects using vite, esbuild, and rollup', - async ({ executor, expectedPattern }) => { - addProjectConfiguration(tree, 'my-pkg', { - root: 'packages/my-pkg', - sourceRoot: 'packages/my-pkg/src', - projectType: 'library', - targets: { - build: { - executor, - options: {}, - }, - }, - }); - writeJson(tree, `packages/my-pkg/.eslintrc.json`, { - root: true, - ignorePatterns: ['!**/*'], - plugins: ['@nx'], - overrides: [ - { - files: ['*.json'], - parser: 'jsonc-eslint-parser', - rules: { - '@nx/dependency-checks': 'error', - }, - }, - ], - }); - - update(tree); - - expect(readJson(tree, 'packages/my-pkg/.eslintrc.json')).toEqual({ - root: true, - ignorePatterns: ['!**/*'], - plugins: ['@nx'], - overrides: [ - { - files: ['*.json'], - parser: 'jsonc-eslint-parser', - rules: { - '@nx/dependency-checks': [ - 'error', - { - ignoredFiles: [expectedPattern], - }, - ], - }, - }, - ], - }); - } - ); - - it('should retain existing severity', () => { - addProjectConfiguration(tree, 'my-pkg', { - root: 'packages/my-pkg', - sourceRoot: 'packages/my-pkg/src', - projectType: 'library', - targets: { - build: { - executor: '@nx/vite:build', - options: {}, - }, - }, - }); - writeJson(tree, `packages/my-pkg/.eslintrc.json`, { - root: true, - ignorePatterns: ['!**/*'], - plugins: ['@nx'], - overrides: [ - { - files: ['*.json'], - parser: 'jsonc-eslint-parser', - rules: { - '@nx/dependency-checks': 'warn', - }, - }, - ], - }); - - update(tree); - - expect(readJson(tree, 'packages/my-pkg/.eslintrc.json')).toEqual({ - root: true, - ignorePatterns: ['!**/*'], - plugins: ['@nx'], - overrides: [ - { - files: ['*.json'], - parser: 'jsonc-eslint-parser', - rules: { - '@nx/dependency-checks': [ - 'warn', - { - ignoredFiles: ['{projectRoot}/vite.config.{js,ts,mjs,mts}'], - }, - ], - }, - }, - ], - }); - }); - - it('should retain existing options', () => { - addProjectConfiguration(tree, 'my-pkg', { - root: 'packages/my-pkg', - sourceRoot: 'packages/my-pkg/src', - projectType: 'library', - targets: { - build: { - executor: '@nx/vite:build', - options: {}, - }, - }, - }); - writeJson(tree, `packages/my-pkg/.eslintrc.json`, { - root: true, - ignorePatterns: ['!**/*'], - plugins: ['@nx'], - overrides: [ - { - files: ['*.json'], - parser: 'jsonc-eslint-parser', - rules: { - '@nx/dependency-checks': [ - 'error', - { - checkVersionMismatches: false, - }, - ], - }, - }, - ], - }); - - update(tree); - - expect(readJson(tree, 'packages/my-pkg/.eslintrc.json')).toEqual({ - root: true, - ignorePatterns: ['!**/*'], - plugins: ['@nx'], - overrides: [ - { - files: ['*.json'], - parser: 'jsonc-eslint-parser', - rules: { - '@nx/dependency-checks': [ - 'error', - { - checkVersionMismatches: false, - ignoredFiles: ['{projectRoot}/vite.config.{js,ts,mjs,mts}'], - }, - ], - }, - }, - ], - }); - }); -}); diff --git a/packages/eslint/src/migrations/update-16-8-0-add-ignored-files/update-16-8-0-add-ignored-files.ts b/packages/eslint/src/migrations/update-16-8-0-add-ignored-files/update-16-8-0-add-ignored-files.ts deleted file mode 100644 index a070ef746cff43..00000000000000 --- a/packages/eslint/src/migrations/update-16-8-0-add-ignored-files/update-16-8-0-add-ignored-files.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { getProjects, Tree } from '@nx/devkit'; -import { forEachExecutorOptions } from '@nx/devkit/src/generators/executor-options-utils'; -import { - findEslintFile, - isEslintConfigSupported, - lintConfigHasOverride, - updateOverrideInLintConfig, -} from '../../generators/utils/eslint-file'; - -// Add `ignoredFiles` pattern to projects using vite, esbuild, and rollup. -// This is needed because the @nx/dependency-checks lint rule will complain -// about dependencies used in build config files, even though they are not -// production dependencies. -export default function update(tree: Tree) { - const projects = getProjects(tree); - - const addIgnorePattern = - (ignorePattern: string) => (_options: unknown, projectName: string) => { - const project = projects.get(projectName); - if ( - !findEslintFile(tree, project.root) || - !isEslintConfigSupported(tree) - ) { - return; - } - if ( - lintConfigHasOverride( - tree, - project.root, - (o) => - Array.isArray(o.files) - ? o.files.some((f) => f.match(/\.json$/)) - : !!o.files?.match(/\.json$/), - true - ) - ) { - updateOverrideInLintConfig( - tree, - project.root, - (o) => !!o.rules?.['@nx/dependency-checks'], - (o) => { - const value = o.rules['@nx/dependency-checks']; - let ruleSeverity: 0 | 1 | 2 | 'error' | 'warn' | 'off'; - let ruleOptions: any; - if (Array.isArray(value)) { - ruleSeverity = value[0]; - ruleOptions = value[1]; - } else { - ruleSeverity = value; - ruleOptions = {}; - } - ruleOptions.ignoredFiles = [ignorePattern]; - o.rules['@nx/dependency-checks'] = [ruleSeverity, ruleOptions]; - return o; - } - ); - } - }; - - forEachExecutorOptions( - tree, - '@nx/vite:build', - addIgnorePattern('{projectRoot}/vite.config.{js,ts,mjs,mts}') - ); - forEachExecutorOptions( - tree, - '@nx/vite:test', - addIgnorePattern('{projectRoot}/vite.config.{js,ts,mjs,mts}') - ); - forEachExecutorOptions( - tree, - '@nx/esbuild:esbuild', - addIgnorePattern('{projectRoot}/esbuild.config.{js,ts,mjs,mts}') - ); - forEachExecutorOptions( - tree, - '@nx/rollup:rollup', - addIgnorePattern('{projectRoot}/rollup.config.{js,ts,mjs,mts}') - ); -} diff --git a/packages/expo/migrations.json b/packages/expo/migrations.json index 6b6d10155604f0..2b968b5277fdb4 100644 --- a/packages/expo/migrations.json +++ b/packages/expo/migrations.json @@ -1,47 +1,5 @@ { "generators": { - "remove-deprecated-expo-targets": { - "version": "16.0.0-beta.0", - "cli": "nx", - "description": "Remove deprecated expo targets", - "factory": "./src/migrations/update-16-0-0/remove-deprecated-targets" - }, - "update-16-0-0-add-nx-packages": { - "cli": "nx", - "version": "16.0.0-beta.1", - "description": "Replace @nrwl/expo with @nx/expo", - "implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages" - }, - "update-eas-scripts-16-1-4": { - "cli": "nx", - "version": "16.1.4-beta.0", - "description": "Update package.json eas build lifecycle scripts", - "implementation": "./src/migrations/update-16-1-4/update-eas-scripts" - }, - "update-16-6-0-add-dependsOn": { - "cli": "nx", - "version": "16.6.0-beta.0", - "description": "Add dependsOn like ensure-symlink or sync-deps to targets", - "implementation": "./src/migrations/update-16-6-0/add-depends-on" - }, - "update-16-6-0-update-metro-config": { - "cli": "nx", - "version": "16.6.0-beta.0", - "description": "Update metro.config.js to use the new metro config format", - "implementation": "./src/migrations/update-16-6-0/update-metro-config" - }, - "update-16-9-0-remove-types-react-native": { - "cli": "nx", - "version": "16.9.0-beta.1", - "description": "Remove @types/react-native from package.json", - "implementation": "./src/migrations/update-16-9-0/remove-types-react-native" - }, - "update-16-9-0-update-eas-json-cli-version": { - "cli": "nx", - "version": "16.9.0-beta.1", - "description": "Update eas.json cli version", - "implementation": "./src/migrations/update-16-9-0/update-eas-cli-version" - }, "update-18-0-0-remove-block-list": { "cli": "nx", "version": "18.0.0-beta.0", @@ -86,226 +44,6 @@ } }, "packageJsonUpdates": { - "16.0.0": { - "version": "16.0.0-beta.0", - "packages": { - "expo": { - "version": "48.0.11", - "alwaysAddToPackageJson": false - }, - "react-native": { - "version": "0.71.6", - "alwaysAddToPackageJson": false - }, - "@types/react-native": { - "version": "0.71.6", - "alwaysAddToPackageJson": false - }, - "eas-cli": { - "version": "~3.10.0", - "alwaysAddToPackageJson": false - }, - "@expo/cli": { - "version": "~0.7.0", - "alwaysAddToPackageJson": false - }, - "@testing-library/react-native": { - "version": "12.0.1", - "alwaysAddToPackageJson": false - }, - "jest-expo": { - "version": "~48.0.2", - "alwaysAddToPackageJson": false, - "addToPackageJson": "devDependencies" - } - } - }, - "16.0.2": { - "version": "16.0.2-beta.0", - "packages": { - "expo": { - "version": "48.0.15", - "alwaysAddToPackageJson": false - }, - "react-native": { - "version": "0.71.7", - "alwaysAddToPackageJson": false - }, - "eas-cli": { - "version": "~3.10.2", - "alwaysAddToPackageJson": false - }, - "@expo/cli": { - "version": "~0.7.1", - "alwaysAddToPackageJson": false - }, - "expo-splash-screen": { - "version": "~0.18.2", - "alwaysAddToPackageJson": false - } - } - }, - "16.1.5": { - "version": "16.1.5-beta.0", - "packages": { - "expo": { - "version": "^48.0.16", - "alwaysAddToPackageJson": false - }, - "eas-cli": { - "version": "~3.12.0", - "alwaysAddToPackageJson": false - }, - "@testing-library/react-native": { - "version": "12.1.2", - "alwaysAddToPackageJson": false - } - } - }, - "16.2.2": { - "version": "16.2.2-beta.0", - "packages": { - "expo": { - "version": "^48.0.17", - "alwaysAddToPackageJson": false - }, - "eas-cli": { - "version": "~3.13.2", - "alwaysAddToPackageJson": false - }, - "react-native": { - "version": "0.71.8", - "alwaysAddToPackageJson": false - }, - "@types/react-native": { - "version": "0.71.7", - "alwaysAddToPackageJson": false - } - } - }, - "16.4.0": { - "version": "16.4.0-beta.5", - "packages": { - "expo": { - "version": "^48.0.19", - "alwaysAddToPackageJson": false - }, - "eas-cli": { - "version": "~3.13.3", - "alwaysAddToPackageJson": false - }, - "@expo/cli": { - "version": "~0.7.3", - "alwaysAddToPackageJson": false - } - } - }, - "16.6.0": { - "version": "16.6.0-beta.0", - "packages": { - "expo": { - "version": "^49.0.3", - "alwaysAddToPackageJson": false - }, - "@expo/metro-config": { - "version": "~0.10.6", - "alwaysAddToPackageJson": false - }, - "expo-splash-screen": { - "version": "~0.20.4", - "alwaysAddToPackageJson": false - }, - "expo-status-bar": { - "version": "~1.6.0", - "alwaysAddToPackageJson": false - }, - "@expo/cli": { - "version": "~0.10.10", - "alwaysAddToPackageJson": false - }, - "eas-cli": { - "version": "~3.15.0", - "alwaysAddToPackageJson": false - }, - "babel-preset-expo": { - "version": "~9.5.0", - "alwaysAddToPackageJson": false - }, - "jest-expo": { - "version": "~49.0.0", - "alwaysAddToPackageJson": false - }, - "metro-resolver": { - "version": "0.76.7", - "alwaysAddToPackageJson": false - }, - "metro": { - "version": "0.76.7", - "alwaysAddToPackageJson": false - }, - "react-native": { - "version": "0.72.3", - "alwaysAddToPackageJson": false - }, - "@types/react-native": { - "version": "0.72.2", - "alwaysAddToPackageJson": false - }, - "react-native-web": { - "version": "~0.19.6", - "alwaysAddToPackageJson": false - }, - "react-native-svg": { - "version": "13.9.0", - "alwaysAddToPackageJson": false - } - } - }, - "16.9.0": { - "version": "16.9.0-beta.1", - "packages": { - "expo": { - "version": "49.0.10", - "alwaysAddToPackageJson": false - }, - "@expo/metro-config": { - "version": "~0.10.7", - "alwaysAddToPackageJson": false - }, - "expo-splash-screen": { - "version": "~0.20.5", - "alwaysAddToPackageJson": false - }, - "@expo/cli": { - "version": "~0.10.12", - "alwaysAddToPackageJson": false - }, - "eas-cli": { - "version": "~5.2.0", - "alwaysAddToPackageJson": false - }, - "babel-preset-expo": { - "version": "~9.5.2", - "alwaysAddToPackageJson": false - }, - "react-native": { - "version": "0.72.4", - "alwaysAddToPackageJson": false - }, - "react-native-web": { - "version": "~0.19.8", - "alwaysAddToPackageJson": false - }, - "@testing-library/react-native": { - "version": "~12.3.0", - "alwaysAddToPackageJson": false - }, - "@testing-library/jest-native": { - "version": "~5.4.3", - "alwaysAddToPackageJson": false - } - } - }, "17.1.0": { "version": "17.1.0-beta.0", "packages": { diff --git a/packages/expo/src/generators/application/application.ts b/packages/expo/src/generators/application/application.ts index a7cf520a7bc932..058dc24445f304 100644 --- a/packages/expo/src/generators/application/application.ts +++ b/packages/expo/src/generators/application/application.ts @@ -6,6 +6,7 @@ import { Tree, } from '@nx/devkit'; import { initGenerator as jsInitGenerator } from '@nx/js'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { addLinting } from '../../utils/add-linting'; import { addJest } from '../../utils/add-jest'; @@ -35,6 +36,8 @@ export async function expoApplicationGeneratorInternal( host: Tree, schema: Schema ): Promise { + assertNotUsingTsSolutionSetup(host, 'expo', 'application'); + const options = await normalizeOptions(host, schema); const tasks: GeneratorCallback[] = []; diff --git a/packages/expo/src/generators/init/init.ts b/packages/expo/src/generators/init/init.ts index 5e35458920d11b..1050bff1a59a90 100644 --- a/packages/expo/src/generators/init/init.ts +++ b/packages/expo/src/generators/init/init.ts @@ -9,6 +9,7 @@ import { Tree, } from '@nx/devkit'; import { addPluginV1 } from '@nx/devkit/src/utils/add-plugin'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { createNodes } from '../../../plugins/plugin'; import { expoCliVersion, @@ -27,6 +28,8 @@ export function expoInitGenerator(tree: Tree, schema: Schema) { } export async function expoInitGeneratorInternal(host: Tree, schema: Schema) { + assertNotUsingTsSolutionSetup(host, 'expo', 'init'); + const nxJson = readNxJson(host); const addPluginDefault = process.env.NX_ADD_PLUGINS !== 'false' && diff --git a/packages/expo/src/generators/library/library.ts b/packages/expo/src/generators/library/library.ts index 42294a89231f6d..b9377948c9d0e4 100644 --- a/packages/expo/src/generators/library/library.ts +++ b/packages/expo/src/generators/library/library.ts @@ -20,6 +20,7 @@ import { getRelativePathToRootTsConfig, initGenerator as jsInitGenerator, } from '@nx/js'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import init from '../init/init'; import { addLinting } from '../../utils/add-linting'; import { addJest } from '../../utils/add-jest'; @@ -49,6 +50,8 @@ export async function expoLibraryGeneratorInternal( host: Tree, schema: Schema ): Promise { + assertNotUsingTsSolutionSetup(host, 'expo', 'library'); + const options = await normalizeOptions(host, schema); if (options.publishable === true && !schema.importPath) { throw new Error( diff --git a/packages/expo/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts b/packages/expo/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts deleted file mode 100644 index 9ee07dbc04ed9e..00000000000000 --- a/packages/expo/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Tree, readJson, updateJson } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import replacePackage from './update-16-0-0-add-nx-packages'; - -describe('update-16-0-0-add-nx-packages', () => { - let tree: Tree; - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - - updateJson(tree, 'package.json', (json) => { - json.devDependencies['@nrwl/expo'] = '16.0.0'; - return json; - }); - }); - - it('should remove the dependency on @nrwl/expo', async () => { - await replacePackage(tree); - - expect( - readJson(tree, 'package.json').dependencies['@nrwl/expo'] - ).not.toBeDefined(); - expect( - readJson(tree, 'package.json').devDependencies['@nrwl/expo'] - ).not.toBeDefined(); - }); - - it('should add a dependency on @nx/expo', async () => { - await replacePackage(tree); - - const packageJson = readJson(tree, 'package.json'); - const newDependencyVersion = - packageJson.devDependencies['@nx/expo'] ?? - packageJson.dependencies['@nx/expo']; - - expect(newDependencyVersion).toBeDefined(); - }); -}); diff --git a/packages/expo/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts b/packages/expo/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts deleted file mode 100644 index 9459acd38444c2..00000000000000 --- a/packages/expo/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Tree, formatFiles } from '@nx/devkit'; -import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package'; - -export default async function replacePackage(tree: Tree): Promise { - await replaceNrwlPackageWithNxPackage(tree, '@nrwl/expo', '@nx/expo'); - - await formatFiles(tree); -} diff --git a/packages/expo/src/migrations/update-16-0-0/remove-deprecated-targets.ts b/packages/expo/src/migrations/update-16-0-0/remove-deprecated-targets.ts deleted file mode 100644 index 735c15aef02557..00000000000000 --- a/packages/expo/src/migrations/update-16-0-0/remove-deprecated-targets.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { - Tree, - formatFiles, - getProjects, - updateProjectConfiguration, -} from '@nx/devkit'; - -/** - * Remove deprecated @expo/cli targets - */ -export default async function update(tree: Tree) { - const projects = getProjects(tree); - - for (const [name, config] of projects.entries()) { - if ( - config.targets?.['start']?.executor === '@nrwl/expo:start' || - config.targets?.['start']?.executor === '@nx/expo:start' - ) { - const targetsToDelete = [ - 'build-ios', - 'build-android', - 'build-web', - 'build-status', - 'publish', - 'publish-set', - 'rollback', - 'eject', - ]; - targetsToDelete.forEach((target) => { - if (config.targets[target]) { - delete config.targets[target]; - } - }); - updateProjectConfiguration(tree, name, config); - } - } - - await formatFiles(tree); -} diff --git a/packages/expo/src/migrations/update-16-1-4/update-eas-scripts.spec.ts b/packages/expo/src/migrations/update-16-1-4/update-eas-scripts.spec.ts deleted file mode 100644 index bdc51c04cce97d..00000000000000 --- a/packages/expo/src/migrations/update-16-1-4/update-eas-scripts.spec.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { - Tree, - addProjectConfiguration, - readJson, - updateJson, -} from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import update from './update-eas-scripts'; - -describe('update-eas-scripts', () => { - let tree: Tree; - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - - addProjectConfiguration(tree, 'products', { - root: 'apps/products', - sourceRoot: 'apps/products/src', - targets: { - start: { - executor: '@nrwl/expo:start', - }, - }, - }); - tree.write('apps/products/package.json', JSON.stringify({})); - }); - - it('should add scripts', async () => { - update(tree); - - expect( - tree.exists('tools/scripts/eas-build-post-install.mjs') - ).toBeTruthy(); - const packageJson = readJson(tree, 'apps/products/package.json'); - expect(packageJson.scripts['eas-build-post-install']).toEqual( - 'cd ../../ && node tools/scripts/eas-build-post-install.mjs . apps/products' - ); - }); - - it('should remove postinstall script', async () => { - updateJson(tree, 'apps/products/package.json', (json) => { - json.scripts = { - postinstall: 'some script', - }; - return json; - }); - update(tree); - - const packageJson = readJson(tree, 'apps/products/package.json'); - expect(packageJson.scripts['postinstall']).toBeUndefined(); - }); -}); diff --git a/packages/expo/src/migrations/update-16-1-4/update-eas-scripts.ts b/packages/expo/src/migrations/update-16-1-4/update-eas-scripts.ts deleted file mode 100644 index 253ee1d54c9020..00000000000000 --- a/packages/expo/src/migrations/update-16-1-4/update-eas-scripts.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { - Tree, - getProjects, - logger, - offsetFromRoot, - updateJson, -} from '@nx/devkit'; -import { addEasScripts } from '../../generators/application/lib/add-eas-scripts'; -import { join } from 'path'; - -/** - * Update app's package.json to use eas-build-post-install scripts. - */ -export default function update(tree: Tree) { - const projects = getProjects(tree); - - for (const [name, config] of projects.entries()) { - if ( - config.targets?.['start']?.executor === '@nrwl/expo:start' || - config.targets?.['start']?.executor === '@nx/expo:start' - ) { - try { - addEasScripts(tree); - updateJson(tree, join(config.root, 'package.json'), (packageJson) => { - if (packageJson.scripts?.['postinstall']) { - delete packageJson.scripts['postinstall']; - } - const offset = offsetFromRoot(config.root); - packageJson.scripts = { - ...packageJson.scripts, - 'eas-build-post-install': `cd ${offset} && node tools/scripts/eas-build-post-install.mjs . ${config.root}`, - }; - return packageJson; - }); - } catch { - logger.error(`Unable to update package.json for project ${name}.`); - } - } - } -} diff --git a/packages/expo/src/migrations/update-16-6-0/add-depends-on.ts b/packages/expo/src/migrations/update-16-6-0/add-depends-on.ts deleted file mode 100644 index c133e28eba656a..00000000000000 --- a/packages/expo/src/migrations/update-16-6-0/add-depends-on.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Tree, getProjects, updateProjectConfiguration } from '@nx/devkit'; - -/** - * This migration adds dependsOn to project.json. - * - */ -export default async function update(tree: Tree) { - const projects = getProjects(tree); - - for (const [name, config] of projects.entries()) { - if (config.targets?.['start']?.executor === '@nx/expo:start') { - config.targets['start'].dependsOn = ['ensure-symlink', 'sync-deps']; - } - if (config.targets?.['run-ios']?.executor === '@nx/expo:run') { - config.targets['run-ios'].dependsOn = ['ensure-symlink', 'sync-deps']; - } - if (config.targets?.['run-android']?.executor === '@nx/expo:run') { - config.targets['run-android'].dependsOn = ['ensure-symlink', 'sync-deps']; - } - if (config.targets?.['prebuild']?.executor === '@nx/expo:prebuild') { - config.targets['prebuild'].dependsOn = ['ensure-symlink', 'sync-deps']; - } - if (config.targets?.['export']?.executor === '@nx/expo:export') { - config.targets['export'].dependsOn = ['ensure-symlink', 'sync-deps']; - } - - updateProjectConfiguration(tree, name, config); - } -} diff --git a/packages/expo/src/migrations/update-16-6-0/update-metro-config.ts b/packages/expo/src/migrations/update-16-6-0/update-metro-config.ts deleted file mode 100644 index 8a165cc66c1c10..00000000000000 --- a/packages/expo/src/migrations/update-16-6-0/update-metro-config.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { Tree, getProjects } from '@nx/devkit'; -import { join } from 'path'; - -/** - * This migration updates metro.config.js to export config as a default. - * - */ -export default async function update(tree: Tree) { - const projects = getProjects(tree); - - for (const [_, config] of projects.entries()) { - if (config.targets?.['start']?.executor === '@nx/expo:start') { - if (tree.exists(join(config.root, 'metro.config.js'))) { - const oldConfig = tree - .read(join(config.root, 'metro.config.js')) - .toString(); - tree.write( - join(config.root, 'metro-v71.config.js'), - oldConfigComment + oldConfig - ); - tree.write(join(config.root, 'metro.config.js'), content); - } - } - } -} - -const oldConfigComment = `/** - * Old custom configuration for React Native v0.71. - * From @react-native/metro-config 0.72.1, it is no longer necessary to use a config function to access the complete default config. - * Please port your custom configuration to metro.config.js. - * Please see https://docs.expo.dev/guides/customizing-metro/ to learn about configuration. - */ -`; - -const content = ` -const { withNxMetro } = require('@nx/expo'); -const { getDefaultConfig } = require('@expo/metro-config'); -const { mergeConfig } = require('metro-config'); - -const defaultConfig = getDefaultConfig(__dirname); -const { assetExts, sourceExts } = defaultConfig.resolver; - -/** - * Metro configuration - * https://facebook.github.io/metro/docs/configuration - * - * @type {import('metro-config').MetroConfig} - */ -const customConfig = { - transformer: { - babelTransformerPath: require.resolve('react-native-svg-transformer'), - }, - resolver: { - assetExts: assetExts.filter((ext) => ext !== 'svg'), - sourceExts: [...sourceExts, 'cjs', 'mjs', 'svg'], - }, -}; - - -module.exports = withNxMetro(mergeConfig(defaultConfig, customConfig), { - // Change this to true to see debugging info. - // Useful if you have issues resolving modules - debug: false, - // all the file extensions used for imports other than 'ts', 'tsx', 'js', 'jsx', 'json' - extensions: [], - // Specify folders to watch, in addition to Nx defaults (workspace libraries and node_modules) - watchFolders: [], -}); -`; diff --git a/packages/expo/src/migrations/update-16-9-0/remove-types-react-native.ts b/packages/expo/src/migrations/update-16-9-0/remove-types-react-native.ts deleted file mode 100644 index a2a9daabb16909..00000000000000 --- a/packages/expo/src/migrations/update-16-9-0/remove-types-react-native.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { - formatFiles, - removeDependenciesFromPackageJson, - Tree, -} from '@nx/devkit'; - -/** - * Remove @types/react-native package since it is no longer required. It would be a part of react native package. - * @param tree - * @returns - */ -export default async function update(tree: Tree) { - removeDependenciesFromPackageJson(tree, [], ['@types/react-native']); - await formatFiles(tree); -} diff --git a/packages/expo/src/migrations/update-16-9-0/update-eas-cli-version.spec.ts b/packages/expo/src/migrations/update-16-9-0/update-eas-cli-version.spec.ts deleted file mode 100644 index 85389d62b9e4b4..00000000000000 --- a/packages/expo/src/migrations/update-16-9-0/update-eas-cli-version.spec.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { addProjectConfiguration, getProjects, Tree } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import update from './update-eas-cli-version'; - -describe('update-eas-cli-version', () => { - let tree: Tree; - - beforeEach(async () => { - tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); - addProjectConfiguration(tree, 'product', { - root: 'apps/product', - sourceRoot: 'apps/product/src', - targets: { - start: { - executor: '@nx/expo:start', - }, - }, - }); - tree.write('apps/product/eas.json', '{"cli":{"version": "1.2.3"}}'); - }); - - it(`should update eas.json with greater than version`, async () => { - await update(tree); - - const easJson = JSON.parse(tree.read('apps/product/eas.json').toString()); - expect(easJson.cli.version).toContain('>='); - }); -}); diff --git a/packages/expo/src/migrations/update-16-9-0/update-eas-cli-version.ts b/packages/expo/src/migrations/update-16-9-0/update-eas-cli-version.ts deleted file mode 100644 index 49de4ae51b3b95..00000000000000 --- a/packages/expo/src/migrations/update-16-9-0/update-eas-cli-version.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Tree, getProjects, updateJson } from '@nx/devkit'; - -export default async function update(tree: Tree) { - const projects = getProjects(tree); - - for (const [name, config] of projects.entries()) { - if (config.targets?.['start']?.executor === '@nx/expo:start') { - updateJson(tree, `${config.root}/eas.json`, (easJson) => { - if (easJson?.cli?.version) { - easJson.cli.version = `>= 5`; - } - return easJson; - }); - } - } -} diff --git a/packages/express/migrations.json b/packages/express/migrations.json index 1f28dfafc3cf75..f9d34cef28c2cd 100644 --- a/packages/express/migrations.json +++ b/packages/express/migrations.json @@ -1,11 +1,4 @@ { - "generators": { - "update-16-0-0-add-nx-packages": { - "cli": "nx", - "version": "16.0.0-beta.1", - "description": "Replace @nrwl/express with @nx/express", - "implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages" - } - }, + "generators": {}, "packageJsonUpdates": {} } diff --git a/packages/express/package.json b/packages/express/package.json index 1e777406eddcfe..44108d69c08d5c 100644 --- a/packages/express/package.json +++ b/packages/express/package.json @@ -32,6 +32,7 @@ }, "dependencies": { "@nx/devkit": "file:../devkit", + "@nx/js": "file:../js", "@nx/node": "file:../node", "tslib": "^2.3.0" }, diff --git a/packages/express/src/generators/application/application.ts b/packages/express/src/generators/application/application.ts index 594a4bfbb4b7e6..a4721b25bf1c13 100644 --- a/packages/express/src/generators/application/application.ts +++ b/packages/express/src/generators/application/application.ts @@ -11,6 +11,7 @@ import { determineProjectNameAndRootOptions, ensureProjectName, } from '@nx/devkit/src/generators/project-name-and-root-utils'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { applicationGenerator as nodeApplicationGenerator } from '@nx/node'; import { tslibVersion } from '@nx/node/src/utils/versions'; import { join } from 'path'; @@ -74,6 +75,8 @@ export async function applicationGenerator(tree: Tree, schema: Schema) { } export async function applicationGeneratorInternal(tree: Tree, schema: Schema) { + assertNotUsingTsSolutionSetup(tree, 'express', 'application'); + const options = await normalizeOptions(tree, schema); const tasks: GeneratorCallback[] = []; diff --git a/packages/express/src/generators/init/init.ts b/packages/express/src/generators/init/init.ts index 3321e30dc2a0d5..bf6d07deca2dc0 100644 --- a/packages/express/src/generators/init/init.ts +++ b/packages/express/src/generators/init/init.ts @@ -6,6 +6,7 @@ import { runTasksInSerial, Tree, } from '@nx/devkit'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { expressVersion, nxVersion } from '../../utils/versions'; import type { Schema } from './schema'; @@ -28,6 +29,8 @@ function updateDependencies(tree: Tree, schema: Schema) { } export async function initGenerator(tree: Tree, schema: Schema) { + assertNotUsingTsSolutionSetup(tree, 'express', 'init'); + let installTask: GeneratorCallback = () => {}; if (!schema.skipPackageJson) { installTask = updateDependencies(tree, schema); diff --git a/packages/express/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts b/packages/express/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts deleted file mode 100644 index 856c86a57b4855..00000000000000 --- a/packages/express/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Tree, readJson, updateJson } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import replacePackage from './update-16-0-0-add-nx-packages'; - -describe('update-16-0-0-add-nx-packages', () => { - let tree: Tree; - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - - updateJson(tree, 'package.json', (json) => { - json.devDependencies['@nrwl/express'] = '16.0.0'; - return json; - }); - }); - - it('should remove the dependency on @nrwl/express', async () => { - await replacePackage(tree); - - expect( - readJson(tree, 'package.json').dependencies['@nrwl/express'] - ).not.toBeDefined(); - expect( - readJson(tree, 'package.json').devDependencies['@nrwl/express'] - ).not.toBeDefined(); - }); - - it('should add a dependency on @nx/express', async () => { - await replacePackage(tree); - - const packageJson = readJson(tree, 'package.json'); - const newDependencyVersion = - packageJson.devDependencies['@nx/express'] ?? - packageJson.dependencies['@nx/express']; - - expect(newDependencyVersion).toBeDefined(); - }); -}); diff --git a/packages/express/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts b/packages/express/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts deleted file mode 100644 index 5ac86ccf454f03..00000000000000 --- a/packages/express/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Tree, formatFiles } from '@nx/devkit'; -import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package'; - -export default async function replacePackage(tree: Tree): Promise { - await replaceNrwlPackageWithNxPackage(tree, '@nrwl/express', '@nx/express'); - - await formatFiles(tree); -} diff --git a/packages/jest/migrations.json b/packages/jest/migrations.json index 12bddd7d972d79..73fcf3cf6eca22 100644 --- a/packages/jest/migrations.json +++ b/packages/jest/migrations.json @@ -1,33 +1,18 @@ { "generators": { - "update-16-0-0-add-nx-packages": { - "cli": "nx", - "version": "16.0.0-beta.1", - "description": "Replace @nrwl/jest with @nx/jest", - "implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages" - }, - "add-test-setup-to-inputs-ignore": { - "cli": "nx", - "version": "16.5.0-beta.2", - "description": "Add test-setup.ts to ignored files in production input", - "implementation": "./src/migrations/update-16-5-0/add-test-setup-to-inputs-ignore" - }, "move-options-to-target-defaults": { "version": "17.1.0-beta.2", "description": "Move jest executor options to nx.json targetDefaults", "implementation": "./src/migrations/update-17-1-0/move-options-to-target-defaults" + }, + "replace-getJestProjects-with-getJestProjectsAsync": { + "cli": "nx", + "version": "20.0.0-beta.5", + "description": "replace getJestProjects with getJestProjectsAsync", + "implementation": "./src/migrations/update-20-0-0/replace-getJestProjects-with-getJestProjectsAsync" } }, "packageJsonUpdates": { - "16.0.0": { - "version": "16.0.0-beta.4", - "packages": { - "ts-jest": { - "version": "~29.1.0", - "alwaysAddToPackageJson": false - } - } - }, "17.2.0": { "version": "17.2.0-beta.2", "packages": { diff --git a/packages/jest/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts b/packages/jest/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts deleted file mode 100644 index e92821496f7cb9..00000000000000 --- a/packages/jest/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Tree, readJson, updateJson } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import replacePackage from './update-16-0-0-add-nx-packages'; - -describe('update-16-0-0-add-nx-packages', () => { - let tree: Tree; - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - - updateJson(tree, 'package.json', (json) => { - json.devDependencies['@nrwl/jest'] = '16.0.0'; - return json; - }); - }); - - it('should remove the dependency on @nrwl/jest', async () => { - await replacePackage(tree); - - expect( - readJson(tree, 'package.json').dependencies['@nrwl/jest'] - ).not.toBeDefined(); - expect( - readJson(tree, 'package.json').devDependencies['@nrwl/jest'] - ).not.toBeDefined(); - }); - - it('should add a dependency on @nx/jest', async () => { - await replacePackage(tree); - - const packageJson = readJson(tree, 'package.json'); - const newDependencyVersion = - packageJson.devDependencies['@nx/jest'] ?? - packageJson.dependencies['@nx/jest']; - - expect(newDependencyVersion).toBeDefined(); - }); -}); diff --git a/packages/jest/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts b/packages/jest/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts deleted file mode 100644 index 0d5413bfec219c..00000000000000 --- a/packages/jest/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Tree, formatFiles } from '@nx/devkit'; -import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package'; - -export default async function replacePackage(tree: Tree): Promise { - await replaceNrwlPackageWithNxPackage(tree, '@nrwl/jest', '@nx/jest'); - - await formatFiles(tree); -} diff --git a/packages/jest/src/migrations/update-16-5-0/add-test-setup-to-inputs-ignore.spec.ts b/packages/jest/src/migrations/update-16-5-0/add-test-setup-to-inputs-ignore.spec.ts deleted file mode 100644 index add7fb0f72d138..00000000000000 --- a/packages/jest/src/migrations/update-16-5-0/add-test-setup-to-inputs-ignore.spec.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Tree, readNxJson, updateNxJson } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import addTestSetupToIgnoredInputs from './add-test-setup-to-inputs-ignore'; - -describe('Jest Migration - jest 29 mocked usage in tests', () => { - let tree: Tree; - - beforeEach(() => { - tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); - }); - - it('should add inputs configuration for test-setup if missing', async () => { - updateNxJson(tree, { - namedInputs: { - default: ['{projectRoot}/**/*', 'sharedGlobals'], - sharedGlobals: [], - production: ['default'], - }, - }); - - await addTestSetupToIgnoredInputs(tree); - - const updated = readNxJson(tree); - expect(updated.namedInputs.production).toMatchInlineSnapshot(` - [ - "default", - "!{projectRoot}/src/test-setup.[jt]s", - ] - `); - }); - - it('should not add inputs configuration for test-setup if existing', async () => { - updateNxJson(tree, { - namedInputs: { - default: ['{projectRoot}/**/*', 'sharedGlobals'], - sharedGlobals: [], - production: ['!{projectRoot}/src/test-setup.[jt]s', 'default'], - }, - }); - - await addTestSetupToIgnoredInputs(tree); - - const updated = readNxJson(tree); - expect(updated.namedInputs.production).toMatchInlineSnapshot(` - [ - "!{projectRoot}/src/test-setup.[jt]s", - "default", - ] - `); - }); -}); diff --git a/packages/jest/src/migrations/update-16-5-0/add-test-setup-to-inputs-ignore.ts b/packages/jest/src/migrations/update-16-5-0/add-test-setup-to-inputs-ignore.ts deleted file mode 100644 index 5aab60313634bb..00000000000000 --- a/packages/jest/src/migrations/update-16-5-0/add-test-setup-to-inputs-ignore.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { - NxJsonConfiguration, - Tree, - formatFiles, - readNxJson, - updateNxJson, -} from '@nx/devkit'; - -export async function addTestSetupToIgnoredInputs(tree: Tree) { - const nxJson: NxJsonConfiguration = readNxJson(tree); - - if (!nxJson) { - return; - } - if ( - nxJson.namedInputs?.production && - !nxJson.namedInputs.production.includes( - '!{projectRoot}/src/test-setup.[jt]s' - ) - ) { - nxJson.namedInputs.production.push('!{projectRoot}/src/test-setup.[jt]s'); - updateNxJson(tree, nxJson); - } - - await formatFiles(tree); -} - -export default addTestSetupToIgnoredInputs; diff --git a/packages/jest/src/migrations/update-20-0-0/replace-getJestProjects-with-getJestProjectsAsync.spec.ts b/packages/jest/src/migrations/update-20-0-0/replace-getJestProjects-with-getJestProjectsAsync.spec.ts new file mode 100644 index 00000000000000..e654118a65884c --- /dev/null +++ b/packages/jest/src/migrations/update-20-0-0/replace-getJestProjects-with-getJestProjectsAsync.spec.ts @@ -0,0 +1,65 @@ +import { Tree } from '@nx/devkit'; +import { createTree } from '@nx/devkit/testing'; +import update from './replace-getJestProjects-with-getJestProjectsAsync'; + +describe('replace-getJestProjects-with-getJestProjectsAsync', () => { + let tree: Tree; + + beforeEach(() => { + tree = createTree(); + }); + + it('should replace getJestProjects with getJestProjectsAsync', async () => { + tree.write( + 'jest.config.ts', + ` + const { getJestProjects } = require('@nx/jest'); + + module.exports = { + projects: getJestProjects(), + }; + ` + ); + await update(tree); + const updatedJestConfig = tree.read('jest.config.ts')?.toString(); + expect(updatedJestConfig).toMatchInlineSnapshot(` + " + const { getJestProjectsAsync } = require('@nx/jest'); + + export default async () => ({ + projects: await getJestProjectsAsync(), + }); + " + `); + }); + + it('should replace getJestProjects with getJestProjectsAsync with additonal properties', async () => { + tree.write( + 'jest.config.ts', + ` + const { getJestProjects } = require('@nx/jest'); + + module.exports = { + projects: getJestProjects(), + filename: __filename, + env: process.env, + dirname: __dirname + }; + ` + ); + await update(tree); + const updatedJestConfig = tree.read('jest.config.ts')?.toString(); + expect(updatedJestConfig).toMatchInlineSnapshot(` + " + const { getJestProjectsAsync } = require('@nx/jest'); + + export default async () => ({ + projects: await getJestProjectsAsync(), + filename: __filename, + env: process.env, + dirname: __dirname + }); + " + `); + }); +}); diff --git a/packages/jest/src/migrations/update-20-0-0/replace-getJestProjects-with-getJestProjectsAsync.ts b/packages/jest/src/migrations/update-20-0-0/replace-getJestProjects-with-getJestProjectsAsync.ts new file mode 100644 index 00000000000000..ae005222f1cdc3 --- /dev/null +++ b/packages/jest/src/migrations/update-20-0-0/replace-getJestProjects-with-getJestProjectsAsync.ts @@ -0,0 +1,94 @@ +// go through the jest.config files +// see if it imports from @nx/jest and if it uses getJestProjects +// replace getJestProjects with getJestProjectsAsync + +import { globAsync, Tree } from '@nx/devkit'; +import { ensureTypescript } from '@nx/js/src/utils/typescript/ensure-typescript'; +import { BinaryExpression, ExpressionStatement } from 'typescript'; + +let tsModule: typeof import('typescript'); + +export default async function update(tree: Tree) { + if (!tsModule) { + tsModule = ensureTypescript(); + } + + const jestConfigPaths = await globAsync(tree, [ + '**/jest.config.{cjs,mjs,js,cts,mts,ts}', + ]); + jestConfigPaths.forEach((jestConfigPath) => { + const oldContent = tree.read(jestConfigPath).toString(); + if (oldContent?.includes('projects: getJestProjects()')) { + let sourceFile = tsModule.createSourceFile( + jestConfigPath, + oldContent, + tsModule.ScriptTarget.Latest, + true + ); + + // find the import statement for @nx/jest + const importStatement = sourceFile.statements.find( + (statement) => + tsModule.isVariableStatement(statement) && + statement.declarationList.declarations.some( + (declaration) => + tsModule.isCallExpression(declaration.initializer) && + tsModule.isIdentifier(declaration.initializer.expression) && + declaration.initializer.expression.escapedText === 'require' && + tsModule.isStringLiteral(declaration.initializer.arguments[0]) && + declaration.initializer.arguments[0].text === '@nx/jest' + ) + ); + if (importStatement) { + // find export statement with `projects: getJestProjects()` + let exportStatement = sourceFile.statements.find( + (statement) => + tsModule.isExpressionStatement(statement) && + tsModule.isBinaryExpression(statement.expression) && + tsModule.isPropertyAccessExpression(statement.expression.left) && + tsModule.isObjectLiteralExpression(statement.expression.right) && + statement.expression.operatorToken.kind === + tsModule.SyntaxKind.EqualsToken && + tsModule.isIdentifier(statement.expression.left.expression) && + statement.expression.left.expression.escapedText === 'module' && + tsModule.isIdentifier(statement.expression.left.name) && + statement.expression.left.name.escapedText === 'exports' && + statement.expression.right.properties.some( + (property) => + tsModule.isPropertyAssignment(property) && + tsModule.isIdentifier(property.name) && + property.name.escapedText === 'projects' && + tsModule.isCallExpression(property.initializer) && + tsModule.isIdentifier(property.initializer.expression) && + property.initializer.expression.escapedText === + 'getJestProjects' + ) + ) as ExpressionStatement; + + if (exportStatement) { + // replace getJestProjects with getJestProjectsAsync in export statement + const rightExpression = ( + exportStatement.expression as BinaryExpression + ).right.getText(); + const newExpression = rightExpression.replace( + 'getJestProjects()', + 'await getJestProjectsAsync()' + ); + const newStatement = `export default async () => (${newExpression});`; + let newContent = oldContent.replace( + exportStatement.getText(), + newStatement + ); + + // replace getJestProjects with getJestProjectsAsync in import statement + newContent = newContent.replace( + 'getJestProjects', + 'getJestProjectsAsync' + ); + + tree.write(jestConfigPath, newContent); + } + } + } + }); +} diff --git a/packages/jest/src/utils/config/get-jest-projects.ts b/packages/jest/src/utils/config/get-jest-projects.ts index f06422b4937162..d9c68aa0e80720 100644 --- a/packages/jest/src/utils/config/get-jest-projects.ts +++ b/packages/jest/src/utils/config/get-jest-projects.ts @@ -12,6 +12,8 @@ function getJestConfigProjectPath(projectJestConfigPath: string): string { } /** + * TODO(v21): Remove this function + * @deprecated To get projects use {@link getJestProjectsAsync} instead. This will be removed in v21. * Get a list of paths to all the jest config files * using the Nx Jest executor. * diff --git a/packages/js/migrations.json b/packages/js/migrations.json index 99e0241965cf42..a277e5dd84cd8a 100644 --- a/packages/js/migrations.json +++ b/packages/js/migrations.json @@ -1,23 +1,5 @@ { "generators": { - "update-16-0-0-add-nx-packages": { - "cli": "nx", - "version": "16.0.0-beta.1", - "description": "Replace @nrwl/js with @nx/js", - "implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages" - }, - "explicitly-set-projects-to-update-buildable-deps": { - "cli": "nx", - "version": "16.6.0-beta.0", - "description": "Explicitly set 'updateBuildableProjectDepsInPackageJson' to 'true' in targets that rely on that value as the default.", - "factory": "./src/migrations/update-16-6-0/explicitly-set-projects-to-update-buildable-deps" - }, - "16-8-2-update-swcrc": { - "cli": "nx", - "version": "16.8.2-beta.0", - "description": "Remove invalid options (strict, noInterop) for ES6 type modules.", - "factory": "./src/migrations/update-16-8-2/update-swcrc" - }, "update-17-0-0-remove-deprecated-build-options": { "cli": "nx", "version": "17.0.2", @@ -26,65 +8,6 @@ } }, "packageJsonUpdates": { - "16.0.0": { - "version": "16.0.0-beta.3", - "packages": { - "@swc/cli": { - "version": "~0.1.62", - "alwaysAddToPackageJson": false - }, - "@swc/helpers": { - "version": "~0.5.0", - "alwaysAddToPackageJson": false - } - } - }, - "16.1.0": { - "version": "16.1.0-beta.0", - "x-prompt": "Do you want to update to TypeScript v5.0?", - "requires": { - "typescript": ">=4.9.5 <5.0.0" - }, - "packages": { - "typescript": { - "version": "~5.0.2" - } - } - }, - "16.4.0": { - "version": "16.4.0-beta.11", - "x-prompt": "Do you want to update to TypeScript v5.1?", - "requires": { - "typescript": ">=5.0.0 <5.1.0" - }, - "packages": { - "typescript": { - "version": "~5.1.3" - } - } - }, - "16.8.2": { - "version": "16.8.2-beta.0", - "packages": { - "@swc/core": { - "version": "~1.3.85", - "alwaysAddToPackageJson": false - }, - "@swc/helpers": { - "version": "~0.5.2", - "alwaysAddToPackageJson": false - } - } - }, - "16.9.2": { - "version": "16.9.2-beta.0", - "packages": { - "@swc-node/register": { - "version": "~1.6.7", - "alwaysAddToPackageJson": false - } - } - }, "17.0.0": { "version": "17.0.0-rc.2", "packages": { diff --git a/packages/js/src/generators/init/init.ts b/packages/js/src/generators/init/init.ts index d2950689af19d0..a2dd121cafc9ed 100644 --- a/packages/js/src/generators/init/init.ts +++ b/packages/js/src/generators/init/init.ts @@ -90,7 +90,7 @@ export async function initGeneratorInternal( process.env.NX_ADD_PLUGINS !== 'false' && nxJson.useInferencePlugins !== false; schema.addTsPlugin ??= - schema.addPlugin && process.env.NX_ADD_TS_PLUGIN === 'true'; + schema.addPlugin && process.env.NX_ADD_TS_PLUGIN !== 'false'; if (schema.addTsPlugin) { await addPlugin( diff --git a/packages/js/src/generators/library/library.ts b/packages/js/src/generators/library/library.ts index 747e809ea350ca..5d790a88ac8ed2 100644 --- a/packages/js/src/generators/library/library.ts +++ b/packages/js/src/generators/library/library.ts @@ -856,7 +856,9 @@ async function normalizeOptions( } if (options.bundler === 'none') { - options.bundler = 'tsc'; + throw new Error( + `Publishable libraries can't be generated with "--bundler=none". Please select a valid bundler.` + ); } } diff --git a/packages/js/src/generators/release-version/release-version.spec.ts b/packages/js/src/generators/release-version/release-version.spec.ts index 4436066e334e65..350d0c2ff5e1e7 100644 --- a/packages/js/src/generators/release-version/release-version.spec.ts +++ b/packages/js/src/generators/release-version/release-version.spec.ts @@ -454,7 +454,7 @@ To fix this you will either need to add a package.json file at that location, or }); describe('updateDependentsOptions', () => { - it(`should not update dependents when filtering to a subset of projects by default`, async () => { + it(`should update dependents even when filtering to a subset of projects which do not include those dependents, by default`, async () => { expect(readJson(tree, 'libs/my-lib/package.json').version).toEqual( '0.0.1' ); @@ -494,6 +494,7 @@ To fix this you will either need to add a package.json file at that location, or currentVersionResolver: 'disk', specifierSource: 'prompt', releaseGroup: createReleaseGroup('independent'), + // No value for updateDependents, should default to 'auto' }); expect(readJson(tree, 'libs/my-lib/package.json')) @@ -512,10 +513,10 @@ To fix this you will either need to add a package.json file at that location, or ).toMatchInlineSnapshot(` { "dependencies": { - "my-lib": "0.0.1", + "my-lib": "9.9.9", }, "name": "project-with-dependency-on-my-pkg", - "version": "0.0.1", + "version": "0.0.2", } `); expect( @@ -526,10 +527,10 @@ To fix this you will either need to add a package.json file at that location, or ).toMatchInlineSnapshot(` { "devDependencies": { - "my-lib": "0.0.1", + "my-lib": "9.9.9", }, "name": "project-with-devDependency-on-my-pkg", - "version": "0.0.1", + "version": "0.0.2", } `); }); diff --git a/packages/js/src/generators/release-version/release-version.ts b/packages/js/src/generators/release-version/release-version.ts index 4e3b366cf378c3..2c61a9270850d2 100644 --- a/packages/js/src/generators/release-version/release-version.ts +++ b/packages/js/src/generators/release-version/release-version.ts @@ -88,7 +88,7 @@ Valid values are: ${validReleaseVersionPrefixes } // Set default for updateDependents - const updateDependents = options.updateDependents ?? 'never'; + const updateDependents = options.updateDependents ?? 'auto'; const updateDependentsBump = 'patch'; // Sort the projects topologically if update dependents is enabled @@ -601,7 +601,7 @@ To fix this you will either need to add a package.json file at that location, or return localPackageDependency.target === project.name; }); - const includeTransitiveDependents = updateDependents === 'auto'; + const includeTransitiveDependents = updateDependents !== 'never'; const transitiveLocalPackageDependents: LocalPackageDependency[] = []; if (includeTransitiveDependents) { for (const directDependent of allDependentProjects) { @@ -674,7 +674,7 @@ To fix this you will either need to add a package.json file at that location, or logMsg += `\n${dependentProjectsOutsideCurrentBatch .map((dependentProject) => `${indent}- ${dependentProject.source}`) .join('\n')}`; - logMsg += `\n${indent}=> You can adjust this behavior by setting \`version.generatorOptions.updateDependents\` to "auto"`; + logMsg += `\n${indent}=> You can adjust this behavior by removing the usage of \`version.generatorOptions.updateDependents\` with "never"`; logger.buffer(logMsg); } } diff --git a/packages/js/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts b/packages/js/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts deleted file mode 100644 index 42b7c511fb9b60..00000000000000 --- a/packages/js/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Tree, readJson, updateJson } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import replacePackage from './update-16-0-0-add-nx-packages'; - -describe('update-16-0-0-add-nx-packages', () => { - let tree: Tree; - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - - updateJson(tree, 'package.json', (json) => { - json.devDependencies['@nrwl/js'] = '16.0.0'; - return json; - }); - }); - - it('should remove the dependency on @nrwl/js', async () => { - await replacePackage(tree); - - expect( - readJson(tree, 'package.json').dependencies['@nrwl/js'] - ).not.toBeDefined(); - expect( - readJson(tree, 'package.json').devDependencies['@nrwl/js'] - ).not.toBeDefined(); - }); - - it('should add a dependency on @nx/js', async () => { - await replacePackage(tree); - - const packageJson = readJson(tree, 'package.json'); - const newDependencyVersion = - packageJson.devDependencies['@nx/js'] ?? - packageJson.dependencies['@nx/js']; - - expect(newDependencyVersion).toBeDefined(); - }); -}); diff --git a/packages/js/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts b/packages/js/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts deleted file mode 100644 index 04118deb72b981..00000000000000 --- a/packages/js/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Tree, formatFiles } from '@nx/devkit'; -import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package'; - -export default async function replacePackage(tree: Tree): Promise { - await replaceNrwlPackageWithNxPackage(tree, '@nrwl/js', '@nx/js'); - - await formatFiles(tree); -} diff --git a/packages/js/src/migrations/update-16-6-0/explicitly-set-projects-to-update-buildable-deps.spec.ts b/packages/js/src/migrations/update-16-6-0/explicitly-set-projects-to-update-buildable-deps.spec.ts deleted file mode 100644 index b21129350c914d..00000000000000 --- a/packages/js/src/migrations/update-16-6-0/explicitly-set-projects-to-update-buildable-deps.spec.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { - ProjectConfiguration, - ProjectGraph, - Tree, - addProjectConfiguration, - readProjectConfiguration, -} from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import migration from './explicitly-set-projects-to-update-buildable-deps'; - -let projectGraph: ProjectGraph; -jest.mock('@nx/devkit', () => ({ - ...jest.requireActual('@nx/devkit'), - createProjectGraphAsync: () => Promise.resolve(projectGraph), -})); - -describe('explicitly-set-projects-to-update-buildable-deps migration', () => { - let tree: Tree; - - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - }); - - it.each(['@nx/js:swc', '@nrwl/js:swc', '@nx/js:tsc', '@nrwl/js:tsc'])( - 'should set updateBuildableProjectDepsInPackageJson option to "true" when not specified in target using "%s"', - async (executor) => { - addProject(tree, 'lib1', { - root: 'lib1', - projectType: 'library', - targets: { build: { executor, options: {} } }, - }); - - await migration(tree); - - const project = readProjectConfiguration(tree, 'lib1'); - expect( - project.targets.build.options.updateBuildableProjectDepsInPackageJson - ).toBe(true); - } - ); - - it.each(['@nx/js:swc', '@nrwl/js:swc', '@nx/js:tsc', '@nrwl/js:tsc'])( - 'should set updateBuildableProjectDepsInPackageJson option to "true" when target has no options object defined using "%s"', - async (executor) => { - addProject(tree, 'lib1', { - root: 'lib1', - projectType: 'library', - targets: { build: { executor } }, - }); - - await migration(tree); - - const project = readProjectConfiguration(tree, 'lib1'); - expect( - project.targets.build.options.updateBuildableProjectDepsInPackageJson - ).toBe(true); - } - ); - - it.each(['@nx/js:swc', '@nrwl/js:swc', '@nx/js:tsc', '@nrwl/js:tsc'])( - 'should not overwrite updateBuildableProjectDepsInPackageJson option when it is specified in target using "%s"', - async (executor) => { - addProject(tree, 'lib1', { - root: 'lib1', - projectType: 'library', - targets: { - build: { - executor, - options: { updateBuildableProjectDepsInPackageJson: false }, - }, - }, - }); - - await migration(tree); - - const project = readProjectConfiguration(tree, 'lib1'); - expect( - project.targets.build.options.updateBuildableProjectDepsInPackageJson - ).toBe(false); - } - ); - - it('should not update targets using other executors', async () => { - const originalProjectConfig: ProjectConfiguration = { - root: 'lib1', - projectType: 'library', - targets: { - build: { - executor: 'some-executor', - options: {}, - }, - }, - }; - addProject(tree, 'lib1', originalProjectConfig); - - await migration(tree); - - const project = readProjectConfiguration(tree, 'lib1'); - expect(project.targets).toStrictEqual(originalProjectConfig.targets); - }); -}); - -function addProject( - tree: Tree, - projectName: string, - config: ProjectConfiguration -): void { - projectGraph = { - dependencies: {}, - nodes: { - [projectName]: { - data: config, - name: projectName, - type: config.projectType === 'application' ? 'app' : 'lib', - }, - }, - }; - addProjectConfiguration(tree, projectName, config); -} diff --git a/packages/js/src/migrations/update-16-6-0/explicitly-set-projects-to-update-buildable-deps.ts b/packages/js/src/migrations/update-16-6-0/explicitly-set-projects-to-update-buildable-deps.ts deleted file mode 100644 index edbe446bf598f6..00000000000000 --- a/packages/js/src/migrations/update-16-6-0/explicitly-set-projects-to-update-buildable-deps.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { - createProjectGraphAsync, - formatFiles, - readProjectConfiguration, - Tree, - updateProjectConfiguration, -} from '@nx/devkit'; - -const executors = new Set([ - '@nx/js:swc', - '@nrwl/js:swc', - '@nx/js:tsc', - '@nrwl/js:tsc', -]); - -export default async function (tree: Tree) { - // use project graph to get the expanded target configurations - const projectGraph = await createProjectGraphAsync(); - - for (const [projectName, { data: projectData }] of Object.entries( - projectGraph.nodes - )) { - if (projectData.projectType !== 'library') { - continue; - } - - for (const [targetName, target] of Object.entries( - projectData.targets || {} - )) { - if (!executors.has(target.executor)) { - continue; - } - - if ( - !target.options || - target.options.updateBuildableProjectDepsInPackageJson === undefined - ) { - // read the project configuration to write the explicit project configuration - // and avoid writing the expanded target configuration - const project = readProjectConfiguration(tree, projectName); - project.targets[targetName].options ??= {}; - project.targets[ - targetName - ].options.updateBuildableProjectDepsInPackageJson = true; - updateProjectConfiguration(tree, projectName, project); - } - } - } - - await formatFiles(tree); -} diff --git a/packages/js/src/migrations/update-16-8-2/update-swcrc.spec.ts b/packages/js/src/migrations/update-16-8-2/update-swcrc.spec.ts deleted file mode 100644 index 7c8e06e7e79b5e..00000000000000 --- a/packages/js/src/migrations/update-16-8-2/update-swcrc.spec.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { addProjectConfiguration, readJson, Tree, writeJson } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import update from './update-swcrc'; - -describe('Migration: update .swcrc', () => { - let tree: Tree; - - beforeEach(async () => { - tree = createTreeWithEmptyWorkspace(); - }); - - it('should remove invalid options for ES6 modules', async () => { - addProjectConfiguration(tree, 'pkg', { - root: 'pkg', - }); - writeJson(tree, 'pkg/.swcrc', { - module: { - type: 'es6', - strict: true, - noInterop: true, - }, - }); - - await update(tree); - - expect(readJson(tree, 'pkg/.swcrc')).toEqual({ - module: { - type: 'es6', - }, - }); - }); - - it('should keep options for CommonJS modules', async () => { - addProjectConfiguration(tree, 'pkg', { - root: 'pkg', - }); - writeJson(tree, 'pkg/.swcrc', { - module: { - type: 'commonjs', - strict: true, - noInterop: true, - }, - }); - - await update(tree); - - expect(readJson(tree, 'pkg/.swcrc')).toEqual({ - module: { - type: 'commonjs', - strict: true, - noInterop: true, - }, - }); - }); - - it('should ignore projects without module options in .swcrc', async () => { - addProjectConfiguration(tree, 'pkg', { - root: 'pkg', - }); - writeJson(tree, 'pkg/.swcrc', { - jsc: { - target: 'es2017', - }, - }); - - await expect(update(tree)).resolves.not.toThrow(); - - expect(readJson(tree, 'pkg/.swcrc')).toEqual({ - jsc: { - target: 'es2017', - }, - }); - }); - - it('should ignore projects without .swcrc', async () => { - addProjectConfiguration(tree, 'pkg', { - root: 'pkg', - }); - - await expect(update(tree)).resolves.not.toThrow(); - }); -}); diff --git a/packages/js/src/migrations/update-16-8-2/update-swcrc.ts b/packages/js/src/migrations/update-16-8-2/update-swcrc.ts deleted file mode 100644 index 359a38a28493e0..00000000000000 --- a/packages/js/src/migrations/update-16-8-2/update-swcrc.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { - formatFiles, - getProjects, - readJson, - Tree, - writeJson, -} from '@nx/devkit'; -import { join } from 'path'; - -export default async function update(tree: Tree) { - const projects = getProjects(tree); - - for (const config of projects.values()) { - const swcrcPath = join(config.root, '.swcrc'); - if (!tree.exists(swcrcPath)) continue; - const json = readJson(tree, swcrcPath); - // No longer need strict or noInterop for es6 modules - // See: https://github.com/swc-project/swc/commit/7e8d72d - if ( - json.module?.type === 'es6' && - (json.module?.strict || json.module?.noInterop) - ) { - delete json.module.noInterop; - delete json.module.strict; - writeJson(tree, swcrcPath, json); - } - } - - await formatFiles(tree); -} diff --git a/packages/js/src/utils/typescript/ts-solution-setup.ts b/packages/js/src/utils/typescript/ts-solution-setup.ts index 343243031886c3..10b8d3a089637c 100644 --- a/packages/js/src/utils/typescript/ts-solution-setup.ts +++ b/packages/js/src/utils/typescript/ts-solution-setup.ts @@ -1,4 +1,4 @@ -import { readJson, readNxJson, type Tree } from '@nx/devkit'; +import { output, readJson, readNxJson, type Tree } from '@nx/devkit'; import { isUsingPackageManagerWorkspaces } from '../package-manager-workspaces'; export function isUsingTypeScriptPlugin(tree: Tree): boolean { @@ -61,3 +61,29 @@ function isWorkspaceSetupWithTsSolution(tree: Tree): boolean { return true; } + +export function assertNotUsingTsSolutionSetup( + tree: Tree, + pluginName: string, + generatorName: string +): void { + if ( + process.env.NX_IGNORE_UNSUPPORTED_TS_SETUP === 'true' || + !isUsingTsSolutionSetup(tree) + ) { + return; + } + + const artifactString = + generatorName === 'init' + ? `"@nx/${pluginName}" plugin` + : `"@nx/${pluginName}:${generatorName}" generator`; + output.error({ + title: `The ${artifactString} doesn't yet support the existing TypeScript setup`, + bodyLines: [ + `We're working hard to support the existing TypeScript setup with the ${artifactString}. We'll soon release a new version of Nx with support for it.`, + ], + }); + + process.exit(1); +} diff --git a/packages/nest/migrations.json b/packages/nest/migrations.json index 27068d586797b4..f9d34cef28c2cd 100644 --- a/packages/nest/migrations.json +++ b/packages/nest/migrations.json @@ -1,76 +1,4 @@ { - "generators": { - "update-16-0-0-add-nx-packages": { - "cli": "nx", - "version": "16.0.0-beta.1", - "description": "Replace @nrwl/nest with @nx/nest", - "implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages" - }, - "update-16-4-0-support-nestjs-10": { - "cli": "nx", - "version": "16.4.0-beta.16", - "description": "Update TsConfig target to es2021 and CacheModule if being used. Read more at https://docs.nestjs.com/migration-guide", - "implementation": "./src/migrations/update-16-4-0-cache-manager/nestjs-10-updates" - } - }, - "packageJsonUpdates": { - "16.1.0": { - "version": "16.1.0-beta.0", - "packages": { - "@nestjs/common": { - "version": "^9.1.1", - "alwaysAddToPackageJson": false - }, - "@nestjs/core": { - "version": "^9.1.1", - "alwaysAddToPackageJson": false - }, - "@nestjs/platform-express": { - "version": "^9.1.1", - "alwaysAddToPackageJson": false - }, - "@nestjs/schematics": { - "version": "^9.1.0", - "alwaysAddToPackageJson": false - }, - "@nestjs/swagger": { - "version": "^6.3.0", - "alwaysAddToPackageJson": false - }, - "@nestjs/testing": { - "version": "^9.1.1", - "alwaysAddToPackageJson": false - } - } - }, - "16.4.0": { - "version": "16.4.0-beta.11", - "packages": { - "@nestjs/common": { - "version": "^10.0.2", - "alwaysAddToPackageJson": false - }, - "@nestjs/core": { - "version": "^10.0.2", - "alwaysAddToPackageJson": false - }, - "@nestjs/platform-express": { - "version": "^10.0.2", - "alwaysAddToPackageJson": false - }, - "@nestjs/schematics": { - "version": "^10.0.1", - "alwaysAddToPackageJson": false - }, - "@nestjs/swagger": { - "version": "^7.0.2", - "alwaysAddToPackageJson": false - }, - "@nestjs/testing": { - "version": "^10.0.2", - "alwaysAddToPackageJson": false - } - } - } - } + "generators": {}, + "packageJsonUpdates": {} } diff --git a/packages/nest/package.json b/packages/nest/package.json index 156e00f6d94cba..66e60d74059f6a 100644 --- a/packages/nest/package.json +++ b/packages/nest/package.json @@ -36,7 +36,6 @@ "@nx/js": "file:../js", "@nx/eslint": "file:../eslint", "@nx/node": "file:../node", - "@phenomnomnominal/tsquery": "~5.0.1", "tslib": "^2.3.0" }, "publishConfig": { diff --git a/packages/nest/src/generators/application/application.ts b/packages/nest/src/generators/application/application.ts index c7bc9861ca6431..015bb798a06884 100644 --- a/packages/nest/src/generators/application/application.ts +++ b/packages/nest/src/generators/application/application.ts @@ -1,5 +1,6 @@ import type { GeneratorCallback, Tree } from '@nx/devkit'; import { formatFiles, runTasksInSerial } from '@nx/devkit'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { applicationGenerator as nodeApplicationGenerator } from '@nx/node'; import { initGenerator } from '../init/init'; @@ -26,6 +27,8 @@ export async function applicationGeneratorInternal( tree: Tree, rawOptions: ApplicationGeneratorOptions ): Promise { + assertNotUsingTsSolutionSetup(tree, 'nest', 'application'); + const options = await normalizeOptions(tree, rawOptions); const tasks: GeneratorCallback[] = []; diff --git a/packages/nest/src/generators/init/init.ts b/packages/nest/src/generators/init/init.ts index 876319c42687b4..5224b3330a9030 100644 --- a/packages/nest/src/generators/init/init.ts +++ b/packages/nest/src/generators/init/init.ts @@ -1,5 +1,6 @@ import type { GeneratorCallback, Tree } from '@nx/devkit'; import { formatFiles } from '@nx/devkit'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { addDependencies } from './lib'; import type { InitGeneratorOptions } from './schema'; @@ -8,6 +9,8 @@ export async function initGenerator( tree: Tree, options: InitGeneratorOptions ): Promise { + assertNotUsingTsSolutionSetup(tree, 'nest', 'init'); + let installPackagesTask: GeneratorCallback = () => {}; if (!options.skipPackageJson) { installPackagesTask = addDependencies(tree, options); diff --git a/packages/nest/src/generators/library/lib/normalize-options.ts b/packages/nest/src/generators/library/lib/normalize-options.ts index f3b84309e0ef74..8b1f1673c39020 100644 --- a/packages/nest/src/generators/library/lib/normalize-options.ts +++ b/packages/nest/src/generators/library/lib/normalize-options.ts @@ -64,7 +64,7 @@ export function toJsLibraryGeneratorOptions( ): JsLibraryGeneratorSchema { return { name: options.name, - bundler: options?.buildable ? 'tsc' : 'none', + bundler: options.buildable || options.publishable ? 'tsc' : 'none', directory: options.directory, importPath: options.importPath, linter: options.linter, diff --git a/packages/nest/src/generators/library/library.ts b/packages/nest/src/generators/library/library.ts index 4f9731d14a2817..9c48d74cb06874 100644 --- a/packages/nest/src/generators/library/library.ts +++ b/packages/nest/src/generators/library/library.ts @@ -1,6 +1,7 @@ import type { GeneratorCallback, Tree } from '@nx/devkit'; import { formatFiles, runTasksInSerial } from '@nx/devkit'; import { libraryGenerator as jsLibraryGenerator } from '@nx/js'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { addExportsToBarrelFile, addProject, @@ -29,6 +30,8 @@ export async function libraryGeneratorInternal( tree: Tree, rawOptions: LibraryGeneratorOptions ): Promise { + assertNotUsingTsSolutionSetup(tree, 'nest', 'library'); + const options = await normalizeOptions(tree, rawOptions); await jsLibraryGenerator(tree, toJsLibraryGeneratorOptions(options)); const initTask = await initGenerator(tree, rawOptions); diff --git a/packages/nest/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts b/packages/nest/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts deleted file mode 100644 index dc34380a630ad7..00000000000000 --- a/packages/nest/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Tree, readJson, updateJson } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import replacePackage from './update-16-0-0-add-nx-packages'; - -describe('update-16-0-0-add-nx-packages', () => { - let tree: Tree; - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - - updateJson(tree, 'package.json', (json) => { - json.devDependencies['@nrwl/nest'] = '16.0.0'; - return json; - }); - }); - - it('should remove the dependency on @nrwl/nest', async () => { - await replacePackage(tree); - - expect( - readJson(tree, 'package.json').dependencies['@nrwl/nest'] - ).not.toBeDefined(); - expect( - readJson(tree, 'package.json').devDependencies['@nrwl/nest'] - ).not.toBeDefined(); - }); - - it('should add a dependency on @nx/nest', async () => { - await replacePackage(tree); - - const packageJson = readJson(tree, 'package.json'); - const newDependencyVersion = - packageJson.devDependencies['@nx/nest'] ?? - packageJson.dependencies['@nx/nest']; - - expect(newDependencyVersion).toBeDefined(); - }); -}); diff --git a/packages/nest/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts b/packages/nest/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts deleted file mode 100644 index b8bc21758dafd0..00000000000000 --- a/packages/nest/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Tree, formatFiles } from '@nx/devkit'; -import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package'; - -export default async function replacePackage(tree: Tree): Promise { - await replaceNrwlPackageWithNxPackage(tree, '@nrwl/nest', '@nx/nest'); - - await formatFiles(tree); -} diff --git a/packages/nest/src/migrations/update-16-4-0-cache-manager/nestjs-10-updates.ts b/packages/nest/src/migrations/update-16-4-0-cache-manager/nestjs-10-updates.ts deleted file mode 100644 index 1178c5670e9af7..00000000000000 --- a/packages/nest/src/migrations/update-16-4-0-cache-manager/nestjs-10-updates.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { - Tree, - addDependenciesToPackageJson, - createProjectGraphAsync, - formatFiles, - getProjects, - joinPathFragments, - updateJson, - visitNotIgnoredFiles, -} from '@nx/devkit'; -import { tsquery } from '@phenomnomnominal/tsquery'; -import { - ImportDeclaration, - VariableStatement, - ScriptTarget, - isVariableStatement, -} from 'typescript'; - -const JS_TS_FILE_MATCHER = /\.[jt]sx?$/; - -const importMatch = - ':matches(ImportDeclaration, VariableStatement):has(Identifier[name="CacheModule"], Identifier[name="CacheModule"]):has(StringLiteral[value="@nestjs/common"])'; - -export async function updateNestJs10(tree: Tree) { - const nestProjects = await getNestProejcts(); - if (nestProjects.length === 0) { - return; - } - - let installCacheModuleDeps = false; - const projects = getProjects(tree); - - for (const projectName of nestProjects) { - const projectConfig = projects.get(projectName); - const tsConfig = - projectConfig.targets?.build?.options?.tsConfig ?? - joinPathFragments( - projectConfig.root, - projectConfig.projectType === 'application' - ? 'tsconfig.app.json' - : 'tsconfig.lib.json' - ); - - if (tree.exists(tsConfig)) { - updateTsConfigTarget(tree, tsConfig); - } - - visitNotIgnoredFiles(tree, projectConfig.root, (filePath) => { - if (!JS_TS_FILE_MATCHER.test(filePath)) { - return; - } - - installCacheModuleDeps = - updateCacheManagerImport(tree, filePath) || installCacheModuleDeps; - }); - } - - await formatFiles(tree); - - return installCacheModuleDeps - ? addDependenciesToPackageJson( - tree, - { - '@nestjs/cache-manager': '^2.0.0', - 'cache-manager': '^5.2.3', - }, - {} - ) - : () => {}; -} - -async function getNestProejcts(): Promise { - const projectGraph = await createProjectGraphAsync(); - - return Object.entries(projectGraph.dependencies) - .filter(([node, dep]) => - dep.some( - ({ target }) => - !projectGraph.externalNodes?.[node] && target === 'npm:@nestjs/common' - ) - ) - .map(([projectName]) => projectName); -} - -// change import { CacheModule } from '@nestjs/common'; -// to import { CacheModule } from '@nestjs/cache-manager'; -export function updateCacheManagerImport( - tree: Tree, - filePath: string -): boolean { - const content = tree.read(filePath, 'utf-8'); - - const updated = tsquery.replace( - content, - importMatch, - - (node: ImportDeclaration | VariableStatement) => { - const text = node.getText(); - return `${text.replace('CacheModule', '')}\n${ - isVariableStatement(node) - ? "const { CacheModule } = require('@nestjs/cache-manager')" - : "import { CacheModule } from '@nestjs/cache-manager';" - }`; - } - ); - - if (updated !== content) { - tree.write(filePath, updated); - return true; - } -} - -export function updateTsConfigTarget(tree: Tree, tsConfigPath: string) { - updateJson(tree, tsConfigPath, (json) => { - if (!json.compilerOptions.target) { - return json; - } - - const normalizedTargetName = json.compilerOptions.target.toUpperCase(); - // es6 isn't apart of the ScriptTarget enum but is a valid tsconfig target in json file - const existingTarget = - normalizedTargetName === 'ES6' - ? ScriptTarget.ES2015 - : (ScriptTarget[normalizedTargetName] as unknown as ScriptTarget); - - if (existingTarget < ScriptTarget.ES2021) { - json.compilerOptions.target = 'es2021'; - } - - return json; - }); -} - -export default updateNestJs10; diff --git a/packages/nest/src/migrations/update-16-4-0-cache-manager/nestjs-10.spec.ts b/packages/nest/src/migrations/update-16-4-0-cache-manager/nestjs-10.spec.ts deleted file mode 100644 index d17809dd887588..00000000000000 --- a/packages/nest/src/migrations/update-16-4-0-cache-manager/nestjs-10.spec.ts +++ /dev/null @@ -1,242 +0,0 @@ -import { - ProjectConfiguration, - ProjectGraph, - Tree, - addProjectConfiguration, - readJson, -} from '@nx/devkit'; -import { - updateNestJs10, - updateCacheManagerImport, - updateTsConfigTarget, -} from './nestjs-10-updates'; -import { createTreeWithEmptyWorkspace } from 'nx/src/devkit-testing-exports'; - -let projectGraph: ProjectGraph; -jest.mock('@nx/devkit', () => ({ - ...jest.requireActual('@nx/devkit'), - createProjectGraphAsync: () => Promise.resolve(projectGraph), -})); -describe('nestjs 10 migration changes', () => { - let tree: Tree; - beforeEach(() => { - tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); - - jest.resetAllMocks(); - }); - - it('should update nestjs project', async () => { - tree.write( - 'apps/app1/main.ts', - ` -/** - * This is not a production server yet! - * This is only a minimal backend to get started. - */ - -import { Logger } from '@nestjs/common'; -import { NestFactory } from '@nestjs/core'; -import { CacheModule } from '@nestjs/common'; -import { AppModule } from './app/app.module'; - -async function bootstrap() { - const app = await NestFactory.create(AppModule); - const globalPrefix = 'api'; - app.setGlobalPrefix(globalPrefix); - const port = process.env.PORT || 3000; - await app.listen(port); - Logger.log('🚀 Application is running on: http://localhost:' + port + '/' + globalPrefix); -} - -bootstrap(); -` - ); - - tree.write( - 'apps/app1/tsconfig.app.json', - JSON.stringify({ - extends: './tsconfig.json', - compilerOptions: { - outDir: '../../dist/out-tsc', - module: 'commonjs', - types: ['node'], - emitDecoratorMetadata: true, - target: 'es2015', - }, - exclude: ['jest.config.ts', 'src/**/*.spec.ts', 'src/**/*.test.ts'], - include: ['src/**/*.ts'], - }) - ); - addProject( - tree, - 'app1', - { - root: 'apps/app1', - targets: { - build: { - executor: '@nx/webpack:webpack', - options: { - tsConfig: 'apps/app1/tsconfig.app.json', - }, - }, - }, - }, - ['npm:@nestjs/common'] - ); - - await updateNestJs10(tree); - - expect(readJson(tree, 'package.json').dependencies).toMatchInlineSnapshot(` - { - "@nestjs/cache-manager": "^2.0.0", - "cache-manager": "^5.2.3", - } - `); - expect( - readJson(tree, 'apps/app1/tsconfig.app.json').compilerOptions.target - ).toEqual('es2021'); - expect(tree.read('apps/app1/main.ts', 'utf-8')).toContain( - "import { CacheModule } from '@nestjs/cache-manager';" - ); - }); - - it('should work with non buildable lib', async () => { - tree.write( - 'libs/lib1/src/lib/lib1.module.ts', - ` -import { Module, CacheModule } from '@nestjs/common'; - -@Module({ - controllers: [], - providers: [], - exports: [], - imports: [CacheModule.register()], -}) -export class LibOneModule {} -` - ); - - tree.write( - 'libs/lib1/tsconfig.lib.json', - JSON.stringify({ - extends: './tsconfig.json', - compilerOptions: { - outDir: '../../dist/out-tsc', - module: 'commonjs', - types: ['node'], - emitDecoratorMetadata: true, - target: 'es6', - }, - exclude: ['jest.config.ts', 'src/**/*.spec.ts', 'src/**/*.test.ts'], - include: ['src/**/*.ts'], - }) - ); - addProject( - tree, - 'app1', - { - root: 'libs/lib1', - targets: {}, - }, - ['npm:@nestjs/common'] - ); - - await updateNestJs10(tree); - - expect(readJson(tree, 'package.json').dependencies).toMatchInlineSnapshot(` - { - "@nestjs/cache-manager": "^2.0.0", - "cache-manager": "^5.2.3", - } - `); - expect( - readJson(tree, 'libs/lib1/tsconfig.lib.json').compilerOptions.target - ).toEqual('es2021'); - expect(tree.read('libs/lib1/src/lib/lib1.module.ts', 'utf-8')).toContain( - "import { CacheModule } from '@nestjs/cache-manager';" - ); - }); - - it('should update cache module import', () => { - tree.write( - 'main.ts', - ` -import { Module, CacheModule } from '@nestjs/common'; -const { Module, CacheModule } = require('@nestjs/common'); -` - ); - const actual = updateCacheManagerImport(tree, 'main.ts'); - - expect(tree.read('main.ts', 'utf-8')).toMatchInlineSnapshot(` - " - import { Module, } from '@nestjs/common'; - import { CacheModule } from '@nestjs/cache-manager'; - const { Module, } = require('@nestjs/common'); - const { CacheModule } = require('@nestjs/cache-manager') - " - `); - expect(actual).toBe(true); - }); - - it('should NOT update cache module imports', () => { - tree.write( - 'main.ts', - ` -import { AnotherModule } from '@nestjs/common'; -const { AnotherModule } = require('@nestjs/common'); -` - ); - const actual = updateCacheManagerImport(tree, 'main.ts'); - - expect(tree.read('main.ts', 'utf-8')).toMatchInlineSnapshot(` - " - import { AnotherModule } from '@nestjs/common'; - const { AnotherModule } = require('@nestjs/common'); - " - `); - expect(actual).toBeUndefined(); - }); - - it('should update script target', () => { - tree.write( - 'tsconfig.json', - JSON.stringify({ compilerOptions: { target: 'es6' } }) - ); - updateTsConfigTarget(tree, 'tsconfig.json'); - expect(readJson(tree, 'tsconfig.json').compilerOptions.target).toBe( - 'es2021' - ); - }); - - it('should NOT update script if over es2021', () => { - tree.write( - 'tsconfig.json', - JSON.stringify({ compilerOptions: { target: 'es2022' } }) - ); - updateTsConfigTarget(tree, 'tsconfig.json'); - expect(readJson(tree, 'tsconfig.json').compilerOptions.target).toBe( - 'es2022' - ); - }); -}); - -function addProject( - tree: Tree, - projectName: string, - config: ProjectConfiguration, - dependencies: string[] -): void { - projectGraph = { - dependencies: { - [projectName]: dependencies.map((d) => ({ - source: projectName, - target: d, - type: 'static', - })), - }, - nodes: { - [projectName]: { data: config, name: projectName, type: 'app' }, - }, - }; - addProjectConfiguration(tree, projectName, config); -} diff --git a/packages/next/migrations.json b/packages/next/migrations.json index 9d572c73d7c168..0e5a49d0914d07 100644 --- a/packages/next/migrations.json +++ b/packages/next/migrations.json @@ -1,23 +1,5 @@ { "generators": { - "update-16-0-0-add-nx-packages": { - "cli": "nx", - "version": "16.0.0-beta.1", - "description": "Replace @nrwl/next with @nx/next", - "implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages" - }, - "update-16-3-0-remove-root-build-option": { - "cli": "nx", - "version": "16.3.0-beta.9", - "description": "Remove root build option from project configurations since it is not needed.", - "implementation": "./src/migrations/update-16-3-0/remove-root-build-option" - }, - "update-16-4-0-update-next-dependency": { - "cli": "nx", - "version": "16.4.0-beta.3", - "description": "Update package.json moving @nx/next from dependency to devDependency", - "implementation": "./src/migrations/update-16-4-0/update-nx-next-dependency" - }, "update-17-2-7": { "cli": "nx", "version": "17.2.7", @@ -26,24 +8,6 @@ } }, "packageJsonUpdates": { - "16.0.0": { - "version": "16.0.0-beta.0", - "packages": { - "next": { - "version": "13.3.0", - "alwaysAddToPackageJson": false - } - } - }, - "16.4.0-beta.4": { - "version": "16.4.0-beta.4", - "packages": { - "stylus": { - "version": "^0.59.0", - "alwaysAddToPackageJson": false - } - } - }, "17.3.1-beta.0": { "version": "17.3.1-beta.0", "packages": { diff --git a/packages/next/src/generators/application/application.ts b/packages/next/src/generators/application/application.ts index a3bad423195645..d2e3f1bcc3eeb5 100644 --- a/packages/next/src/generators/application/application.ts +++ b/packages/next/src/generators/application/application.ts @@ -7,6 +7,7 @@ import { Tree, } from '@nx/devkit'; import { initGenerator as jsInitGenerator } from '@nx/js'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { setupTailwindGenerator } from '@nx/react'; import { testingLibraryReactVersion, @@ -39,6 +40,8 @@ export async function applicationGenerator(host: Tree, schema: Schema) { } export async function applicationGeneratorInternal(host: Tree, schema: Schema) { + assertNotUsingTsSolutionSetup(host, 'next', 'application'); + const tasks: GeneratorCallback[] = []; const options = await normalizeOptions(host, schema); diff --git a/packages/next/src/generators/init/init.ts b/packages/next/src/generators/init/init.ts index edbd50efe80ff3..adea0c246ca0b7 100644 --- a/packages/next/src/generators/init/init.ts +++ b/packages/next/src/generators/init/init.ts @@ -8,6 +8,7 @@ import { createProjectGraphAsync, } from '@nx/devkit'; import { addPluginV1 } from '@nx/devkit/src/utils/add-plugin'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { reactDomVersion, reactVersion } from '@nx/react/src/utils/versions'; import { addGitIgnoreEntry } from '../../utils/add-gitignore-entry'; import { nextVersion, nxVersion } from '../../utils/versions'; @@ -45,6 +46,8 @@ export async function nextInitGeneratorInternal( host: Tree, schema: InitSchema ) { + assertNotUsingTsSolutionSetup(host, 'next', 'init'); + const nxJson = readNxJson(host); const addPluginDefault = process.env.NX_ADD_PLUGINS !== 'false' && diff --git a/packages/next/src/generators/library/library.ts b/packages/next/src/generators/library/library.ts index b9fb9f9eef0c7b..f785ab1132e3e3 100644 --- a/packages/next/src/generators/library/library.ts +++ b/packages/next/src/generators/library/library.ts @@ -9,6 +9,7 @@ import { } from '@nx/devkit'; import { libraryGenerator as reactLibraryGenerator } from '@nx/react/src/generators/library/library'; import { addTsConfigPath, initGenerator as jsInitGenerator } from '@nx/js'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { testingLibraryReactVersion } from '@nx/react/src/utils/versions'; import { nextInitGenerator } from '../init/init'; @@ -24,6 +25,8 @@ export async function libraryGenerator(host: Tree, rawOptions: Schema) { } export async function libraryGeneratorInternal(host: Tree, rawOptions: Schema) { + assertNotUsingTsSolutionSetup(host, 'next', 'library'); + const options = await normalizeOptions(host, rawOptions); const tasks: GeneratorCallback[] = []; diff --git a/packages/next/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts b/packages/next/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts deleted file mode 100644 index 9e8a332ed3c328..00000000000000 --- a/packages/next/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Tree, readJson, updateJson } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import replacePackage from './update-16-0-0-add-nx-packages'; - -describe('update-16-0-0-add-nx-packages', () => { - let tree: Tree; - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - - updateJson(tree, 'package.json', (json) => { - json.devDependencies['@nrwl/next'] = '16.0.0'; - return json; - }); - }); - - it('should remove the dependency on @nrwl/next', async () => { - await replacePackage(tree); - - expect( - readJson(tree, 'package.json').dependencies['@nrwl/next'] - ).not.toBeDefined(); - expect( - readJson(tree, 'package.json').devDependencies['@nrwl/next'] - ).not.toBeDefined(); - }); - - it('should add a dependency on @nx/next', async () => { - await replacePackage(tree); - - const packageJson = readJson(tree, 'package.json'); - const newDependencyVersion = - packageJson.devDependencies['@nx/next'] ?? - packageJson.dependencies['@nx/next']; - - expect(newDependencyVersion).toBeDefined(); - }); -}); diff --git a/packages/next/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts b/packages/next/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts deleted file mode 100644 index 577d5dd438365e..00000000000000 --- a/packages/next/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Tree, formatFiles } from '@nx/devkit'; -import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package'; - -export default async function replacePackage(tree: Tree): Promise { - await replaceNrwlPackageWithNxPackage(tree, '@nrwl/next', '@nx/next'); - - await formatFiles(tree); -} diff --git a/packages/next/src/migrations/update-16-3-0/remove-root-build-option.spec.ts b/packages/next/src/migrations/update-16-3-0/remove-root-build-option.spec.ts deleted file mode 100644 index 7454b4406ea7de..00000000000000 --- a/packages/next/src/migrations/update-16-3-0/remove-root-build-option.spec.ts +++ /dev/null @@ -1,72 +0,0 @@ -import update from './remove-root-build-option'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import { - addProjectConfiguration, - readProjectConfiguration, - Tree, -} from '@nx/devkit'; - -describe('remove-root-build-option', () => { - let tree: Tree; - - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - }); - - it('should remove the root option from the build target for @nx/next:build executor', async () => { - addProjectConfiguration(tree, 'my-app', { - root: 'my-app', - targets: { - build: { - executor: '@nx/next:build', - options: { - root: 'my-app', - }, - }, - }, - }); - - await update(tree); - - const updatedConfig = readProjectConfiguration(tree, 'my-app'); - expect(updatedConfig.targets.build.options.root).toBeUndefined(); - }); - - it('should remove the root option from the build target for @nrwl/next:build executor', async () => { - addProjectConfiguration(tree, 'my-app', { - root: 'my-app', - targets: { - build: { - executor: '@nrwl/next:build', - options: { - root: 'my-app', - }, - }, - }, - }); - - await update(tree); - - const updatedConfig = readProjectConfiguration(tree, 'my-app'); - expect(updatedConfig.targets.build.options.root).toBeUndefined(); - }); - - it('should leave other executors alone', async () => { - addProjectConfiguration(tree, 'my-app', { - root: 'my-app', - targets: { - build: { - executor: '@acme/foo:bar', - options: { - root: 'my-app', - }, - }, - }, - }); - - await update(tree); - - const updatedConfig = readProjectConfiguration(tree, 'my-app'); - expect(updatedConfig.targets.build.options.root).toEqual('my-app'); - }); -}); diff --git a/packages/next/src/migrations/update-16-3-0/remove-root-build-option.ts b/packages/next/src/migrations/update-16-3-0/remove-root-build-option.ts deleted file mode 100644 index 0fc1d8a3d61d6d..00000000000000 --- a/packages/next/src/migrations/update-16-3-0/remove-root-build-option.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { - readProjectConfiguration, - Tree, - updateProjectConfiguration, -} from '@nx/devkit'; -import { forEachExecutorOptions } from '@nx/devkit/src/generators/executor-options-utils'; - -export default async function update(tree: Tree) { - forEachExecutorOptions( - tree, - '@nx/next:build', - (options, projectName, targetName) => { - const projectConfig = readProjectConfiguration(tree, projectName); - delete projectConfig.targets[targetName].options.root; - updateProjectConfiguration(tree, projectName, projectConfig); - } - ); - forEachExecutorOptions( - tree, - '@nrwl/next:build', - (options, projectName, targetName) => { - const projectConfig = readProjectConfiguration(tree, projectName); - delete projectConfig.targets[targetName].options.root; - updateProjectConfiguration(tree, projectName, projectConfig); - } - ); -} diff --git a/packages/next/src/migrations/update-16-4-0/update-nx-next-dependency.spec.ts b/packages/next/src/migrations/update-16-4-0/update-nx-next-dependency.spec.ts deleted file mode 100644 index ba3b4603f418a2..00000000000000 --- a/packages/next/src/migrations/update-16-4-0/update-nx-next-dependency.spec.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Tree, readJson, updateJson } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from 'nx/src/devkit-testing-exports'; -import update from './update-nx-next-dependency'; - -describe('update-nx-next-dependency', () => { - let tree: Tree; - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - - updateJson(tree, 'package.json', (json) => { - json.dependencies['@nx/next'] = '16.0.0'; - return json; - }); - }); - - it('should move @nx/next from dependencies to devDependencies', async () => { - await update(tree); - - expect( - readJson(tree, 'package.json').dependencies['@nx/next'] - ).not.toBeDefined(); - expect( - readJson(tree, 'package.json').devDependencies['@nx/next'] - ).toBeDefined(); - }); -}); diff --git a/packages/next/src/migrations/update-16-4-0/update-nx-next-dependency.ts b/packages/next/src/migrations/update-16-4-0/update-nx-next-dependency.ts deleted file mode 100644 index cebc2938099856..00000000000000 --- a/packages/next/src/migrations/update-16-4-0/update-nx-next-dependency.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Tree, formatFiles, updateJson } from '@nx/devkit'; -import type { PackageJson } from 'nx/src/utils/package-json'; - -export default async function update(tree: Tree) { - if (tree.exists('./package.json')) { - updateJson(tree, 'package.json', (packageJson) => { - if (packageJson.dependencies['@nx/next']) { - packageJson.devDependencies['@nx/next'] = - packageJson.dependencies['@nx/next']; - delete packageJson.dependencies['@nx/next']; - } - return packageJson; - }); - } - await formatFiles(tree); -} diff --git a/packages/node/migrations.json b/packages/node/migrations.json index 13b0d3de921ba3..e90c1b35e3d952 100644 --- a/packages/node/migrations.json +++ b/packages/node/migrations.json @@ -1,30 +1,5 @@ { - "generators": { - "update-16-0-0-add-nx-packages": { - "cli": "nx", - "version": "16.0.0-beta.1", - "description": "Replace @nrwl/node with @nx/node", - "implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages" - }, - "update-16-0-0-update-executor": { - "cli": "nx", - "version": "16.0.0-beta.5", - "description": "Replace @nrwl/node:webpack with @nx/node:webpack", - "implementation": "./src/migrations/update-16-0-0/update-webpack-executor" - }, - "update-16-3-1-update-executor": { - "cli": "nx", - "version": "16.3.1-beta.0", - "description": "Replace @nrwl/node:webpack and @nx/node:webpack with @nx/webpack:webpack for all project targets", - "implementation": "./src/migrations/update-16-3-1/update-webpack-executor" - }, - "update-16-4-0-replace-node-executor": { - "cli": "nx", - "version": "16.4.0-beta.8", - "description": "Replace @nx/node:node with @nx/js:node for all project targets", - "implementation": "./src/migrations/update-16-4-0/replace-node-executor" - } - }, + "generators": {}, "packageJsonUpdates": { "17.3.0": { "version": "17.3.0-beta.3", diff --git a/packages/node/src/generators/application/application.ts b/packages/node/src/generators/application/application.ts index 454005c5c8c1ea..b02534a0e4ca27 100644 --- a/packages/node/src/generators/application/application.ts +++ b/packages/node/src/generators/application/application.ts @@ -30,6 +30,7 @@ import { initGenerator as jsInitGenerator, tsConfigBaseOptions, } from '@nx/js'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { esbuildVersion } from '@nx/js/src/utils/versions'; import { Linter, lintProjectGenerator } from '@nx/eslint'; import { join } from 'path'; @@ -390,6 +391,8 @@ export async function applicationGenerator(tree: Tree, schema: Schema) { } export async function applicationGeneratorInternal(tree: Tree, schema: Schema) { + assertNotUsingTsSolutionSetup(tree, 'node', 'application'); + const options = await normalizeOptions(tree, schema); const tasks: GeneratorCallback[] = []; diff --git a/packages/node/src/generators/init/init.ts b/packages/node/src/generators/init/init.ts index a7d1dce3122e0d..95b34a31344bcf 100644 --- a/packages/node/src/generators/init/init.ts +++ b/packages/node/src/generators/init/init.ts @@ -6,6 +6,7 @@ import { runTasksInSerial, Tree, } from '@nx/devkit'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { nxVersion } from '../../utils/versions'; import { Schema } from './schema'; @@ -26,6 +27,8 @@ function updateDependencies(tree: Tree, options: Schema) { } export async function initGenerator(tree: Tree, options: Schema) { + assertNotUsingTsSolutionSetup(tree, 'node', 'init'); + let installTask: GeneratorCallback = () => {}; if (!options.skipPackageJson) { installTask = updateDependencies(tree, options); diff --git a/packages/node/src/generators/library/library.ts b/packages/node/src/generators/library/library.ts index d2dc70409a2d62..d5eef8892372c6 100644 --- a/packages/node/src/generators/library/library.ts +++ b/packages/node/src/generators/library/library.ts @@ -21,6 +21,7 @@ import { import { libraryGenerator as jsLibraryGenerator } from '@nx/js'; import { addSwcConfig } from '@nx/js/src/utils/swc/add-swc-config'; import { addSwcDependencies } from '@nx/js/src/utils/swc/add-swc-dependencies'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { join } from 'path'; import { tslibVersion, typesNodeVersion } from '../../utils/versions'; import { initGenerator } from '../init/init'; @@ -43,6 +44,8 @@ export async function libraryGenerator(tree: Tree, schema: Schema) { } export async function libraryGeneratorInternal(tree: Tree, schema: Schema) { + assertNotUsingTsSolutionSetup(tree, 'node', 'library'); + const options = await normalizeOptions(tree, schema); const tasks: GeneratorCallback[] = [ await initGenerator(tree, { @@ -59,7 +62,7 @@ export async function libraryGeneratorInternal(tree: Tree, schema: Schema) { const libraryInstall = await jsLibraryGenerator(tree, { ...options, - bundler: schema.buildable ? 'tsc' : 'none', + bundler: schema.buildable || schema.publishable ? 'tsc' : 'none', includeBabelRc: schema.babelJest, importPath: options.importPath, testEnvironment: 'node', diff --git a/packages/node/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts b/packages/node/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts deleted file mode 100644 index 0b72ce84879c38..00000000000000 --- a/packages/node/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Tree, readJson, updateJson } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import replacePackage from './update-16-0-0-add-nx-packages'; - -describe('update-16-0-0-add-nx-packages', () => { - let tree: Tree; - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - - updateJson(tree, 'package.json', (json) => { - json.devDependencies['@nrwl/node'] = '16.0.0'; - return json; - }); - }); - - it('should remove the dependency on @nrwl/node', async () => { - await replacePackage(tree); - - expect( - readJson(tree, 'package.json').dependencies['@nrwl/node'] - ).not.toBeDefined(); - expect( - readJson(tree, 'package.json').devDependencies['@nrwl/node'] - ).not.toBeDefined(); - }); - - it('should add a dependency on @nx/node', async () => { - await replacePackage(tree); - - const packageJson = readJson(tree, 'package.json'); - const newDependencyVersion = - packageJson.devDependencies['@nx/node'] ?? - packageJson.dependencies['@nx/node']; - - expect(newDependencyVersion).toBeDefined(); - }); -}); diff --git a/packages/node/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts b/packages/node/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts deleted file mode 100644 index aa0821ebae2555..00000000000000 --- a/packages/node/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Tree, formatFiles } from '@nx/devkit'; -import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package'; - -export default async function replacePackage(tree: Tree): Promise { - await replaceNrwlPackageWithNxPackage(tree, '@nrwl/node', '@nx/node'); - - await formatFiles(tree); -} diff --git a/packages/node/src/migrations/update-16-0-0/update-webpack-executor.spec.ts b/packages/node/src/migrations/update-16-0-0/update-webpack-executor.spec.ts deleted file mode 100644 index 6af63c248b2ceb..00000000000000 --- a/packages/node/src/migrations/update-16-0-0/update-webpack-executor.spec.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { addProjectConfiguration, readProjectConfiguration } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; - -import update from './update-webpack-executor'; - -describe('Migration: @nrwl/webpack', () => { - it(`should update usage of webpack executor`, async () => { - let tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); - - addProjectConfiguration(tree, 'myapp', { - root: 'apps/myapp', - sourceRoot: 'apps/myapp/src', - projectType: 'application', - targets: { - foo: { - executor: '@nrwl/node:webpack', - options: {}, - }, - bar: { - executor: '@nx/node:webpack', - options: {}, - }, - }, - }); - - await update(tree); - - expect(readProjectConfiguration(tree, 'myapp')).toEqual({ - $schema: '../../node_modules/nx/schemas/project-schema.json', - name: 'myapp', - root: 'apps/myapp', - sourceRoot: 'apps/myapp/src', - projectType: 'application', - targets: { - foo: { - executor: '@nx/webpack:webpack', - options: { - compiler: 'tsc', - target: 'node', - }, - }, - bar: { - executor: '@nx/webpack:webpack', - options: { - compiler: 'tsc', - target: 'node', - }, - }, - }, - }); - }); -}); diff --git a/packages/node/src/migrations/update-16-0-0/update-webpack-executor.ts b/packages/node/src/migrations/update-16-0-0/update-webpack-executor.ts deleted file mode 100644 index faf23d5e301eae..00000000000000 --- a/packages/node/src/migrations/update-16-0-0/update-webpack-executor.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { - formatFiles, - readProjectConfiguration, - Tree, - updateProjectConfiguration, -} from '@nx/devkit'; -import { forEachExecutorOptions } from '@nx/devkit/src/generators/executor-options-utils'; - -export default async function update(tree: Tree) { - const migrateProject = (options, projectName, targetName) => { - const projectConfig = readProjectConfiguration(tree, projectName); - projectConfig.targets[targetName].executor = '@nx/webpack:webpack'; - projectConfig.targets[targetName].options.compiler = 'tsc'; - projectConfig.targets[targetName].options.target = 'node'; - updateProjectConfiguration(tree, projectName, projectConfig); - }; - - forEachExecutorOptions(tree, '@nx/node:webpack', migrateProject); - forEachExecutorOptions(tree, '@nrwl/node:webpack', migrateProject); - - await formatFiles(tree); -} diff --git a/packages/node/src/migrations/update-16-3-1/update-webpack-executor.spec.ts b/packages/node/src/migrations/update-16-3-1/update-webpack-executor.spec.ts deleted file mode 100644 index 6af63c248b2ceb..00000000000000 --- a/packages/node/src/migrations/update-16-3-1/update-webpack-executor.spec.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { addProjectConfiguration, readProjectConfiguration } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; - -import update from './update-webpack-executor'; - -describe('Migration: @nrwl/webpack', () => { - it(`should update usage of webpack executor`, async () => { - let tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); - - addProjectConfiguration(tree, 'myapp', { - root: 'apps/myapp', - sourceRoot: 'apps/myapp/src', - projectType: 'application', - targets: { - foo: { - executor: '@nrwl/node:webpack', - options: {}, - }, - bar: { - executor: '@nx/node:webpack', - options: {}, - }, - }, - }); - - await update(tree); - - expect(readProjectConfiguration(tree, 'myapp')).toEqual({ - $schema: '../../node_modules/nx/schemas/project-schema.json', - name: 'myapp', - root: 'apps/myapp', - sourceRoot: 'apps/myapp/src', - projectType: 'application', - targets: { - foo: { - executor: '@nx/webpack:webpack', - options: { - compiler: 'tsc', - target: 'node', - }, - }, - bar: { - executor: '@nx/webpack:webpack', - options: { - compiler: 'tsc', - target: 'node', - }, - }, - }, - }); - }); -}); diff --git a/packages/node/src/migrations/update-16-3-1/update-webpack-executor.ts b/packages/node/src/migrations/update-16-3-1/update-webpack-executor.ts deleted file mode 100644 index faf23d5e301eae..00000000000000 --- a/packages/node/src/migrations/update-16-3-1/update-webpack-executor.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { - formatFiles, - readProjectConfiguration, - Tree, - updateProjectConfiguration, -} from '@nx/devkit'; -import { forEachExecutorOptions } from '@nx/devkit/src/generators/executor-options-utils'; - -export default async function update(tree: Tree) { - const migrateProject = (options, projectName, targetName) => { - const projectConfig = readProjectConfiguration(tree, projectName); - projectConfig.targets[targetName].executor = '@nx/webpack:webpack'; - projectConfig.targets[targetName].options.compiler = 'tsc'; - projectConfig.targets[targetName].options.target = 'node'; - updateProjectConfiguration(tree, projectName, projectConfig); - }; - - forEachExecutorOptions(tree, '@nx/node:webpack', migrateProject); - forEachExecutorOptions(tree, '@nrwl/node:webpack', migrateProject); - - await formatFiles(tree); -} diff --git a/packages/node/src/migrations/update-16-4-0/replace-node-executor.spec.ts b/packages/node/src/migrations/update-16-4-0/replace-node-executor.spec.ts deleted file mode 100644 index 3e947bf22c254b..00000000000000 --- a/packages/node/src/migrations/update-16-4-0/replace-node-executor.spec.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { addProjectConfiguration, readProjectConfiguration } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import update from './replace-node-executor'; - -describe('Migration: replace @nx/node:node executor', () => { - it(`should replace @nx/node:node executor with @nx/js:node`, async () => { - let tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); - - addProjectConfiguration(tree, 'myapp', { - root: 'apps/myapp', - sourceRoot: 'apps/myapp/src', - projectType: 'application', - targets: { - foo: { - executor: '@nx/node:node', - options: {}, - }, - bar: { - executor: '@nx/node:node', - options: {}, - }, - }, - }); - - addProjectConfiguration(tree, 'myapp2', { - root: 'apps/myapp2', - sourceRoot: 'apps/myapp2/src', - projectType: 'application', - targets: { - foo: { - executor: '@nx/node:node', - options: {}, - }, - bar: { - executor: '@nx/node:node', - options: {}, - }, - }, - }); - - await update(tree); - - expect(readProjectConfiguration(tree, 'myapp')).toEqual({ - $schema: '../../node_modules/nx/schemas/project-schema.json', - name: 'myapp', - root: 'apps/myapp', - sourceRoot: 'apps/myapp/src', - projectType: 'application', - targets: { - foo: { - executor: '@nx/js:node', - options: {}, - }, - bar: { - executor: '@nx/js:node', - options: {}, - }, - }, - }); - - expect(readProjectConfiguration(tree, 'myapp2')).toEqual({ - $schema: '../../node_modules/nx/schemas/project-schema.json', - name: 'myapp2', - root: 'apps/myapp2', - sourceRoot: 'apps/myapp2/src', - projectType: 'application', - targets: { - foo: { - executor: '@nx/js:node', - options: {}, - }, - bar: { - executor: '@nx/js:node', - options: {}, - }, - }, - }); - }); -}); diff --git a/packages/node/src/migrations/update-16-4-0/replace-node-executor.ts b/packages/node/src/migrations/update-16-4-0/replace-node-executor.ts deleted file mode 100644 index 950413dea1dac2..00000000000000 --- a/packages/node/src/migrations/update-16-4-0/replace-node-executor.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { - formatFiles, - readProjectConfiguration, - Tree, - updateProjectConfiguration, -} from '@nx/devkit'; -import { forEachExecutorOptions } from '@nx/devkit/src/generators/executor-options-utils'; - -export default async function update(tree: Tree) { - const migrateProject = (_options, projectName, targetName) => { - const projectConfig = readProjectConfiguration(tree, projectName); - projectConfig.targets[targetName].executor = '@nx/js:node'; - updateProjectConfiguration(tree, projectName, projectConfig); - }; - - forEachExecutorOptions(tree, '@nx/node:node', migrateProject); - - await formatFiles(tree); -} diff --git a/packages/nuxt/src/generators/application/application.ts b/packages/nuxt/src/generators/application/application.ts index 0a0b7e4edf06f9..97bb4c946189fe 100644 --- a/packages/nuxt/src/generators/application/application.ts +++ b/packages/nuxt/src/generators/application/application.ts @@ -18,6 +18,7 @@ import { getRelativePathToRootTsConfig, initGenerator as jsInitGenerator, } from '@nx/js'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { updateGitIgnore } from '../../utils/update-gitignore'; import { Linter } from '@nx/eslint'; import { addE2e } from './lib/add-e2e'; @@ -33,6 +34,8 @@ import { } from 'nx/src/nx-cloud/utilities/onboarding'; export async function applicationGenerator(tree: Tree, schema: Schema) { + assertNotUsingTsSolutionSetup(tree, 'nuxt', 'application'); + const tasks: GeneratorCallback[] = []; const options = await normalizeOptions(tree, schema); diff --git a/packages/nuxt/src/generators/init/init.ts b/packages/nuxt/src/generators/init/init.ts index 1bc971e19b9049..5eef7f78ea4771 100644 --- a/packages/nuxt/src/generators/init/init.ts +++ b/packages/nuxt/src/generators/init/init.ts @@ -1,11 +1,14 @@ import { createProjectGraphAsync, GeneratorCallback, Tree } from '@nx/devkit'; import { addPluginV1 } from '@nx/devkit/src/utils/add-plugin'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { createNodes } from '../../plugins/plugin'; import { InitSchema } from './schema'; import { updateDependencies } from './lib/utils'; export async function nuxtInitGenerator(host: Tree, schema: InitSchema) { + assertNotUsingTsSolutionSetup(host, 'nuxt', 'init'); + await addPluginV1( host, await createProjectGraphAsync(), diff --git a/packages/nx/.eslintrc.json b/packages/nx/.eslintrc.json index f3132262034acd..040a6956efd776 100644 --- a/packages/nx/.eslintrc.json +++ b/packages/nx/.eslintrc.json @@ -9,8 +9,18 @@ "no-restricted-imports": [ "error", { - "name": "fs-extra", - "message": "Please use equivalent utilities from `node:fs` instead." + "paths": [ + { + "name": "fs-extra", + "message": "Please use equivalent utilities from `node:fs` instead." + } + ], + "patterns": [ + { + "group": ["**/devkit-exports"], + "message": "Do not import from devkit-exports from the nx package" + } + ] } ] } diff --git a/packages/nx/migrations.json b/packages/nx/migrations.json index 1a495445cee323..465e2c5a72181f 100644 --- a/packages/nx/migrations.json +++ b/packages/nx/migrations.json @@ -1,42 +1,5 @@ { "generators": { - "16.0.0-remove-nrwl-cli": { - "cli": "nx", - "version": "16.0.0-beta.0", - "description": "Remove @nrwl/cli.", - "implementation": "./src/migrations/update-16-0-0/remove-nrwl-cli" - }, - "16.0.0-tokens-for-depends-on": { - "cli": "nx", - "version": "16.0.0-beta.9", - "description": "Replace `dependsOn.projects` and `inputs` definitions with new configuration format.", - "implementation": "./src/migrations/update-16-0-0/update-depends-on-to-tokens" - }, - "16.0.0-update-nx-cloud-runner": { - "cli": "nx", - "version": "16.0.0-beta.0", - "description": "Replace @nrwl/nx-cloud with nx-cloud", - "implementation": "./src/migrations/update-16-0-0/update-nx-cloud-runner" - }, - "16.2.0-remove-output-path-from-run-commands": { - "cli": "nx", - "version": "16.2.0-beta.0", - "description": "Remove outputPath from run commands", - "implementation": "./src/migrations/update-16-2-0/remove-run-commands-output-path" - }, - "16.6.0-prefix-outputs": { - "cli": "nx", - "version": "16.6.0-beta.6", - "description": "Prefix outputs with {workspaceRoot}/{projectRoot} if needed", - "implementation": "./src/migrations/update-15-0-0/prefix-outputs" - }, - "16.8.0-escape-dollar-sign-env": { - "cli": "nx", - "version": "16.8.0-beta.3", - "description": "Escape $ in env variables", - "implementation": "./src/migrations/update-16-8-0/escape-dollar-sign-env-variables", - "x-repair-skip": true - }, "17.0.0-move-cache-directory": { "cli": "nx", "version": "17.0.0-beta.1", diff --git a/packages/nx/release/changelog-renderer/index.spec.ts b/packages/nx/release/changelog-renderer/index.spec.ts index 2f33a089dde5f8..e1c04b8a800137 100644 --- a/packages/nx/release/changelog-renderer/index.spec.ts +++ b/packages/nx/release/changelog-renderer/index.spec.ts @@ -1,6 +1,6 @@ import type { ChangelogChange } from '../../src/command-line/release/changelog'; import { DEFAULT_CONVENTIONAL_COMMITS_CONFIG } from '../../src/command-line/release/config/conventional-commits'; -import defaultChangelogRenderer from './index'; +import DefaultChangelogRenderer from './index'; jest.mock('../../src/project-graph/file-map-utils', () => ({ createFileMapUsingProjectGraph: jest.fn().mockImplementation(() => { @@ -25,17 +25,16 @@ jest.mock('../../src/project-graph/file-map-utils', () => ({ }), })); -describe('defaultChangelogRenderer()', () => { - const projectGraph = { - nodes: {}, - } as any; +describe('ChangelogRenderer', () => { const changes: ChangelogChange[] = [ { shortHash: '4130f65', - author: { - name: 'James Henry', - email: 'jh@example.com', - }, + authors: [ + { + name: 'James Henry', + email: 'jh@example.com', + }, + ], body: '"\n\nM\tpackages/pkg-a/src/index.ts\nM\tpackages/pkg-b/src/index.ts\n"', description: 'all packages fixed', type: 'fix', @@ -52,10 +51,12 @@ describe('defaultChangelogRenderer()', () => { }, { shortHash: '7dc5ec3', - author: { - name: 'James Henry', - email: 'jh@example.com', - }, + authors: [ + { + name: 'James Henry', + email: 'jh@example.com', + }, + ], body: '"\n\nM\tpackages/pkg-b/src/index.ts\n"', description: 'and another new capability', type: 'feat', @@ -72,10 +73,12 @@ describe('defaultChangelogRenderer()', () => { }, { shortHash: 'd7a58a2', - author: { - name: 'James Henry', - email: 'jh@example.com', - }, + authors: [ + { + name: 'James Henry', + email: 'jh@example.com', + }, + ], body: '"\n\nM\tpackages/pkg-a/src/index.ts\n"', description: 'new hotness', type: 'feat', @@ -92,10 +95,12 @@ describe('defaultChangelogRenderer()', () => { }, { shortHash: 'feace4a', - author: { - name: 'James Henry', - email: 'jh@example.com', - }, + authors: [ + { + name: 'James Henry', + email: 'jh@example.com', + }, + ], body: '"\n\nM\tpackages/pkg-b/src/index.ts\n"', description: 'brand new thing', type: 'feat', @@ -112,10 +117,12 @@ describe('defaultChangelogRenderer()', () => { }, { shortHash: '6301405', - author: { - name: 'James Henry', - email: 'jh@example.com', - }, + authors: [ + { + name: 'James Henry', + email: 'jh@example.com', + }, + ], body: '"\n\nM\tpackages/pkg-a/src/index.ts\n', description: 'squashing bugs', type: 'fix', @@ -132,601 +139,712 @@ describe('defaultChangelogRenderer()', () => { }, ]; - describe('workspaceChangelog', () => { - it('should generate markdown for all projects by organizing commits by type, then grouped by scope within the type (sorted alphabetically), then chronologically within the scope group', async () => { - const markdown = await defaultChangelogRenderer({ - projectGraph, - changes, - releaseVersion: 'v1.1.0', - project: null, - entryWhenNoChanges: false, - changelogRenderOptions: { - authors: true, - }, - conventionalCommitsConfig: DEFAULT_CONVENTIONAL_COMMITS_CONFIG, - }); - expect(markdown).toMatchInlineSnapshot(` - "## v1.1.0 - - - ### 🚀 Features + describe('DefaultChangelogRenderer', () => { + describe('workspaceChangelog', () => { + it('should generate markdown for all projects by organizing commits by type, then grouped by scope within the type (sorted alphabetically), then chronologically within the scope group', async () => { + const renderer = new DefaultChangelogRenderer({ + changes, + changelogEntryVersion: 'v1.1.0', + project: null, + isVersionPlans: false, + entryWhenNoChanges: false, + changelogRenderOptions: { + authors: true, + }, + conventionalCommitsConfig: DEFAULT_CONVENTIONAL_COMMITS_CONFIG, + }); + const markdown = await renderer.render(); + expect(markdown).toMatchInlineSnapshot(` + "## v1.1.0 - - **pkg-a:** new hotness - - **pkg-b:** brand new thing - - **pkg-b:** and another new capability + ### 🚀 Features - ### 🩹 Fixes + - **pkg-a:** new hotness + - **pkg-b:** brand new thing + - **pkg-b:** and another new capability - - all packages fixed - - **pkg-a:** squashing bugs + ### 🩹 Fixes - ### ❤️ Thank You + - all packages fixed + - **pkg-a:** squashing bugs - - James Henry" - `); - }); + ### ❤️ Thank You - it('should not generate a Thank You section when changelogRenderOptions.authors is false', async () => { - const markdown = await defaultChangelogRenderer({ - projectGraph, - changes, - // Major version, should use single # for generated heading - releaseVersion: 'v1.0.0', - project: null, - entryWhenNoChanges: false, - changelogRenderOptions: { - authors: false, - }, - conventionalCommitsConfig: DEFAULT_CONVENTIONAL_COMMITS_CONFIG, + - James Henry" + `); }); - expect(markdown).toMatchInlineSnapshot(` - "# v1.0.0 + it('should not generate a Thank You section when changelogRenderOptions.authors is false', async () => { + const renderer = new DefaultChangelogRenderer({ + changes, + // Major version, should use single # for generated heading + changelogEntryVersion: 'v1.0.0', + project: null, + isVersionPlans: false, + entryWhenNoChanges: false, + changelogRenderOptions: { + authors: false, + }, + conventionalCommitsConfig: DEFAULT_CONVENTIONAL_COMMITS_CONFIG, + }); + const markdown = await renderer.render(); + expect(markdown).toMatchInlineSnapshot(` + "# v1.0.0 - ### 🚀 Features + ### 🚀 Features - - **pkg-a:** new hotness - - **pkg-b:** brand new thing - - **pkg-b:** and another new capability + - **pkg-a:** new hotness + - **pkg-b:** brand new thing + - **pkg-b:** and another new capability - ### 🩹 Fixes + ### 🩹 Fixes - - all packages fixed - - **pkg-a:** squashing bugs" - `); + - all packages fixed + - **pkg-a:** squashing bugs" + `); + }); }); - }); - - describe('project level configs', () => { - it('should generate markdown for the given project by organizing commits by type, then chronologically', async () => { - const otherOpts = { - projectGraph, - changes, - releaseVersion: 'v1.1.0', - entryWhenNoChanges: false as const, - changelogRenderOptions: { - authors: true, - }, - conventionalCommitsConfig: DEFAULT_CONVENTIONAL_COMMITS_CONFIG, - }; - - expect( - await defaultChangelogRenderer({ - ...otherOpts, - project: 'pkg-a', - }) - ).toMatchInlineSnapshot(` - "## v1.1.0 - - - ### 🚀 Features - - - **pkg-a:** new hotness - - - ### 🩹 Fixes - - - all packages fixed - - - **pkg-a:** squashing bugs - - ### ❤️ Thank You - - - James Henry" - `); - - expect( - await defaultChangelogRenderer({ - ...otherOpts, - project: 'pkg-a', - // test that the authors option is being respected for project changelogs and therefore no Thank You section exists + describe('project level configs', () => { + it('should generate markdown for the given project by organizing commits by type, then chronologically', async () => { + const otherOpts = { + changes, + changelogEntryVersion: 'v1.1.0', + entryWhenNoChanges: false as const, + isVersionPlans: false, changelogRenderOptions: { - authors: false, + authors: true, }, - }) - ).toMatchInlineSnapshot(` - "## v1.1.0 + conventionalCommitsConfig: DEFAULT_CONVENTIONAL_COMMITS_CONFIG, + }; + expect( + await new DefaultChangelogRenderer({ + ...otherOpts, + project: 'pkg-a', + }).render() + ).toMatchInlineSnapshot(` + "## v1.1.0 - ### 🚀 Features + ### 🚀 Features - - **pkg-a:** new hotness + - **pkg-a:** new hotness + ### 🩹 Fixes - ### 🩹 Fixes + - all packages fixed + - **pkg-a:** squashing bugs - - all packages fixed + ### ❤️ Thank You - - **pkg-a:** squashing bugs" - `); + - James Henry" + `); - expect( - await defaultChangelogRenderer({ - ...otherOpts, - project: 'pkg-b', - }) - ).toMatchInlineSnapshot(` - "## v1.1.0 + expect( + await new DefaultChangelogRenderer({ + ...otherOpts, + project: 'pkg-a', + // test that the authors option is being respected for project changelogs and therefore no Thank You section exists + changelogRenderOptions: { + authors: false, + }, + }).render() + ).toMatchInlineSnapshot(` + "## v1.1.0 + ### 🚀 Features - ### 🚀 Features + - **pkg-a:** new hotness - - **pkg-b:** brand new thing + ### 🩹 Fixes - - **pkg-b:** and another new capability + - all packages fixed + - **pkg-a:** squashing bugs" + `); + expect( + await new DefaultChangelogRenderer({ + ...otherOpts, + project: 'pkg-b', + }).render() + ).toMatchInlineSnapshot(` + "## v1.1.0 - ### 🩹 Fixes + ### 🚀 Features - - all packages fixed + - **pkg-b:** and another new capability + - **pkg-b:** brand new thing + ### 🩹 Fixes - ### ❤️ Thank You + - all packages fixed - - James Henry" - `); - }); + ### ❤️ Thank You - it('should only include authors relevant to the specific project', async () => { - const changes: ChangelogChange[] = [ - { - shortHash: '4130f65', - author: { - name: 'Author 1', - email: 'author-1@example.com', + - James Henry" + `); + }); + + it('should only include authors relevant to the specific project', async () => { + const changes: ChangelogChange[] = [ + { + shortHash: '4130f65', + authors: [ + { + name: 'Author 1', + email: 'author-1@example.com', + }, + ], + body: '"\n\nM\tpackages/pkg-a/src/index.ts\nM\tpackages/pkg-b/src/index.ts\n"', + description: 'all packages fixed', + type: 'fix', + scope: '', + githubReferences: [ + { + value: '4130f65', + type: 'hash', + }, + ], + isBreaking: false, + revertedHashes: [], + affectedProjects: ['pkg-a', 'pkg-b'], }, - body: '"\n\nM\tpackages/pkg-a/src/index.ts\nM\tpackages/pkg-b/src/index.ts\n"', - description: 'all packages fixed', - type: 'fix', - scope: '', - githubReferences: [ - { - value: '4130f65', - type: 'hash', - }, - ], - isBreaking: false, - revertedHashes: [], - affectedProjects: ['pkg-a', 'pkg-b'], - }, - { - shortHash: '7dc5ec3', - author: { - name: 'Author 2', - email: 'author-2@example.com', + { + shortHash: '7dc5ec3', + authors: [ + { + name: 'Author 2', + email: 'author-2@example.com', + }, + ], + body: '"\n\nM\tpackages/pkg-b/src/index.ts\n"', + description: 'and another new capability', + type: 'feat', + scope: 'pkg-b', + githubReferences: [ + { + value: '7dc5ec3', + type: 'hash', + }, + ], + isBreaking: false, + revertedHashes: [], + affectedProjects: ['pkg-b'], }, - body: '"\n\nM\tpackages/pkg-b/src/index.ts\n"', - description: 'and another new capability', - type: 'feat', - scope: 'pkg-b', - githubReferences: [ - { - value: '7dc5ec3', - type: 'hash', - }, - ], - isBreaking: false, - revertedHashes: [], - affectedProjects: ['pkg-b'], - }, - { - shortHash: 'd7a58a2', - author: { - name: 'Author 3', - email: 'author-3@example.com', + { + shortHash: 'd7a58a2', + authors: [ + { + name: 'Author 3', + email: 'author-3@example.com', + }, + ], + body: '"\n\nM\tpackages/pkg-a/src/index.ts\n"', + description: 'new hotness', + type: 'feat', + scope: 'pkg-a', + githubReferences: [ + { + value: 'd7a58a2', + type: 'hash', + }, + ], + isBreaking: false, + revertedHashes: [], + affectedProjects: ['pkg-a'], }, - body: '"\n\nM\tpackages/pkg-a/src/index.ts\n"', - description: 'new hotness', - type: 'feat', - scope: 'pkg-a', - githubReferences: [ - { - value: 'd7a58a2', - type: 'hash', - }, - ], - isBreaking: false, - revertedHashes: [], - affectedProjects: ['pkg-a'], - }, - { - shortHash: 'feace4a', - author: { - name: 'Author 4', - email: 'author-4@example.com', + { + shortHash: 'feace4a', + authors: [ + { + name: 'Author 4', + email: 'author-4@example.com', + }, + ], + body: '"\n\nM\tpackages/pkg-b/src/index.ts\n"', + description: 'brand new thing', + type: 'feat', + scope: 'pkg-b', + githubReferences: [ + { + value: 'feace4a', + type: 'hash', + }, + ], + isBreaking: false, + revertedHashes: [], + affectedProjects: ['pkg-b'], }, - body: '"\n\nM\tpackages/pkg-b/src/index.ts\n"', - description: 'brand new thing', - type: 'feat', - scope: 'pkg-b', - githubReferences: [ - { - value: 'feace4a', - type: 'hash', - }, - ], - isBreaking: false, - revertedHashes: [], - affectedProjects: ['pkg-b'], - }, - { - shortHash: '6301405', - author: { - name: 'Author 5', - email: 'author-5@example.com', + { + shortHash: '6301405', + authors: [ + { + name: 'Author 5', + email: 'author-5@example.com', + }, + ], + body: '"\n\nM\tpackages/pkg-a/src/index.ts\n', + description: 'squashing bugs', + type: 'fix', + scope: 'pkg-a', + githubReferences: [ + { + value: '6301405', + type: 'hash', + }, + ], + isBreaking: false, + revertedHashes: [], + affectedProjects: ['pkg-a'], }, - body: '"\n\nM\tpackages/pkg-a/src/index.ts\n', - description: 'squashing bugs', - type: 'fix', - scope: 'pkg-a', - githubReferences: [ - { - value: '6301405', - type: 'hash', - }, - ], - isBreaking: false, - revertedHashes: [], - affectedProjects: ['pkg-a'], - }, - ]; - - const otherOpts = { - projectGraph, - changes, - releaseVersion: 'v1.1.0', - entryWhenNoChanges: false as const, - changelogRenderOptions: { - authors: true, - }, - conventionalCommitsConfig: DEFAULT_CONVENTIONAL_COMMITS_CONFIG, - }; - - expect( - await defaultChangelogRenderer({ - ...otherOpts, - project: 'pkg-a', - }) - ).toMatchInlineSnapshot(` - "## v1.1.0 - - - ### 🚀 Features + ]; - - **pkg-a:** new hotness + const otherOpts = { + changes, + changelogEntryVersion: 'v1.1.0', + entryWhenNoChanges: false as const, + isVersionPlans: false, + changelogRenderOptions: { + authors: true, + }, + conventionalCommitsConfig: DEFAULT_CONVENTIONAL_COMMITS_CONFIG, + }; + expect( + await new DefaultChangelogRenderer({ + ...otherOpts, + project: 'pkg-a', + }).render() + ).toMatchInlineSnapshot(` + "## v1.1.0 - ### 🩹 Fixes + ### 🚀 Features - - all packages fixed + - **pkg-a:** new hotness - - **pkg-a:** squashing bugs + ### 🩹 Fixes + - all packages fixed + - **pkg-a:** squashing bugs - ### ❤️ Thank You + ### ❤️ Thank You - - Author 1 - - Author 3 - - Author 5" - `); + - Author 1 + - Author 3 + - Author 5" + `); - expect( - await defaultChangelogRenderer({ - ...otherOpts, - project: 'pkg-b', - }) - ).toMatchInlineSnapshot(` - "## v1.1.0 + expect( + await new DefaultChangelogRenderer({ + ...otherOpts, + project: 'pkg-b', + }).render() + ).toMatchInlineSnapshot(` + "## v1.1.0 + ### 🚀 Features - ### 🚀 Features + - **pkg-b:** and another new capability + - **pkg-b:** brand new thing - - **pkg-b:** brand new thing + ### 🩹 Fixes - - **pkg-b:** and another new capability + - all packages fixed + ### ❤️ Thank You - ### 🩹 Fixes - - - all packages fixed - + - Author 1 + - Author 2 + - Author 4" + `); + }); + }); - ### ❤️ Thank You + describe('entryWhenNoChanges', () => { + it('should respect the entryWhenNoChanges option for the workspace changelog', async () => { + const otherOpts = { + changes: [], + changelogEntryVersion: 'v1.1.0', + project: null, // workspace changelog + isVersionPlans: false, + changelogRenderOptions: { + authors: true, + }, + conventionalCommitsConfig: DEFAULT_CONVENTIONAL_COMMITS_CONFIG, + }; + + expect( + await new DefaultChangelogRenderer({ + ...otherOpts, + entryWhenNoChanges: 'Nothing at all!', + }).render() + ).toMatchInlineSnapshot(` + "## v1.1.0 + + Nothing at all!" + `); + + expect( + await new DefaultChangelogRenderer({ + ...otherOpts, + entryWhenNoChanges: false, // should not create an entry + }).render() + ).toMatchInlineSnapshot(`""`); + }); - - Author 1 - - Author 2 - - Author 4" - `); + it('should respect the entryWhenNoChanges option for project changelogs', async () => { + const otherOpts = { + changes: [], + changelogEntryVersion: 'v1.1.0', + project: 'pkg-a', + isVersionPlans: false, + changelogRenderOptions: { + authors: true, + }, + conventionalCommitsConfig: DEFAULT_CONVENTIONAL_COMMITS_CONFIG, + }; + + expect( + await new DefaultChangelogRenderer({ + ...otherOpts, + entryWhenNoChanges: 'Nothing at all!', + }).render() + ).toMatchInlineSnapshot(` + "## v1.1.0 + + Nothing at all!" + `); + + expect( + await new DefaultChangelogRenderer({ + ...otherOpts, + entryWhenNoChanges: false, // should not create an entry + }).render() + ).toMatchInlineSnapshot(`""`); + }); }); - }); - describe('entryWhenNoChanges', () => { - it('should respect the entryWhenNoChanges option for the workspace changelog', async () => { - const otherOpts = { - projectGraph, - changes: [], - releaseVersion: 'v1.1.0', - project: null, // workspace changelog - changelogRenderOptions: { - authors: true, - }, - conventionalCommitsConfig: DEFAULT_CONVENTIONAL_COMMITS_CONFIG, - }; + describe('revert commits', () => { + it('should generate a Revert section for the changelog if the reverted commit is not part of the same release', async () => { + const changesWithOnlyRevert: ChangelogChange[] = [ + { + shortHash: '6528e88aa', + authors: [ + { + name: 'James Henry', + email: 'jh@example.com', + }, + ], + body: 'This reverts commit 6d68236d467812aba4557a2bc7f667157de80fdb.\n"\n\nM\tpackages/js/src/generators/release-version/release-version.spec.ts\nM\tpackages/js/src/generators/release-version/release-version.ts\n', + description: + 'Revert "fix(release): do not update dependents when they already use "*" (#20607)"', + type: 'revert', + scope: 'release', + githubReferences: [ + { + type: 'pull-request', + value: '#20607', + }, + { + value: '6528e88aa', + type: 'hash', + }, + ], + isBreaking: false, + revertedHashes: ['6d68236d467812aba4557a2bc7f667157de80fdb'], + affectedProjects: ['js'], + }, + ]; + + const markdown = await new DefaultChangelogRenderer({ + changes: changesWithOnlyRevert, + changelogEntryVersion: 'v1.1.0', + project: null, + isVersionPlans: false, + entryWhenNoChanges: false, + changelogRenderOptions: { + authors: true, + }, + conventionalCommitsConfig: DEFAULT_CONVENTIONAL_COMMITS_CONFIG, + }).render(); - expect( - await defaultChangelogRenderer({ - ...otherOpts, - entryWhenNoChanges: 'Nothing at all!', - }) - ).toMatchInlineSnapshot(` - "## v1.1.0 + expect(markdown).toMatchInlineSnapshot(` + "## v1.1.0 - Nothing at all!" - `); + ### ⏪ Revert - expect( - await defaultChangelogRenderer({ - ...otherOpts, - entryWhenNoChanges: false, // should not create an entry - }) - ).toMatchInlineSnapshot(`""`); - }); + - **release:** Revert "fix(release): do not update dependents when they already use "*" (#20607)" - it('should respect the entryWhenNoChanges option for project changelogs', async () => { - const otherOpts = { - projectGraph, - changes: [], - releaseVersion: 'v1.1.0', - project: 'pkg-a', - changelogRenderOptions: { - authors: true, - }, - conventionalCommitsConfig: DEFAULT_CONVENTIONAL_COMMITS_CONFIG, - }; + ### ❤️ Thank You - expect( - await defaultChangelogRenderer({ - ...otherOpts, - entryWhenNoChanges: 'Nothing at all!', - }) - ).toMatchInlineSnapshot(` - "## v1.1.0 + - James Henry" + `); + }); - Nothing at all!" - `); + it('should strip both the original commit and its revert if they are both included in the current range of commits', async () => { + const changesWithRevertAndOriginal: ChangelogChange[] = [ + { + shortHash: '6528e88aa', + authors: [ + { + name: 'James Henry', + email: 'jh@example.com', + }, + ], + body: 'This reverts commit 6d68236d467812aba4557a2bc7f667157de80fdb.\n"\n\nM\tpackages/js/src/generators/release-version/release-version.spec.ts\nM\tpackages/js/src/generators/release-version/release-version.ts\n', + description: + 'Revert "fix(release): do not update dependents when they already use "*" (#20607)"', + type: 'revert', + scope: 'release', + githubReferences: [ + { + type: 'pull-request', + value: '#20607', + }, + { + value: '6528e88aa', + type: 'hash', + }, + ], + isBreaking: false, + revertedHashes: ['6d68236d467812aba4557a2bc7f667157de80fdb'], + affectedProjects: ['js'], + }, + { + shortHash: '6d68236d4', + authors: [ + { + name: 'James Henry', + email: 'jh@example.com', + }, + ], + body: '"\n\nM\tpackages/js/src/generators/release-version/release-version.spec.ts\nM\tpackages/js/src/generators/release-version/release-version.ts\n', + description: 'do not update dependents when they already use "*"', + type: 'fix', + scope: 'release', + githubReferences: [ + { + type: 'pull-request', + value: '#20607', + }, + { + value: '6d68236d4', + type: 'hash', + }, + ], + isBreaking: false, + revertedHashes: [], + affectedProjects: ['js'], + }, + ]; + + const markdown = await new DefaultChangelogRenderer({ + changes: changesWithRevertAndOriginal, + changelogEntryVersion: 'v1.1.0', + project: null, + isVersionPlans: false, + entryWhenNoChanges: false, + changelogRenderOptions: { + authors: true, + }, + conventionalCommitsConfig: DEFAULT_CONVENTIONAL_COMMITS_CONFIG, + }).render(); - expect( - await defaultChangelogRenderer({ - ...otherOpts, - entryWhenNoChanges: false, // should not create an entry - }) - ).toMatchInlineSnapshot(`""`); + expect(markdown).toMatchInlineSnapshot(`""`); + }); }); - }); - describe('revert commits', () => { - it('should generate a Revert section for the changelog if the reverted commit is not part of the same release', async () => { - const changesWithOnlyRevert: ChangelogChange[] = [ - { - shortHash: '6528e88aa', - author: { - name: 'James Henry', - email: 'jh@example.com', - }, - body: 'This reverts commit 6d68236d467812aba4557a2bc7f667157de80fdb.\n"\n\nM\tpackages/js/src/generators/release-version/release-version.spec.ts\nM\tpackages/js/src/generators/release-version/release-version.ts\n', - description: - 'Revert "fix(release): do not update dependents when they already use "*" (#20607)"', - type: 'revert', - scope: 'release', - githubReferences: [ - { - type: 'pull-request', - value: '#20607', - }, + describe('breaking changes', () => { + it('should work for breaking changes with just the ! and no explanation', async () => { + const breakingChangeWithExplanation: ChangelogChange = { + shortHash: '54f2f6ed1', + authors: [ { - value: '6528e88aa', - type: 'hash', + name: 'James Henry', + email: 'jh@example.com', }, ], - isBreaking: false, - revertedHashes: ['6d68236d467812aba4557a2bc7f667157de80fdb'], - affectedProjects: ['js'], - }, - ]; + body: + 'M\tpackages/rxjs/src/internal/observable/dom/WebSocketSubject.ts\n' + + '"', + description: 'no longer extends `Subject`.', + type: 'feat', + scope: 'WebSocketSubject', + githubReferences: [{ value: '54f2f6ed1', type: 'hash' }], + isBreaking: true, + revertedHashes: [], + affectedProjects: ['rxjs'], + }; + + const markdown = await new DefaultChangelogRenderer({ + changes: [breakingChangeWithExplanation], + changelogEntryVersion: 'v1.1.0', + project: null, + isVersionPlans: false, + entryWhenNoChanges: false, + changelogRenderOptions: { + authors: true, + }, + conventionalCommitsConfig: DEFAULT_CONVENTIONAL_COMMITS_CONFIG, + }).render(); - const markdown = await defaultChangelogRenderer({ - projectGraph, - changes: changesWithOnlyRevert, - releaseVersion: 'v1.1.0', - project: null, - entryWhenNoChanges: false, - changelogRenderOptions: { - authors: true, - }, - conventionalCommitsConfig: DEFAULT_CONVENTIONAL_COMMITS_CONFIG, - }); + expect(markdown).toMatchInlineSnapshot(` + "## v1.1.0 - expect(markdown).toMatchInlineSnapshot(` - "## v1.1.0 + ### 🚀 Features + - ⚠️ **WebSocketSubject:** no longer extends \`Subject\`. - ### ⏪ Revert + ### ⚠️ Breaking Changes - - **release:** Revert "fix(release): do not update dependents when they already use "*" (#20607)" + - ⚠️ **WebSocketSubject:** no longer extends \`Subject\`. - ### ❤️ Thank You + ### ❤️ Thank You - - James Henry" - `); - }); + - James Henry" + `); + }); - it('should strip both the original commit and its revert if they are both included in the current range of commits', async () => { - const changesWithRevertAndOriginal: ChangelogChange[] = [ - { - shortHash: '6528e88aa', - author: { - name: 'James Henry', - email: 'jh@example.com', - }, - body: 'This reverts commit 6d68236d467812aba4557a2bc7f667157de80fdb.\n"\n\nM\tpackages/js/src/generators/release-version/release-version.spec.ts\nM\tpackages/js/src/generators/release-version/release-version.ts\n', - description: - 'Revert "fix(release): do not update dependents when they already use "*" (#20607)"', - type: 'revert', - scope: 'release', - githubReferences: [ - { - type: 'pull-request', - value: '#20607', - }, - { - value: '6528e88aa', - type: 'hash', - }, - ], - isBreaking: false, - revertedHashes: ['6d68236d467812aba4557a2bc7f667157de80fdb'], - affectedProjects: ['js'], - }, - { - shortHash: '6d68236d4', - author: { - name: 'James Henry', - email: 'jh@example.com', - }, - body: '"\n\nM\tpackages/js/src/generators/release-version/release-version.spec.ts\nM\tpackages/js/src/generators/release-version/release-version.ts\n', - description: 'do not update dependents when they already use "*"', - type: 'fix', - scope: 'release', - githubReferences: [ + it('should extract the explanation of a breaking change and render it preferentially', async () => { + const breakingChangeWithExplanation: ChangelogChange = { + shortHash: '54f2f6ed1', + authors: [ { - type: 'pull-request', - value: '#20607', - }, - { - value: '6d68236d4', - type: 'hash', + name: 'James Henry', + email: 'jh@example.com', }, ], - isBreaking: false, + body: + 'BREAKING CHANGE: `WebSocketSubject` is no longer `instanceof Subject`. Check for `instanceof WebSocketSubject` instead.\n' + + '"\n' + + '\n' + + 'M\tpackages/rxjs/src/internal/observable/dom/WebSocketSubject.ts\n' + + '"', + description: 'no longer extends `Subject`.', + type: 'feat', + scope: 'WebSocketSubject', + githubReferences: [{ value: '54f2f6ed1', type: 'hash' }], + isBreaking: true, revertedHashes: [], - affectedProjects: ['js'], - }, - ]; + affectedProjects: ['rxjs'], + }; + + const markdown = await new DefaultChangelogRenderer({ + changes: [breakingChangeWithExplanation], + changelogEntryVersion: 'v1.1.0', + project: null, + isVersionPlans: false, + entryWhenNoChanges: false, + changelogRenderOptions: { + authors: true, + }, + conventionalCommitsConfig: DEFAULT_CONVENTIONAL_COMMITS_CONFIG, + }).render(); - const markdown = await defaultChangelogRenderer({ - projectGraph, - changes: changesWithRevertAndOriginal, - releaseVersion: 'v1.1.0', - project: null, - entryWhenNoChanges: false, - changelogRenderOptions: { - authors: true, - }, - conventionalCommitsConfig: DEFAULT_CONVENTIONAL_COMMITS_CONFIG, - }); + expect(markdown).toMatchInlineSnapshot(` + "## v1.1.0 - expect(markdown).toMatchInlineSnapshot(`""`); - }); - }); + ### 🚀 Features - describe('breaking changes', () => { - it('should work for breaking changes with just the ! and no explanation', async () => { - const breakingChangeWithExplanation: ChangelogChange = { - shortHash: '54f2f6ed1', - author: { - name: 'James Henry', - email: 'jh@example.com', - }, - body: - 'M\tpackages/rxjs/src/internal/observable/dom/WebSocketSubject.ts\n' + - '"', - description: 'no longer extends `Subject`.', - type: 'feat', - scope: 'WebSocketSubject', - githubReferences: [{ value: '54f2f6ed1', type: 'hash' }], - isBreaking: true, - revertedHashes: [], - affectedProjects: ['rxjs'], - }; - - const markdown = await defaultChangelogRenderer({ - projectGraph, - changes: [breakingChangeWithExplanation], - releaseVersion: 'v1.1.0', - project: null, - entryWhenNoChanges: false, - changelogRenderOptions: { - authors: true, - }, - conventionalCommitsConfig: DEFAULT_CONVENTIONAL_COMMITS_CONFIG, + - ⚠️ **WebSocketSubject:** no longer extends \`Subject\`. + + ### ⚠️ Breaking Changes + + - **WebSocketSubject:** \`WebSocketSubject\` is no longer \`instanceof Subject\`. Check for \`instanceof WebSocketSubject\` instead. + + ### ❤️ Thank You + + - James Henry" + `); }); + }); - expect(markdown).toMatchInlineSnapshot(` - "## v1.1.0 + describe('dependency bumps', () => { + it('should render the dependency bumps in addition to the changes', async () => { + expect( + await new DefaultChangelogRenderer({ + changes, + changelogEntryVersion: 'v1.1.0', + entryWhenNoChanges: false as const, + changelogRenderOptions: { + authors: true, + }, + isVersionPlans: false, + conventionalCommitsConfig: DEFAULT_CONVENTIONAL_COMMITS_CONFIG, + project: 'pkg-a', + dependencyBumps: [ + { + dependencyName: 'pkg-b', + newVersion: '2.0.0', + }, + ], + }).render() + ).toMatchInlineSnapshot(` + "## v1.1.0 + ### 🚀 Features - ### 🚀 Features + - **pkg-a:** new hotness - - ⚠️ **WebSocketSubject:** no longer extends \`Subject\`. + ### 🩹 Fixes - ### ⚠️ Breaking Changes + - all packages fixed + - **pkg-a:** squashing bugs - - ⚠️ **WebSocketSubject:** no longer extends \`Subject\`. + ### 🧱 Updated Dependencies - ### ❤️ Thank You + - Updated pkg-b to 2.0.0 - - James Henry" - `); + ### ❤️ Thank You + + - James Henry" + `); + }); + + it('should render the dependency bumps and release version title even when there are no changes', async () => { + expect( + await new DefaultChangelogRenderer({ + changes: [], + changelogEntryVersion: 'v3.1.0', + entryWhenNoChanges: + 'should not be printed because we have dependency bumps', + changelogRenderOptions: { + authors: true, + }, + isVersionPlans: false, + conventionalCommitsConfig: DEFAULT_CONVENTIONAL_COMMITS_CONFIG, + project: 'pkg-a', + dependencyBumps: [ + { + dependencyName: 'pkg-b', + newVersion: '4.0.0', + }, + ], + }).render() + ).toMatchInlineSnapshot(` + "## v3.1.0 + + ### 🧱 Updated Dependencies + + - Updated pkg-b to 4.0.0" + `); + }); }); + }); - it('should extract the explanation of a breaking change and render it preferentially', async () => { - const breakingChangeWithExplanation: ChangelogChange = { - shortHash: '54f2f6ed1', - author: { - name: 'James Henry', - email: 'jh@example.com', - }, - body: - 'BREAKING CHANGE: `WebSocketSubject` is no longer `instanceof Subject`. Check for `instanceof WebSocketSubject` instead.\n' + - '"\n' + - '\n' + - 'M\tpackages/rxjs/src/internal/observable/dom/WebSocketSubject.ts\n' + - '"', - description: 'no longer extends `Subject`.', - type: 'feat', - scope: 'WebSocketSubject', - githubReferences: [{ value: '54f2f6ed1', type: 'hash' }], - isBreaking: true, - revertedHashes: [], - affectedProjects: ['rxjs'], - }; - - const markdown = await defaultChangelogRenderer({ - projectGraph, - changes: [breakingChangeWithExplanation], - releaseVersion: 'v1.1.0', + describe('Custom ChangelogRenderer', () => { + it('should be possible to override individual methods of the DefaultChangelogRenderer', async () => { + class CustomChangelogRenderer extends DefaultChangelogRenderer { + public renderVersionTitle(): string { + return 'Custom Version Title'; + } + } + + const renderer = new CustomChangelogRenderer({ + changes, + changelogEntryVersion: 'v1.1.0', project: null, + isVersionPlans: false, entryWhenNoChanges: false, changelogRenderOptions: { authors: true, @@ -734,100 +852,25 @@ describe('defaultChangelogRenderer()', () => { conventionalCommitsConfig: DEFAULT_CONVENTIONAL_COMMITS_CONFIG, }); + const markdown = await renderer.render(); expect(markdown).toMatchInlineSnapshot(` - "## v1.1.0 - - - ### 🚀 Features - - - ⚠️ **WebSocketSubject:** no longer extends \`Subject\`. - - ### ⚠️ Breaking Changes - - - **WebSocketSubject:** \`WebSocketSubject\` is no longer \`instanceof Subject\`. Check for \`instanceof WebSocketSubject\` instead. - - ### ❤️ Thank You - - - James Henry" - `); - }); - }); - - describe('dependency bumps', () => { - it('should render the dependency bumps in addition to the changes', async () => { - expect( - await defaultChangelogRenderer({ - projectGraph, - changes, - releaseVersion: 'v1.1.0', - entryWhenNoChanges: false as const, - changelogRenderOptions: { - authors: true, - }, - conventionalCommitsConfig: DEFAULT_CONVENTIONAL_COMMITS_CONFIG, - project: 'pkg-a', - dependencyBumps: [ - { - dependencyName: 'pkg-b', - newVersion: '2.0.0', - }, - ], - }) - ).toMatchInlineSnapshot(` - "## v1.1.0 - + "Custom Version Title ### 🚀 Features - **pkg-a:** new hotness - + - **pkg-b:** brand new thing + - **pkg-b:** and another new capability ### 🩹 Fixes - all packages fixed - - **pkg-a:** squashing bugs - - ### 🧱 Updated Dependencies - - - Updated pkg-b to 2.0.0 - - ### ❤️ Thank You - James Henry" `); }); - - it('should render the dependency bumps and release version title even when there are no changes', async () => { - expect( - await defaultChangelogRenderer({ - projectGraph, - changes: [], - releaseVersion: 'v3.1.0', - entryWhenNoChanges: - 'should not be printed because we have dependency bumps', - changelogRenderOptions: { - authors: true, - }, - conventionalCommitsConfig: DEFAULT_CONVENTIONAL_COMMITS_CONFIG, - project: 'pkg-a', - dependencyBumps: [ - { - dependencyName: 'pkg-b', - newVersion: '4.0.0', - }, - ], - }) - ).toMatchInlineSnapshot(` - "## v3.1.0 - - - ### 🧱 Updated Dependencies - - - Updated pkg-b to 4.0.0" - `); - }); }); }); diff --git a/packages/nx/release/changelog-renderer/index.ts b/packages/nx/release/changelog-renderer/index.ts index b1eaf6667a91df..e4d9b91714dafc 100644 --- a/packages/nx/release/changelog-renderer/index.ts +++ b/packages/nx/release/changelog-renderer/index.ts @@ -2,13 +2,10 @@ import { major } from 'semver'; import { ChangelogChange } from '../../src/command-line/release/changelog'; import { NxReleaseConfig } from '../../src/command-line/release/config/config'; import { DEFAULT_CONVENTIONAL_COMMITS_CONFIG } from '../../src/command-line/release/config/conventional-commits'; -import { GitCommit } from '../../src/command-line/release/utils/git'; import { GithubRepoData, - RepoSlug, formatReferences, } from '../../src/command-line/release/utils/github'; -import type { ProjectGraph } from '../../src/config/project-graph'; // axios types and values don't seem to match import _axios = require('axios'); @@ -21,7 +18,7 @@ const axios = _axios as any as (typeof _axios)['default']; export type ChangelogRenderOptions = Record; /** - * When versioning projects independently and enabling `"updateDependents": "always"`, there could + * When versioning projects independently and enabling `"updateDependents": "auto"`, there could * be additional dependency bump information that is not captured in the commit data, but that nevertheless * should be included in the rendered changelog. */ @@ -30,39 +27,6 @@ export type DependencyBump = { newVersion: string; }; -/** - * A ChangelogRenderer function takes in the extracted commits and other relevant metadata - * and returns a string, or a Promise of a string of changelog contents (usually markdown). - * - * @param {Object} config The configuration object for the ChangelogRenderer - * @param {ProjectGraph} config.projectGraph The project graph for the workspace - * @param {GitCommit[]} config.commits DEPRECATED [Use 'config.changes' instead] - The collection of extracted commits to generate a changelog for - * @param {ChangelogChange[]} config.changes The collection of changes to show in the changelog - * @param {string} config.releaseVersion The version that is being released - * @param {string | null} config.project The name of specific project to generate a changelog for, or `null` if the overall workspace changelog - * @param {string | false} config.entryWhenNoChanges The (already interpolated) string to use as the changelog entry when there are no changes, or `false` if no entry should be generated - * @param {ChangelogRenderOptions} config.changelogRenderOptions The options specific to the ChangelogRenderer implementation - * @param {DependencyBump[]} config.dependencyBumps Optional list of additional dependency bumps that occurred as part of the release, outside of the commit data - * @param {GithubRepoData} config.repoData Resolved data for the current GitHub repository - */ -export type ChangelogRenderer = (config: { - projectGraph: ProjectGraph; - // TODO(v20): remove 'commits' and make 'changes' required - commits?: GitCommit[]; - changes?: ChangelogChange[]; - releaseVersion: string; - project: string | null; - entryWhenNoChanges: string | false; - changelogRenderOptions: DefaultChangelogRenderOptions; - dependencyBumps?: DependencyBump[]; - // TODO(v20): remove repoSlug in favour of repoData - repoSlug?: RepoSlug; - repoData?: GithubRepoData; - // TODO(v20): Evaluate if there is a cleaner way to configure this when breaking changes are allowed - // null if version plans are being used to generate the changelog - conventionalCommitsConfig: NxReleaseConfig['conventionalCommits'] | null; -}) => Promise | string; - /** * The specific options available to the default implementation of the ChangelogRenderer that nx exports * for the common case. @@ -91,201 +55,210 @@ export interface DefaultChangelogRenderOptions extends ChangelogRenderOptions { versionTitleDate?: boolean; } -/** - * The default ChangelogRenderer implementation that nx exports for the common case of generating markdown - * from the given commits and other metadata. - */ -const defaultChangelogRenderer: ChangelogRenderer = async ({ - projectGraph, - changes, - releaseVersion, - project, - entryWhenNoChanges, - changelogRenderOptions, - dependencyBumps, - repoSlug, - conventionalCommitsConfig, - repoData, -}): Promise => { - const markdownLines: string[] = []; - - // If the current range of changes contains both a commit and its revert, we strip them both from the final list. Changes from version plans are unaffected, as they have no hashes. - for (const change of changes) { - if (change.type === 'revert' && change.revertedHashes) { - for (const revertedHash of change.revertedHashes) { - const revertedCommit = changes.find( - (c) => c.shortHash && revertedHash.startsWith(c.shortHash) - ); - if (revertedCommit) { - changes.splice(changes.indexOf(revertedCommit), 1); - changes.splice(changes.indexOf(change), 1); - } - } - } +export default class DefaultChangelogRenderer { + protected changes: ChangelogChange[]; + protected changelogEntryVersion: string; + protected project: string | null; + protected entryWhenNoChanges: string | false; + protected changelogRenderOptions: DefaultChangelogRenderOptions; + protected isVersionPlans: boolean; + protected dependencyBumps?: DependencyBump[]; + protected repoData?: GithubRepoData; + protected conventionalCommitsConfig: + | NxReleaseConfig['conventionalCommits'] + | null; + protected relevantChanges: ChangelogChange[]; + protected breakingChanges: string[]; + protected additionalChangesForAuthorsSection: ChangelogChange[]; + + /** + * A ChangelogRenderer class takes in the determined changes and other relevant metadata + * and returns a string, or a Promise of a string of changelog contents (usually markdown). + * + * @param {Object} config The configuration object for the ChangelogRenderer + * @param {ChangelogChange[]} config.changes The collection of changes to show in the changelog + * @param {string} config.changelogEntryVersion The version for which we are rendering the current changelog entry + * @param {string | null} config.project The name of specific project to generate a changelog entry for, or `null` if the overall workspace changelog + * @param {string | false} config.entryWhenNoChanges The (already interpolated) string to use as the changelog entry when there are no changes, or `false` if no entry should be generated + * @param {boolean} config.isVersionPlans Whether or not Nx release version plans are the source of truth for the changelog entry + * @param {ChangelogRenderOptions} config.changelogRenderOptions The options specific to the ChangelogRenderer implementation + * @param {DependencyBump[]} config.dependencyBumps Optional list of additional dependency bumps that occurred as part of the release, outside of the change data + * @param {GithubRepoData} config.repoData Resolved data for the current GitHub repository + * @param {NxReleaseConfig['conventionalCommits'] | null} config.conventionalCommitsConfig The configuration for conventional commits, or null if version plans are being used + */ + constructor(config: { + changes: ChangelogChange[]; + changelogEntryVersion: string; + project: string | null; + entryWhenNoChanges: string | false; + isVersionPlans: boolean; + changelogRenderOptions: DefaultChangelogRenderOptions; + dependencyBumps?: DependencyBump[]; + repoData?: GithubRepoData; + conventionalCommitsConfig: NxReleaseConfig['conventionalCommits'] | null; + }) { + this.changes = this.filterChanges(config.changes, config.project); + this.changelogEntryVersion = config.changelogEntryVersion; + this.project = config.project; + this.entryWhenNoChanges = config.entryWhenNoChanges; + this.isVersionPlans = config.isVersionPlans; + this.changelogRenderOptions = config.changelogRenderOptions; + this.dependencyBumps = config.dependencyBumps; + this.repoData = config.repoData; + this.conventionalCommitsConfig = config.conventionalCommitsConfig; + + this.relevantChanges = []; + this.breakingChanges = []; + this.additionalChangesForAuthorsSection = []; } - let relevantChanges = changes; - const breakingChanges = []; - - // For now to keep the interface of the changelog renderer non-breaking for v19 releases we have a somewhat indirect check for whether or not we are generating a changelog for version plans - const isVersionPlans = !conventionalCommitsConfig; - - // Only applicable for version plans - const additionalChangesForAuthorsSection = []; - - // Provide a default configuration for version plans to allow most of the subsequent logic to work in the same way it would for conventional commits - // NOTE: The one exception is breaking/major changes, where we do not follow the same structure and instead only show the changes once - if (isVersionPlans) { - conventionalCommitsConfig = { - types: { - feat: DEFAULT_CONVENTIONAL_COMMITS_CONFIG.types.feat, - fix: DEFAULT_CONVENTIONAL_COMMITS_CONFIG.types.fix, - }, - }; - // Trim down "relevant changes" to only include non-breaking ones so that we can render them differently under version plans, - // but keep track of the changes for the purposes of the authors section - // TODO(v20): Clean this abstraction up as part of the larger overall refactor of changelog rendering - for (let i = 0; i < relevantChanges.length; i++) { - if (relevantChanges[i].isBreaking) { - const change = relevantChanges[i]; - additionalChangesForAuthorsSection.push(change); - const line = formatChange( - change, - changelogRenderOptions, - isVersionPlans, - repoData - ); - breakingChanges.push(line); - relevantChanges.splice(i, 1); - } + protected filterChanges( + changes: ChangelogChange[], + project: string | null + ): ChangelogChange[] { + if (project === null) { + return changes; } + return changes.filter( + (c) => + c.affectedProjects && + (c.affectedProjects === '*' || c.affectedProjects.includes(project)) + ); } - const changeTypes = conventionalCommitsConfig.types; - - // workspace root level changelog - if (project === null) { - // No changes for the workspace - if (relevantChanges.length === 0 && breakingChanges.length === 0) { - if (dependencyBumps?.length) { - applyAdditionalDependencyBumps({ - markdownLines, - dependencyBumps, - releaseVersion, - changelogRenderOptions, - }); - } else if (entryWhenNoChanges) { - markdownLines.push( - '', - `${createVersionTitle( - releaseVersion, - changelogRenderOptions - )}\n\n${entryWhenNoChanges}`, - '' - ); - } - return markdownLines.join('\n').trim(); + async render(): Promise { + const sections: string[][] = []; + + this.preprocessChanges(); + + if (this.shouldRenderEmptyEntry()) { + return this.renderEmptyEntry(); } - const typeGroups: Record = groupBy( - relevantChanges, - 'type' - ); + sections.push([this.renderVersionTitle()]); - markdownLines.push( - '', - createVersionTitle(releaseVersion, changelogRenderOptions), - '' - ); + const changesByType = this.renderChangesByType(); + if (changesByType.length > 0) { + sections.push(changesByType); + } - for (const type of Object.keys(changeTypes)) { - const group = typeGroups[type]; - if (!group || group.length === 0) { - continue; - } + if (this.hasBreakingChanges()) { + sections.push(this.renderBreakingChanges()); + } - markdownLines.push('', '### ' + changeTypes[type].changelog.title, ''); - - /** - * In order to make the final changelog most readable, we organize changes as follows: - * - By scope, where scopes are in alphabetical order (changes with no scope are listed first) - * - Within a particular scope grouping, we list changes in chronological order - */ - const changesInChronologicalOrder = group.reverse(); - const changesGroupedByScope: Record = groupBy( - changesInChronologicalOrder, - 'scope' - ); - const scopesSortedAlphabetically = Object.keys( - changesGroupedByScope - ).sort(); - - for (const scope of scopesSortedAlphabetically) { - const changes = changesGroupedByScope[scope]; - for (const change of changes) { - const line = formatChange( - change, - changelogRenderOptions, - isVersionPlans, - repoData + if (this.hasDependencyBumps()) { + sections.push(this.renderDependencyBumps()); + } + + if (this.shouldRenderAuthors()) { + sections.push(await this.renderAuthors()); + } + + // Join sections with double newlines, and trim any extra whitespace + return sections + .filter((section) => section.length > 0) + .map((section) => section.join('\n').trim()) + .join('\n\n') + .trim(); + } + + protected preprocessChanges(): void { + this.relevantChanges = [...this.changes]; + this.breakingChanges = []; + this.additionalChangesForAuthorsSection = []; + + // Filter out reverted changes + for (let i = this.relevantChanges.length - 1; i >= 0; i--) { + const change = this.relevantChanges[i]; + if (change.type === 'revert' && change.revertedHashes) { + for (const revertedHash of change.revertedHashes) { + const revertedCommitIndex = this.relevantChanges.findIndex( + (c) => c.shortHash && revertedHash.startsWith(c.shortHash) ); - markdownLines.push(line); - if (change.isBreaking) { - const breakingChangeExplanation = extractBreakingChangeExplanation( - change.body - ); - breakingChanges.push( - breakingChangeExplanation - ? `- ${ - change.scope ? `**${change.scope.trim()}:** ` : '' - }${breakingChangeExplanation}` - : line - ); + if (revertedCommitIndex !== -1) { + this.relevantChanges.splice(revertedCommitIndex, 1); + this.relevantChanges.splice(i, 1); + i--; + break; } } } } - } else { - // project level changelog - relevantChanges = relevantChanges.filter( - (c) => - c.affectedProjects && - (c.affectedProjects === '*' || c.affectedProjects.includes(project)) - ); - // Generating for a named project, but that project has no relevant changes in the current set of commits, exit early - if (relevantChanges.length === 0 && breakingChanges.length === 0) { - if (dependencyBumps?.length) { - applyAdditionalDependencyBumps({ - markdownLines, - dependencyBumps, - releaseVersion, - changelogRenderOptions, - }); - } else if (entryWhenNoChanges) { - markdownLines.push( - '', - `${createVersionTitle( - releaseVersion, - changelogRenderOptions - )}\n\n${entryWhenNoChanges}`, - '' - ); + if (this.isVersionPlans) { + this.conventionalCommitsConfig = { + types: { + feat: DEFAULT_CONVENTIONAL_COMMITS_CONFIG.types.feat, + fix: DEFAULT_CONVENTIONAL_COMMITS_CONFIG.types.fix, + }, + }; + + for (let i = this.relevantChanges.length - 1; i >= 0; i--) { + if (this.relevantChanges[i].isBreaking) { + const change = this.relevantChanges[i]; + this.additionalChangesForAuthorsSection.push(change); + const line = this.formatChange(change); + this.breakingChanges.push(line); + this.relevantChanges.splice(i, 1); + } + } + } else { + for (const change of this.relevantChanges) { + if (change.isBreaking) { + const breakingChangeExplanation = + this.extractBreakingChangeExplanation(change.body); + this.breakingChanges.push( + breakingChangeExplanation + ? `- ${ + change.scope ? `**${change.scope.trim()}:** ` : '' + }${breakingChangeExplanation}` + : this.formatChange(change) + ); + } } - return markdownLines.join('\n').trim(); } + } - markdownLines.push( - '', - createVersionTitle(releaseVersion, changelogRenderOptions), - '' + protected shouldRenderEmptyEntry(): boolean { + return ( + this.relevantChanges.length === 0 && + this.breakingChanges.length === 0 && + !this.hasDependencyBumps() ); + } + + protected renderEmptyEntry(): string { + if (this.hasDependencyBumps()) { + return [ + this.renderVersionTitle(), + '', + ...this.renderDependencyBumps(), + ].join('\n'); + } else if (this.entryWhenNoChanges) { + return `${this.renderVersionTitle()}\n\n${this.entryWhenNoChanges}`; + } + return ''; + } + + protected renderVersionTitle(): string { + const isMajorVersion = + `${major(this.changelogEntryVersion)}.0.0` === + this.changelogEntryVersion.replace(/^v/, ''); + let maybeDateStr = ''; + if (this.changelogRenderOptions.versionTitleDate) { + const dateStr = new Date().toISOString().slice(0, 10); + maybeDateStr = ` (${dateStr})`; + } + return isMajorVersion + ? `# ${this.changelogEntryVersion}${maybeDateStr}` + : `## ${this.changelogEntryVersion}${maybeDateStr}`; + } + + protected renderChangesByType(): string[] { + const markdownLines: string[] = []; + const typeGroups = this.groupChangesByType(); + const changeTypes = this.conventionalCommitsConfig.types; - const typeGroups: Record = groupBy( - // Sort the relevant changes to have the unscoped changes first, before grouping by type - relevantChanges.sort((a, b) => (b.scope ? 1 : 0) - (a.scope ? 1 : 0)), - 'type' - ); for (const type of Object.keys(changeTypes)) { const group = typeGroups[type]; if (!group || group.length === 0) { @@ -294,74 +267,111 @@ const defaultChangelogRenderer: ChangelogRenderer = async ({ markdownLines.push('', `### ${changeTypes[type].changelog.title}`, ''); - const changesInChronologicalOrder = group.reverse(); - for (const change of changesInChronologicalOrder) { - const line = formatChange( - change, - changelogRenderOptions, - isVersionPlans, - repoData - ); - markdownLines.push(line + '\n'); - if (change.isBreaking) { - const breakingChangeExplanation = extractBreakingChangeExplanation( - change.body - ); - breakingChanges.push( - breakingChangeExplanation - ? `- ${ - change.scope ? `**${change.scope.trim()}:** ` : '' - }${breakingChangeExplanation}` - : line - ); + if (this.project === null) { + const changesGroupedByScope = this.groupChangesByScope(group); + const scopesSortedAlphabetically = Object.keys( + changesGroupedByScope + ).sort(); + + for (const scope of scopesSortedAlphabetically) { + const changes = changesGroupedByScope[scope]; + for (const change of changes.reverse()) { + const line = this.formatChange(change); + markdownLines.push(line); + if (change.isBreaking && !this.isVersionPlans) { + const breakingChangeExplanation = + this.extractBreakingChangeExplanation(change.body); + this.breakingChanges.push( + breakingChangeExplanation + ? `- ${ + change.scope ? `**${change.scope.trim()}:** ` : '' + }${breakingChangeExplanation}` + : line + ); + } + } + } + } else { + // For project-specific changelogs, maintain the original order + for (const change of group) { + const line = this.formatChange(change); + markdownLines.push(line); + if (change.isBreaking && !this.isVersionPlans) { + const breakingChangeExplanation = + this.extractBreakingChangeExplanation(change.body); + this.breakingChanges.push( + breakingChangeExplanation + ? `- ${ + change.scope ? `**${change.scope.trim()}:** ` : '' + }${breakingChangeExplanation}` + : line + ); + } } } } + + return markdownLines; + } + + protected hasBreakingChanges(): boolean { + return this.breakingChanges.length > 0; + } + + protected renderBreakingChanges(): string[] { + const uniqueBreakingChanges = Array.from(new Set(this.breakingChanges)); + return ['### ⚠️ Breaking Changes', '', ...uniqueBreakingChanges]; } - if (breakingChanges.length > 0) { - markdownLines.push('', '### ⚠️ Breaking Changes', '', ...breakingChanges); + protected hasDependencyBumps(): boolean { + return this.dependencyBumps && this.dependencyBumps.length > 0; } - if (dependencyBumps?.length) { - applyAdditionalDependencyBumps({ - markdownLines, - dependencyBumps, - releaseVersion, - changelogRenderOptions, + protected renderDependencyBumps(): string[] { + const markdownLines = ['', '### 🧱 Updated Dependencies', '']; + this.dependencyBumps.forEach(({ dependencyName, newVersion }) => { + markdownLines.push(`- Updated ${dependencyName} to ${newVersion}`); }); + return markdownLines; + } + + protected shouldRenderAuthors(): boolean { + return this.changelogRenderOptions.authors; } - if (changelogRenderOptions.authors) { + protected async renderAuthors(): Promise { + const markdownLines: string[] = []; const _authors = new Map; github?: string }>(); for (const change of [ - ...relevantChanges, - ...additionalChangesForAuthorsSection, + ...this.relevantChanges, + ...this.additionalChangesForAuthorsSection, ]) { - if (!change.author) { + if (!change.authors) { continue; } - const name = formatName(change.author.name); - if (!name || name.includes('[bot]')) { - continue; - } - if (_authors.has(name)) { - const entry = _authors.get(name); - entry.email.add(change.author.email); - } else { - _authors.set(name, { email: new Set([change.author.email]) }); + for (const author of change.authors) { + const name = this.formatName(author.name); + if (!name || name.includes('[bot]')) { + continue; + } + if (_authors.has(name)) { + const entry = _authors.get(name); + entry.email.add(author.email); + } else { + _authors.set(name, { email: new Set([author.email]) }); + } } } - // Try to map authors to github usernames - if (repoData && changelogRenderOptions.mapAuthorsToGitHubUsernames) { + if ( + this.repoData && + this.changelogRenderOptions.mapAuthorsToGitHubUsernames + ) { await Promise.all( [..._authors.keys()].map(async (authorName) => { const meta = _authors.get(authorName); for (const email of meta.email) { - // For these pseudo-anonymized emails we can just extract the Github username from before the @ - // It could either be in the format: username@ or github_id+username@ if (email.endsWith('@users.noreply.github.com')) { const match = email.match( /^(\d+\+)?([^@]+)@users\.noreply\.github\.com$/ @@ -371,7 +381,6 @@ const defaultChangelogRenderer: ChangelogRenderer = async ({ break; } } - // Look up any other emails against the ungh.cc API const { data } = await axios .get( `https://ungh.cc/users/find/${email}` @@ -397,147 +406,93 @@ const defaultChangelogRenderer: ChangelogRenderer = async ({ '### ' + '❤️ Thank You', '', ...authors - // Sort the contributors by name .sort((a, b) => a.name.localeCompare(b.name)) .map((i) => { - // Tag the author's Github username if we were able to resolve it so that Github adds them as a contributor const github = i.github ? ` @${i.github}` : ''; return `- ${i.name}${github}`; }) ); } - } - - return markdownLines.join('\n').trim(); -}; -export default defaultChangelogRenderer; - -function applyAdditionalDependencyBumps({ - markdownLines, - dependencyBumps, - releaseVersion, - changelogRenderOptions, -}: { - markdownLines: string[]; - dependencyBumps: DependencyBump[]; - releaseVersion: string; - changelogRenderOptions: DefaultChangelogRenderOptions; -}) { - if (markdownLines.length === 0) { - markdownLines.push( - '', - `${createVersionTitle(releaseVersion, changelogRenderOptions)}\n`, - '' - ); - } else { - markdownLines.push(''); + return markdownLines; } - markdownLines.push('### 🧱 Updated Dependencies\n'); - dependencyBumps.forEach(({ dependencyName, newVersion }) => { - markdownLines.push(`- Updated ${dependencyName} to ${newVersion}`); - }); - markdownLines.push(''); -} - -function formatName(name = '') { - return name - .split(' ') - .map((p) => p.trim()) - .join(' '); -} -function groupBy(items: any[], key: string) { - const groups = {}; - for (const item of items) { - groups[item[key]] = groups[item[key]] || []; - groups[item[key]].push(item); - } - return groups; -} + protected formatChange(change: ChangelogChange): string { + let description = change.description; + let extraLines = []; + let extraLinesStr = ''; + if (description.includes('\n')) { + [description, ...extraLines] = description.split('\n'); + const indentation = ' '; + extraLinesStr = extraLines + .filter((l) => l.trim().length > 0) + .map((l) => `${indentation}${l}`) + .join('\n'); + } -function formatChange( - change: ChangelogChange, - changelogRenderOptions: DefaultChangelogRenderOptions, - isVersionPlans: boolean, - repoData?: GithubRepoData -): string { - let description = change.description; - let extraLines = []; - let extraLinesStr = ''; - if (description.includes('\n')) { - [description, ...extraLines] = description.split('\n'); - // Align the extra lines with the start of the description for better readability - const indentation = ' '; - extraLinesStr = extraLines - .filter((l) => l.trim().length > 0) - .map((l) => `${indentation}${l}`) - .join('\n'); + let changeLine = + '- ' + + (!this.isVersionPlans && change.isBreaking ? '⚠️ ' : '') + + (!this.isVersionPlans && change.scope + ? `**${change.scope.trim()}:** ` + : '') + + description; + if (this.repoData && this.changelogRenderOptions.commitReferences) { + changeLine += formatReferences(change.githubReferences, this.repoData); + } + if (extraLinesStr) { + changeLine += '\n\n' + extraLinesStr; + } + return changeLine; } - /** - * In version plans changelogs: - * - don't repeat the breaking change icon - * - don't render the scope - */ - let changeLine = - '- ' + - (!isVersionPlans && change.isBreaking ? '⚠️ ' : '') + - (!isVersionPlans && change.scope ? `**${change.scope.trim()}:** ` : '') + - description; - if (repoData && changelogRenderOptions.commitReferences) { - changeLine += formatReferences(change.githubReferences, repoData); - } - if (extraLinesStr) { - changeLine += '\n\n' + extraLinesStr; + protected groupChangesByType(): Record { + const typeGroups: Record = {}; + for (const change of this.relevantChanges) { + typeGroups[change.type] = typeGroups[change.type] || []; + typeGroups[change.type].push(change); + } + return typeGroups; } - return changeLine; -} -/** - * It is common to add further information about a breaking change in the commit body, - * and it is naturally that information that should be included in the BREAKING CHANGES - * section of changelog, rather than repeating the commit title/description. - */ -function extractBreakingChangeExplanation(message: string): string | null { - if (!message) { - return null; + protected groupChangesByScope( + changes: ChangelogChange[] + ): Record { + const scopeGroups: Record = {}; + for (const change of changes) { + const scope = change.scope || ''; + scopeGroups[scope] = scopeGroups[scope] || []; + scopeGroups[scope].push(change); + } + return scopeGroups; } - const breakingChangeIdentifier = 'BREAKING CHANGE:'; - const startIndex = message.indexOf(breakingChangeIdentifier); + protected extractBreakingChangeExplanation(message: string): string | null { + if (!message) { + return null; + } - if (startIndex === -1) { - // "BREAKING CHANGE:" not found in the message - return null; - } + const breakingChangeIdentifier = 'BREAKING CHANGE:'; + const startIndex = message.indexOf(breakingChangeIdentifier); - const startOfBreakingChange = startIndex + breakingChangeIdentifier.length; - const endOfBreakingChange = message.indexOf('\n', startOfBreakingChange); + if (startIndex === -1) { + return null; + } - if (endOfBreakingChange === -1) { - // No newline character found, extract till the end of the message - return message.substring(startOfBreakingChange).trim(); - } + const startOfBreakingChange = startIndex + breakingChangeIdentifier.length; + const endOfBreakingChange = message.indexOf('\n', startOfBreakingChange); - // Extract and return the breaking change message - return message.substring(startOfBreakingChange, endOfBreakingChange).trim(); -} + if (endOfBreakingChange === -1) { + return message.substring(startOfBreakingChange).trim(); + } -function createVersionTitle( - version: string, - changelogRenderOptions: DefaultChangelogRenderOptions -) { - // Normalize by removing any leading `v` during comparison - const isMajorVersion = `${major(version)}.0.0` === version.replace(/^v/, ''); - let maybeDateStr = ''; - if (changelogRenderOptions.versionTitleDate) { - // YYYY-MM-DD - const dateStr = new Date().toISOString().slice(0, 10); - maybeDateStr = ` (${dateStr})`; + return message.substring(startOfBreakingChange, endOfBreakingChange).trim(); } - if (isMajorVersion) { - return `# ${version}${maybeDateStr}`; + + protected formatName(name = ''): string { + return name + .split(' ') + .map((p) => p.trim()) + .join(' '); } - return `## ${version}${maybeDateStr}`; } diff --git a/packages/nx/src/command-line/add/add.ts b/packages/nx/src/command-line/add/add.ts index 3eac3e7d1855f9..5f2aad46cc1595 100644 --- a/packages/nx/src/command-line/add/add.ts +++ b/packages/nx/src/command-line/add/add.ts @@ -4,7 +4,7 @@ import * as ora from 'ora'; import { isAngularPluginInstalled } from '../../adapter/angular-json'; import type { GeneratorsJsonEntry } from '../../config/misc-interfaces'; import { readNxJson, type NxJsonConfiguration } from '../../config/nx-json'; -import { runNxAsync } from '../../utils/child-process'; +import { runNxAsync, runNxSync } from '../../utils/child-process'; import { writeJsonFile } from '../../utils/fileutils'; import { logger } from '../../utils/logger'; import { output } from '../../utils/output'; @@ -135,8 +135,8 @@ async function initializePlugin( args.push(...options.__overrides_unparsed__); } - await runNxAsync(`g ${pkgName}:${initGenerator} ${args.join(' ')}`, { - silent: !options.verbose, + runNxSync(`g ${pkgName}:${initGenerator} ${args.join(' ')}`, { + stdio: [0, 1, 2], }); } catch (e) { spinner.fail(); diff --git a/packages/nx/src/command-line/nx-commands.ts b/packages/nx/src/command-line/nx-commands.ts index 0feeb611864b18..454f67f9c921e5 100644 --- a/packages/nx/src/command-line/nx-commands.ts +++ b/packages/nx/src/command-line/nx-commands.ts @@ -45,6 +45,7 @@ import { yargsAffectedGraphCommand, } from './deprecated/command-objects'; import { yargsSyncCheckCommand, yargsSyncCommand } from './sync/command-object'; +import { output } from '../utils/output'; // Ensure that the output takes up the available width of the terminal. yargs.wrap(yargs.terminalWidth()); @@ -101,6 +102,7 @@ export const commandsObject = yargs .command(yargsLoginCommand) .command(yargsLogoutCommand) .command(resolveConformanceCommandObject()) + .command(resolveConformanceCheckCommandObject()) .scriptName('nx') .help() // NOTE: we handle --version in nx.ts, this just tells yargs that the option exists @@ -108,19 +110,43 @@ export const commandsObject = yargs // hit, as the implementation in nx.ts is hit first and calls process.exit(0). .version(); +function createMissingConformanceCommand( + command: 'conformance' | 'conformance:check' +) { + return { + command, + // Hide from --help output in the common case of not having the plugin installed + describe: false, + handler: () => { + output.error({ + title: `${command} is not available`, + bodyLines: [ + `In order to use the \`nx ${command}\` command you must have an active Powerpack license and the \`@nx/powerpack-conformance\` plugin installed.`, + '', + 'To learn more, visit https://nx.dev/features/powerpack/conformance', + ], + }); + process.exit(1); + }, + }; +} + function resolveConformanceCommandObject() { try { const { yargsConformanceCommand } = require('@nx/powerpack-conformance'); return yargsConformanceCommand; - } catch (e) { - return { - command: 'conformance', - // Hide from --help output in the common case of not having the plugin installed - describe: false, - handler: () => { - // TODO: Add messaging to help with learning more about powerpack and conformance - process.exit(1); - }, - }; + } catch { + return createMissingConformanceCommand('conformance'); + } +} + +function resolveConformanceCheckCommandObject() { + try { + const { + yargsConformanceCheckCommand, + } = require('@nx/powerpack-conformance'); + return yargsConformanceCheckCommand; + } catch { + return createMissingConformanceCommand('conformance:check'); } } diff --git a/packages/nx/src/command-line/release/changelog.ts b/packages/nx/src/command-line/release/changelog.ts index 6f23caf9b7c7cc..fd97f74adb1b3d 100644 --- a/packages/nx/src/command-line/release/changelog.ts +++ b/packages/nx/src/command-line/release/changelog.ts @@ -96,8 +96,7 @@ export interface ChangelogChange { body?: string; isBreaking?: boolean; githubReferences?: Reference[]; - // TODO(v20): This should be an array of one or more authors (Co-authored-by is supported at the commit level and should have been supported here) - author?: { name: string; email: string }; + authors?: { name: string; email: string }[]; shortHash?: string; revertedHashes?: string[]; } @@ -303,7 +302,8 @@ export function createAPI(overrideReleaseConfig: NxReleaseConfiguration) { body: '', isBreaking: releaseType.isBreaking, githubReferences, - author, + // TODO(JamesHenry): Implement support for Co-authored-by and adding multiple authors + authors: [author], affectedProjects: '*', } : vp.triggeredByProjects.map((project) => { @@ -314,7 +314,8 @@ export function createAPI(overrideReleaseConfig: NxReleaseConfiguration) { body: '', isBreaking: releaseType.isBreaking, githubReferences, - author, + // TODO(JamesHenry): Implement support for Co-authored-by and adding multiple authors + authors: [author], affectedProjects: [project], }; }); @@ -362,7 +363,7 @@ export function createAPI(overrideReleaseConfig: NxReleaseConfiguration) { body: c.body, isBreaking: c.isBreaking, githubReferences: c.references, - author: c.author, + authors: [c.author], shortHash: c.shortHash, revertedHashes: c.revertedHashes, affectedProjects: '*', @@ -515,13 +516,14 @@ export function createAPI(overrideReleaseConfig: NxReleaseConfiguration) { const releaseType = versionPlanSemverReleaseTypeToChangelogType(bumpForProject); let githubReferences = []; - let author = undefined; + let authors = []; const parsedCommit = vp.commit ? parseGitCommit(vp.commit, true) : null; if (parsedCommit) { githubReferences = parsedCommit.references; - author = parsedCommit.author; + // TODO(JamesHenry): Implement support for Co-authored-by and adding multiple authors + authors = [parsedCommit.author]; } return { type: releaseType.type, @@ -531,8 +533,8 @@ export function createAPI(overrideReleaseConfig: NxReleaseConfiguration) { isBreaking: releaseType.isBreaking, affectedProjects: Object.keys(vp.projectVersionBumps), githubReferences, - author, - }; + authors, + } as ChangelogChange; }) .filter(Boolean); } else { @@ -589,7 +591,8 @@ export function createAPI(overrideReleaseConfig: NxReleaseConfiguration) { body: c.body, isBreaking: c.isBreaking, githubReferences: c.references, - author: c.author, + // TODO(JamesHenry): Implement support for Co-authored-by and adding multiple authors + authors: [c.author], shortHash: c.shortHash, revertedHashes: c.revertedHashes, affectedProjects: commitChangesNonProjectFiles( @@ -606,18 +609,12 @@ export function createAPI(overrideReleaseConfig: NxReleaseConfiguration) { const projectChangelogs = await generateChangelogForProjects({ tree, args, - projectGraph, changes, projectsVersionData, releaseGroup, projects: [project], nxReleaseConfig, projectToAdditionalDependencyBumps, - // TODO: remove this after the changelog renderer is refactored to remove coupling with git commits - commits: filterHiddenCommits( - commits, - nxReleaseConfig.conventionalCommits - ), }); let hasPushed = false; @@ -688,7 +685,8 @@ export function createAPI(overrideReleaseConfig: NxReleaseConfiguration) { body: '', isBreaking: releaseType.isBreaking, githubReferences, - author, + // TODO(JamesHenry): Implement support for Co-authored-by and adding multiple authors + authors: [author], affectedProjects: '*', } : vp.triggeredByProjects.map((project) => { @@ -699,7 +697,8 @@ export function createAPI(overrideReleaseConfig: NxReleaseConfiguration) { body: '', isBreaking: releaseType.isBreaking, githubReferences, - author, + // TODO(JamesHenry): Implement support for Co-authored-by and adding multiple authors + authors: [author], affectedProjects: [project], }; }); @@ -745,7 +744,8 @@ export function createAPI(overrideReleaseConfig: NxReleaseConfiguration) { body: c.body, isBreaking: c.isBreaking, githubReferences: c.references, - author: c.author, + // TODO(JamesHenry): Implement support for Co-authored-by and adding multiple authors + authors: [c.author], shortHash: c.shortHash, revertedHashes: c.revertedHashes, affectedProjects: commitChangesNonProjectFiles( @@ -762,18 +762,12 @@ export function createAPI(overrideReleaseConfig: NxReleaseConfiguration) { const projectChangelogs = await generateChangelogForProjects({ tree, args, - projectGraph, changes, projectsVersionData, releaseGroup, projects: projectNodes, nxReleaseConfig, projectToAdditionalDependencyBumps, - // TODO: remove this after the changelog renderer is refactored to remove coupling with git commits - commits: filterHiddenCommits( - commits, - nxReleaseConfig.conventionalCommits - ), }); let hasPushed = false; @@ -1094,7 +1088,7 @@ async function generateChangelogForWorkspace({ const dryRun = !!args.dryRun; const gitRemote = args.gitRemote; - const changelogRenderer = resolveChangelogRenderer(config.renderer); + const ChangelogRendererClass = resolveChangelogRenderer(config.renderer); let interpolatedTreePath = config.file || ''; if (interpolatedTreePath) { @@ -1121,18 +1115,17 @@ async function generateChangelogForWorkspace({ const githubRepoData = getGitHubRepoData(gitRemote, config.createRelease); - let contents = await changelogRenderer({ - projectGraph, + const changelogRenderer = new ChangelogRendererClass({ changes, - commits, - releaseVersion: releaseVersion.rawVersion, + changelogEntryVersion: releaseVersion.rawVersion, project: null, - repoSlug: githubRepoData?.slug, + isVersionPlans: false, repoData: githubRepoData, entryWhenNoChanges: config.entryWhenNoChanges, changelogRenderOptions: config.renderOptions, conventionalCommitsConfig: nxReleaseConfig.conventionalCommits, }); + let contents = await changelogRenderer.render(); /** * If interactive mode, make the changelog contents available for the user to modify in their editor of choice, @@ -1191,9 +1184,7 @@ async function generateChangelogForWorkspace({ async function generateChangelogForProjects({ tree, args, - projectGraph, changes, - commits, projectsVersionData, releaseGroup, projects, @@ -1202,9 +1193,7 @@ async function generateChangelogForProjects({ }: { tree: Tree; args: ChangelogOptions; - projectGraph: ProjectGraph; changes: ChangelogChange[]; - commits: GitCommit[]; projectsVersionData: VersionData; releaseGroup: ReleaseGroupWithName; projects: ProjectGraphProjectNode[]; @@ -1223,7 +1212,7 @@ async function generateChangelogForProjects({ const dryRun = !!args.dryRun; const gitRemote = args.gitRemote; - const changelogRenderer = resolveChangelogRenderer(config.renderer); + const ChangelogRendererClass = resolveChangelogRenderer(config.renderer); const projectChangelogs: NxReleaseChangelogResult['projectChangelogs'] = {}; @@ -1262,13 +1251,10 @@ async function generateChangelogForProjects({ const githubRepoData = getGitHubRepoData(gitRemote, config.createRelease); - let contents = await changelogRenderer({ - projectGraph, + const changelogRenderer = new ChangelogRendererClass({ changes, - commits, - releaseVersion: releaseVersion.rawVersion, + changelogEntryVersion: releaseVersion.rawVersion, project: project.name, - repoSlug: githubRepoData?.slug, repoData: githubRepoData, entryWhenNoChanges: typeof config.entryWhenNoChanges === 'string' @@ -1279,11 +1265,13 @@ async function generateChangelogForProjects({ }) : false, changelogRenderOptions: config.renderOptions, + isVersionPlans: !!releaseGroup.versionPlans, conventionalCommitsConfig: releaseGroup.versionPlans ? null : nxReleaseConfig.conventionalCommits, dependencyBumps: projectToAdditionalDependencyBumps.get(project.name), }); + let contents = await changelogRenderer.render(); /** * If interactive mode, make the changelog contents available for the user to modify in their editor of choice, diff --git a/packages/nx/src/command-line/release/config/filter-release-groups.spec.ts b/packages/nx/src/command-line/release/config/filter-release-groups.spec.ts index 97d1a63669353d..12d0ec341e7b6e 100644 --- a/packages/nx/src/command-line/release/config/filter-release-groups.spec.ts +++ b/packages/nx/src/command-line/release/config/filter-release-groups.spec.ts @@ -1,7 +1,7 @@ -import { type ProjectGraph } from '../../../devkit-exports'; import { IMPLICIT_DEFAULT_RELEASE_GROUP, NxReleaseConfig } from './config'; import { DEFAULT_CONVENTIONAL_COMMITS_CONFIG } from './conventional-commits'; import { filterReleaseGroups } from './filter-release-groups'; +import type { ProjectGraph } from '../../../config/project-graph'; describe('filterReleaseGroups()', () => { let projectGraph: ProjectGraph; diff --git a/packages/nx/src/command-line/release/index.ts b/packages/nx/src/command-line/release/index.ts index 43707974583d4f..0fb8e0a2080c3d 100644 --- a/packages/nx/src/command-line/release/index.ts +++ b/packages/nx/src/command-line/release/index.ts @@ -25,6 +25,10 @@ export const releaseChangelog = defaultClient.releaseChangelog.bind( defaultClient ) as typeof defaultClient.releaseChangelog; +/** + * @public + */ +export { PublishProjectsResult } from './publish'; /** * @public */ diff --git a/packages/nx/src/command-line/release/publish.ts b/packages/nx/src/command-line/release/publish.ts index bf2ccc6f38427a..2dd875bd13581a 100644 --- a/packages/nx/src/command-line/release/publish.ts +++ b/packages/nx/src/command-line/release/publish.ts @@ -9,13 +9,13 @@ import { } from '../../config/project-graph'; import { createProjectFileMapUsingProjectGraph } from '../../project-graph/file-map-utils'; import { createProjectGraphAsync } from '../../project-graph/project-graph'; -import { runCommand } from '../../tasks-runner/run-command'; +import { runCommandForTasks } from '../../tasks-runner/run-command'; import { createOverrides, readGraphFileFromGraphArg, } from '../../utils/command-line-utils'; -import { output } from '../../utils/output'; import { handleErrors } from '../../utils/handle-errors'; +import { output } from '../../utils/output'; import { projectHasTarget } from '../../utils/project-graph-utils'; import { generateGraph } from '../graph/graph'; import { PublishOptions } from './command-object'; @@ -27,8 +27,24 @@ import { deepMergeJson } from './config/deep-merge-json'; import { filterReleaseGroups } from './config/filter-release-groups'; import { printConfigAndExit } from './utils/print-config'; +export interface PublishProjectsResult { + [projectName: string]: { + code: number; + }; +} + export const releasePublishCLIHandler = (args: PublishOptions) => - handleErrors(args.verbose, () => createAPI({})(args, true)); + handleErrors(args.verbose, async () => { + const publishProjectsResult: PublishProjectsResult = await createAPI({})( + args + ); + // If all projects are published successfully, return 0, otherwise return 1 + return Object.values(publishProjectsResult).every( + (result) => result.code === 0 + ) + ? 0 + : 1; + }); export function createAPI(overrideReleaseConfig: NxReleaseConfiguration) { /** @@ -37,9 +53,8 @@ export function createAPI(overrideReleaseConfig: NxReleaseConfiguration) { * to have control over their own error handling when using the API. */ return async function releasePublish( - args: PublishOptions, - isCLI = false - ): Promise { + args: PublishOptions + ): Promise { /** * When used via the CLI, the args object will contain a __overrides_unparsed__ property that is * important for invoking the relevant executor behind the scenes. @@ -98,53 +113,53 @@ export function createAPI(overrideReleaseConfig: NxReleaseConfiguration) { _args.groups?.length > 0 || args.excludeTaskDependencies; - let overallExitStatus = 0; + let overallPublishProjectsResult: PublishProjectsResult = {}; if (args.projects?.length) { /** * Run publishing for all remaining release groups and filtered projects within them */ for (const releaseGroup of releaseGroups) { - const status = await runPublishOnProjects( + const publishProjectsResult = await runPublishOnProjects( _args, projectGraph, nxJson, Array.from(releaseGroupToFilteredProjects.get(releaseGroup)), - isCLI, { excludeTaskDependencies: shouldExcludeTaskDependencies, loadDotEnvFiles: process.env.NX_LOAD_DOT_ENV_FILES !== 'false', } ); - if (status !== 0) { - overallExitStatus = status || 1; - } + overallPublishProjectsResult = { + ...overallPublishProjectsResult, + ...publishProjectsResult, + }; } - return overallExitStatus; + return overallPublishProjectsResult; } /** * Run publishing for all remaining release groups */ for (const releaseGroup of releaseGroups) { - const status = await runPublishOnProjects( + const publishProjectsResult = await runPublishOnProjects( _args, projectGraph, nxJson, releaseGroup.projects, - isCLI, { excludeTaskDependencies: shouldExcludeTaskDependencies, loadDotEnvFiles: process.env.NX_LOAD_DOT_ENV_FILES !== 'false', } ); - if (status !== 0) { - overallExitStatus = status || 1; - } + overallPublishProjectsResult = { + ...overallPublishProjectsResult, + ...publishProjectsResult, + }; } - return overallExitStatus; + return overallPublishProjectsResult; }; } @@ -153,12 +168,11 @@ async function runPublishOnProjects( projectGraph: ProjectGraph, nxJson: NxJsonConfiguration, projectNames: string[], - isCLI: boolean, extraOptions: { excludeTaskDependencies: boolean; loadDotEnvFiles: boolean; } -): Promise { +): Promise { const projectsToRun: ProjectGraphProjectNode[] = projectNames.map( (projectName) => projectGraph.nodes[projectName] ); @@ -212,7 +226,7 @@ async function runPublishOnProjects( }, projectNamesWithTarget ); - return 0; + return {}; } const projectsWithTarget = projectsToRun.filter((project) => @@ -232,7 +246,7 @@ async function runPublishOnProjects( /** * Run the relevant nx-release-publish executor on each of the selected projects. */ - const status = await runCommand( + const commandResults = await runCommandForTasks( projectsWithTarget, projectGraph, { nxJson }, @@ -249,16 +263,12 @@ async function runPublishOnProjects( extraOptions ); - if (status !== 0) { - // In order to not add noise to the overall CLI output, do not throw an additional error - if (isCLI) { - return status; - } - // Throw an additional error for programmatic API usage - throw new Error( - 'One or more of the selected projects could not be published' - ); + const publishProjectsResult: PublishProjectsResult = {}; + for (const taskData of Object.values(commandResults)) { + publishProjectsResult[taskData.task.target.project] = { + code: taskData.code, + }; } - return 0; + return publishProjectsResult; } diff --git a/packages/nx/src/command-line/release/utils/print-changes.ts b/packages/nx/src/command-line/release/utils/print-changes.ts index 28febcb9935172..f27d0941d1a936 100644 --- a/packages/nx/src/command-line/release/utils/print-changes.ts +++ b/packages/nx/src/command-line/release/utils/print-changes.ts @@ -1,12 +1,10 @@ import * as chalk from 'chalk'; import { diff } from 'jest-diff'; import { readFileSync } from 'node:fs'; -import { - joinPathFragments, - logger, - workspaceRoot, -} from '../../../devkit-exports'; import { Tree, flushChanges } from '../../../generators/tree'; +import { workspaceRoot } from '../../../utils/workspace-root'; +import { joinPathFragments } from '../../../utils/path'; +import { logger } from '../../../utils/logger'; // jest-diff does not export this constant const NO_DIFF_MESSAGE = 'Compared values have no visual difference.'; diff --git a/packages/nx/src/command-line/release/utils/resolve-changelog-renderer.ts b/packages/nx/src/command-line/release/utils/resolve-changelog-renderer.ts index 0f9ea95e1fa55e..43d1c73ee0989e 100644 --- a/packages/nx/src/command-line/release/utils/resolve-changelog-renderer.ts +++ b/packages/nx/src/command-line/release/utils/resolve-changelog-renderer.ts @@ -1,4 +1,4 @@ -import type { ChangelogRenderer } from '../../../../release/changelog-renderer'; +import type ChangelogRenderer from '../../../../release/changelog-renderer'; import { registerTsProject } from '../../../plugins/js/utils/register'; import { getRootTsConfigPath } from '../../../plugins/js/utils/typescript'; import { interpolate } from '../../../tasks-runner/utils'; @@ -6,13 +6,13 @@ import { workspaceRoot } from '../../../utils/workspace-root'; export function resolveChangelogRenderer( changelogRendererPath: string -): ChangelogRenderer { +): typeof ChangelogRenderer { const interpolatedChangelogRendererPath = interpolate(changelogRendererPath, { workspaceRoot, }); // Try and load the provided (or default) changelog renderer - let changelogRenderer: ChangelogRenderer; + let ChangelogRendererClass: typeof ChangelogRenderer; let cleanupTranspiler = () => {}; try { const rootTsconfigPath = getRootTsConfigPath(); @@ -20,11 +20,11 @@ export function resolveChangelogRenderer( cleanupTranspiler = registerTsProject(rootTsconfigPath); } const r = require(interpolatedChangelogRendererPath); - changelogRenderer = r.default || r; + ChangelogRendererClass = r.default || r; } catch (err) { throw err; } finally { cleanupTranspiler(); } - return changelogRenderer; + return ChangelogRendererClass; } diff --git a/packages/nx/src/command-line/release/utils/resolve-nx-json-error-message.ts b/packages/nx/src/command-line/release/utils/resolve-nx-json-error-message.ts index dd6d04bf897574..d9d9d5f5dc035b 100644 --- a/packages/nx/src/command-line/release/utils/resolve-nx-json-error-message.ts +++ b/packages/nx/src/command-line/release/utils/resolve-nx-json-error-message.ts @@ -1,6 +1,7 @@ import { readFileSync } from 'node:fs'; import { relative } from 'node:path'; -import { joinPathFragments, workspaceRoot } from '../../../devkit-exports'; +import { joinPathFragments } from '../../../utils/path'; +import { workspaceRoot } from '../../../utils/workspace-root'; export async function resolveNxJsonConfigErrorMessage( propPath: string[] diff --git a/packages/nx/src/command-line/release/version.ts b/packages/nx/src/command-line/release/version.ts index e93015cbd3217d..a188d6fdfcd80d 100644 --- a/packages/nx/src/command-line/release/version.ts +++ b/packages/nx/src/command-line/release/version.ts @@ -86,10 +86,10 @@ export interface ReleaseVersionGeneratorSchema { conventionalCommitsConfig?: NxReleaseConfig['conventionalCommits']; deleteVersionPlans?: boolean; /** - * 'auto' allows users to opt into dependents being updated (a patch version bump) when a dependency is versioned. - * This is only applicable to independently released projects. + * 'auto' is the default and will cause dependents to be updated (a patch version bump) when a dependency is versioned. + * This is only applicable to independently released projects. 'never' will cause dependents to not be updated. */ - updateDependents?: 'never' | 'auto'; + updateDependents?: 'auto' | 'never'; /** * Whether or not to completely omit project logs when that project has no applicable changes. This can be useful for * large monorepos which have a large number of projects, especially when only a subset are released together. diff --git a/packages/nx/src/command-line/yargs-utils/shared-options.ts b/packages/nx/src/command-line/yargs-utils/shared-options.ts index 6d0247b60b1265..0dcb210724298b 100644 --- a/packages/nx/src/command-line/yargs-utils/shared-options.ts +++ b/packages/nx/src/command-line/yargs-utils/shared-options.ts @@ -96,9 +96,9 @@ export function withRunOptions(yargs: Argv): Argv { default: false, }) .option('skipSync', { + describe: 'Skips running the sync generators associated with the tasks.', type: 'boolean', - // TODO(leo): add description and make it visible once it is stable - hidden: true, + default: false, }) .options('cloud', { type: 'boolean', diff --git a/packages/nx/src/internal-testing-utils/assert-valid-migrations.ts b/packages/nx/src/internal-testing-utils/assert-valid-migrations.ts index 4902ca6a04edb2..950822d3f8c0af 100644 --- a/packages/nx/src/internal-testing-utils/assert-valid-migrations.ts +++ b/packages/nx/src/internal-testing-utils/assert-valid-migrations.ts @@ -2,17 +2,26 @@ import { MigrationsJson, MigrationsJsonEntry } from '../config/misc-interfaces'; import * as path from 'path'; export function assertValidMigrationPaths(json: MigrationsJson, root: string) { + let hasTests = false; Object.entries(json.generators).forEach(([generator, m]) => { - it(`should have valid path generator: ${generator}`, () => { + hasTests = true; + it(`should have valid path generator: ${generator}`, () => { validateMigration(m, root); }); }); Object.entries(json.schematics ?? {}).forEach(([schematic, m]) => { + hasTests = true; it(`should have valid path schematic: ${schematic}`, () => { validateMigration(m, root); }); }); + + if (!hasTests) { + it('should pass without migrations', () => { + // no-op + }); + } } function validateMigration(m: MigrationsJsonEntry, root: string) { diff --git a/packages/nx/src/migrations/update-15-0-0/prefix-outputs.spec.ts b/packages/nx/src/migrations/update-15-0-0/prefix-outputs.spec.ts deleted file mode 100644 index dad298a7a394b7..00000000000000 --- a/packages/nx/src/migrations/update-15-0-0/prefix-outputs.spec.ts +++ /dev/null @@ -1,192 +0,0 @@ -import { createTreeWithEmptyWorkspace } from '../../generators/testing-utils/create-tree-with-empty-workspace'; -import type { Tree } from '../../generators/tree'; -import { - addProjectConfiguration, - readNxJson, - readProjectConfiguration, - updateNxJson, -} from '../../generators/utils/project-configuration'; -import { readJson, writeJson } from '../../generators/utils/json'; -import prefixOutputs from './prefix-outputs'; -import { validateOutputs } from '../../tasks-runner/utils'; - -describe('15.0.0 migration (prefix-outputs)', () => { - let tree: Tree; - - beforeEach(() => { - tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); - }); - - it('should prefix project outputs', async () => { - addProjectConfiguration(tree, 'proj', { - root: 'proj', - targets: { - build: { - executor: 'nx:run-commands', - outputs: [ - 'dist', - 'dist/{projectRoot}', - 'dist/{projectRoot}/**/*.js', - 'proj/coverage', - './test-results', - '{projectRoot}/build', - '{options.outputDirectory}', - ], - options: {}, - }, - }, - }); - - await prefixOutputs(tree); - - const updated = readProjectConfiguration(tree, 'proj'); - - expect(updated.targets.build.outputs).toEqual([ - '{workspaceRoot}/dist', - '{workspaceRoot}/dist/{projectRoot}', - '{workspaceRoot}/dist/{projectRoot}/**/*.js', - '{projectRoot}/coverage', - '{projectRoot}/test-results', - '{projectRoot}/build', - '{options.outputDirectory}', - ]); - - expect(() => validateOutputs(updated.targets.build.outputs)).not.toThrow(); - }); - - it('should prefix target default outputs', async () => { - const nxJson = readNxJson(tree); - updateNxJson(tree, { - ...nxJson, - targetDefaults: { - build: { - outputs: ['dist', '{projectRoot}/build', '{options.outputPath}'], - }, - }, - }); - - await prefixOutputs(tree); - - const updated = readNxJson(tree); - - expect(updated.targetDefaults).toMatchInlineSnapshot(` - { - "build": { - "outputs": [ - "{workspaceRoot}/dist", - "{projectRoot}/build", - "{options.outputPath}", - ], - }, - } - `); - }); - - it('should migrate package.json projects', async () => { - writeJson(tree, 'proj/package.json', { - name: 'proj', - scripts: { - build: 'echo', - }, - nx: { - targets: { - build: { - outputs: ['dist/proj', 'proj/build'], - }, - }, - }, - }); - tree.delete('workspace.json'); - - await prefixOutputs(tree); - - expect(readJson(tree, 'proj/package.json').nx.targets.build).toEqual({ - outputs: ['{workspaceRoot}/dist/proj', '{projectRoot}/build'], - }); - }); - - it('should not error for package.json projects', async () => { - writeJson(tree, 'proj/package.json', { - name: 'proj', - scripts: { - build: 'echo', - }, - }); - tree.delete('workspace.json'); - - await prefixOutputs(tree); - }); - - it('should handle negated outputs', async () => { - const nxJson = readNxJson(tree); - updateNxJson(tree, { - ...nxJson, - targetDefaults: { - build: { - outputs: ['!dist', '{projectRoot}/build', '{options.outputPath}'], - }, - }, - }); - - await prefixOutputs(tree); - - const updated = readNxJson(tree); - - expect(updated.targetDefaults).toMatchInlineSnapshot(` - { - "build": { - "outputs": [ - "!{workspaceRoot}/dist", - "{projectRoot}/build", - "{options.outputPath}", - ], - }, - } - `); - }); -}); - -describe('15.0.0 migration (prefix-outputs) (v1)', () => { - let tree: Tree; - - beforeEach(() => { - tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); - }); - - it('should prefix project outputs', async () => { - addProjectConfiguration(tree, 'proj', { - root: 'proj', - targets: { - build: { - executor: 'nx:run-commands', - outputs: [ - 'dist', - 'dist/{projectRoot}', - 'dist/{projectRoot}/**/*.js', - 'proj/coverage', - './test-results', - '{projectRoot}/build', - '{options.outputDirectory}', - ], - options: {}, - }, - }, - }); - - await prefixOutputs(tree); - - const updated = readProjectConfiguration(tree, 'proj'); - - expect(updated.targets.build.outputs).toEqual([ - '{workspaceRoot}/dist', - '{workspaceRoot}/dist/{projectRoot}', - '{workspaceRoot}/dist/{projectRoot}/**/*.js', - '{projectRoot}/coverage', - '{projectRoot}/test-results', - '{projectRoot}/build', - '{options.outputDirectory}', - ]); - - expect(() => validateOutputs(updated.targets.build.outputs)).not.toThrow(); - }); -}); diff --git a/packages/nx/src/migrations/update-15-0-0/prefix-outputs.ts b/packages/nx/src/migrations/update-15-0-0/prefix-outputs.ts deleted file mode 100644 index 3c5f281670bf85..00000000000000 --- a/packages/nx/src/migrations/update-15-0-0/prefix-outputs.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { Tree } from '../../generators/tree'; -import { formatChangedFilesWithPrettierIfAvailable } from '../../generators/internal-utils/format-changed-files-with-prettier-if-available'; -import { - getProjects, - updateProjectConfiguration, -} from '../../generators/utils/project-configuration'; -import { readNxJson, updateNxJson } from '../../generators/utils/nx-json'; -import { joinPathFragments } from '../../utils/path'; -import { join } from 'path'; -import { - transformLegacyOutputs, - validateOutputs, -} from '../../tasks-runner/utils'; -import { updateJson } from '../../generators/utils/json'; -import { PackageJson } from '../../utils/package-json'; - -export default async function (tree: Tree) { - // If the workspace doesn't have a nx.json, don't make any changes - if (!tree.exists('nx.json')) { - return; - } - - const nxJson = readNxJson(tree); - - for (const [projectName, project] of getProjects(tree)) { - for (const [_, target] of Object.entries(project.targets ?? {})) { - if (!target.outputs) { - continue; - } - - target.outputs = transformLegacyOutputs(project.root, target.outputs); - } - try { - updateProjectConfiguration(tree, projectName, project); - } catch { - if (tree.exists(join(project.root, 'package.json'))) { - updateJson( - tree, - join(project.root, 'package.json'), - (json) => { - for (const target of Object.values(json.nx?.targets ?? {})) { - if (target.outputs) { - target.outputs = transformLegacyOutputs( - project.root, - target.outputs - ); - } - } - - return json; - } - ); - } - } - } - - if (nxJson.targetDefaults) { - for (const [_, target] of Object.entries(nxJson.targetDefaults)) { - if (!target.outputs) { - continue; - } - target.outputs = transformLegacyOutputs('{projectRoot}', target.outputs); - } - - updateNxJson(tree, nxJson); - } - - await formatChangedFilesWithPrettierIfAvailable(tree); -} diff --git a/packages/nx/src/migrations/update-16-0-0/remove-nrwl-cli.ts b/packages/nx/src/migrations/update-16-0-0/remove-nrwl-cli.ts deleted file mode 100644 index f13430e58ec2b3..00000000000000 --- a/packages/nx/src/migrations/update-16-0-0/remove-nrwl-cli.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Tree } from '../../generators/tree'; -import { formatChangedFilesWithPrettierIfAvailable } from '../../generators/internal-utils/format-changed-files-with-prettier-if-available'; -import { updateJson } from '../../generators/utils/json'; - -export default async function (tree: Tree) { - updateJson(tree, 'package.json', (json) => { - for (const deps of [json.dependencies, json.devDependencies]) { - if (deps) { - delete deps['@nrwl/cli']; - } - } - - return json; - }); - - await formatChangedFilesWithPrettierIfAvailable(tree); -} diff --git a/packages/nx/src/migrations/update-16-0-0/update-depends-on-to-tokens.spec.ts b/packages/nx/src/migrations/update-16-0-0/update-depends-on-to-tokens.spec.ts deleted file mode 100644 index fed29c7aa59fb6..00000000000000 --- a/packages/nx/src/migrations/update-16-0-0/update-depends-on-to-tokens.spec.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { - addProjectConfiguration, - readNxJson, - readProjectConfiguration, -} from '../../generators/utils/project-configuration'; - -import update from './update-depends-on-to-tokens'; -import { updateJson, writeJson } from '../../generators/utils/json'; -import { createTreeWithEmptyWorkspace } from '../../generators/testing-utils/create-tree-with-empty-workspace'; -import { assertRunsAgainstNxRepo } from '../../internal-testing-utils/run-migration-against-this-workspace'; - -describe('update-depends-on-to-tokens', () => { - it('should update nx.json', async () => { - const tree = createTreeWithEmptyWorkspace(); - updateJson(tree, 'nx.json', (json) => { - json.targetDefaults = { - build: { - dependsOn: [ - { - projects: 'self', - }, - ], - inputs: [{ projects: 'self', input: 'someInput' }], - }, - test: { - dependsOn: [ - { - projects: 'dependencies', - }, - ], - inputs: [{ projects: 'dependencies', input: 'someInput' }], - }, - other: { - dependsOn: ['^deps'], - }, - }; - return json; - }); - await update(tree); - const nxJson = readNxJson(tree); - const buildDependencyConfiguration = nxJson.targetDefaults.build - .dependsOn[0] as any; - const testDependencyConfiguration = nxJson.targetDefaults.test - .dependsOn[0] as any; - const buildInputConfiguration = nxJson.targetDefaults.build - .inputs[0] as any; - const testInputConfiguration = nxJson.targetDefaults.test.inputs[0] as any; - expect(buildDependencyConfiguration.projects).not.toBeDefined(); - expect(buildDependencyConfiguration.dependencies).not.toBeDefined(); - expect(buildInputConfiguration.projects).not.toBeDefined(); - expect(buildInputConfiguration.dependencies).not.toBeDefined(); - expect(testInputConfiguration.projects).not.toBeDefined(); - expect(testInputConfiguration.dependencies).toEqual(true); - expect(testDependencyConfiguration.projects).not.toBeDefined(); - expect(testDependencyConfiguration.dependencies).toEqual(true); - expect(nxJson.targetDefaults.other.dependsOn).toEqual(['^deps']); - }); - - it('should update project configurations', async () => { - const tree = createTreeWithEmptyWorkspace(); - addProjectConfiguration(tree, 'proj1', { - root: 'proj1', - targets: { - build: { - dependsOn: [ - { - projects: 'self', - target: 'build', - }, - ], - inputs: [{ projects: 'self', input: 'someInput' }], - }, - test: { - dependsOn: [ - { - projects: 'dependencies', - target: 'test', - }, - ], - inputs: [{ projects: 'dependencies', input: 'someInput' }], - }, - other: { - dependsOn: ['^deps'], - }, - }, - }); - await update(tree); - const project = readProjectConfiguration(tree, 'proj1'); - const buildDependencyConfiguration = project.targets.build - .dependsOn[0] as any; - const testDependencyConfiguration = project.targets.test - .dependsOn[0] as any; - const buildInputConfiguration = project.targets.build.inputs[0] as any; - const testInputConfiguration = project.targets.test.inputs[0] as any; - expect(buildDependencyConfiguration.projects).not.toBeDefined(); - expect(buildDependencyConfiguration.dependencies).not.toBeDefined(); - expect(buildInputConfiguration.projects).not.toBeDefined(); - expect(buildInputConfiguration.dependencies).not.toBeDefined(); - expect(testDependencyConfiguration.projects).not.toBeDefined(); - expect(testDependencyConfiguration.dependencies).toEqual(true); - expect(testInputConfiguration.projects).not.toBeDefined(); - expect(testInputConfiguration.dependencies).toEqual(true); - expect(project.targets.other.dependsOn).toEqual(['^deps']); - expect(project.targets.other.inputs).not.toBeDefined(); - }); - - it('should not throw on nulls', async () => { - const tree = createTreeWithEmptyWorkspace(); - addProjectConfiguration(tree, 'proj1', { - root: 'proj1', - }); - addProjectConfiguration(tree, 'proj2', { - root: 'proj2', - targets: { - build: {}, - }, - }); - writeJson(tree, 'nx.json', {}); - let promise = update(tree); - await expect(promise).resolves.toBeUndefined(); - writeJson(tree, 'nx.json', { - targetDefaults: { - build: {}, - }, - }); - promise = update(tree); - await expect(promise).resolves.toBeUndefined(); - }); - - assertRunsAgainstNxRepo(update); -}); diff --git a/packages/nx/src/migrations/update-16-0-0/update-depends-on-to-tokens.ts b/packages/nx/src/migrations/update-16-0-0/update-depends-on-to-tokens.ts deleted file mode 100644 index 6fabe17983a676..00000000000000 --- a/packages/nx/src/migrations/update-16-0-0/update-depends-on-to-tokens.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { - getProjects, - readNxJson, - updateNxJson, - updateProjectConfiguration, -} from '../../generators/utils/project-configuration'; -import { Tree } from '../../generators/tree'; -import { formatChangedFilesWithPrettierIfAvailable } from '../../generators/internal-utils/format-changed-files-with-prettier-if-available'; - -export default async function (tree: Tree) { - updateDependsOnAndInputsInsideNxJson(tree); - - const projectsConfigurations = getProjects(tree); - for (const [projectName, projectConfiguration] of projectsConfigurations) { - let projectChanged = false; - for (const [targetName, targetConfiguration] of Object.entries( - projectConfiguration.targets ?? {} - )) { - for (const dependency of targetConfiguration.dependsOn ?? []) { - if (typeof dependency !== 'string') { - if ( - dependency.projects === 'self' || - dependency.projects === '{self}' - ) { - delete dependency.projects; - projectChanged = true; - } else if ( - dependency.projects === 'dependencies' || - dependency.projects === '{dependencies}' - ) { - delete dependency.projects; - dependency.dependencies = true; - projectChanged = true; - } - } - } - for (let i = 0; i < targetConfiguration.inputs?.length ?? 0; i++) { - const input = targetConfiguration.inputs[i]; - if (typeof input !== 'string') { - if ( - 'projects' in input && - (input.projects === 'self' || input.projects === '{self}') - ) { - delete input.projects; - projectChanged = true; - } else if ( - 'projects' in input && - (input.projects === 'dependencies' || - input.projects === '{dependencies}') - ) { - delete input.projects; - targetConfiguration.inputs[i] = { - ...input, - dependencies: true, - }; - projectChanged = true; - } - } - } - } - if (projectChanged) { - updateProjectConfiguration(tree, projectName, projectConfiguration); - } - } - - await formatChangedFilesWithPrettierIfAvailable(tree); -} -function updateDependsOnAndInputsInsideNxJson(tree: Tree) { - const nxJson = readNxJson(tree); - let nxJsonChanged = false; - for (const [target, defaults] of Object.entries( - nxJson?.targetDefaults ?? {} - )) { - for (const dependency of defaults.dependsOn ?? []) { - if (typeof dependency !== 'string') { - if ( - dependency.projects === 'self' || - dependency.projects === '{self}' - ) { - delete dependency.projects; - nxJsonChanged = true; - } else if ( - dependency.projects === 'dependencies' || - dependency.projects === '{dependencies}' - ) { - delete dependency.projects; - dependency.dependencies = true; - nxJsonChanged = true; - } - } - } - for (let i = 0; i < defaults.inputs?.length ?? 0; i++) { - const input = defaults.inputs[i]; - if (typeof input !== 'string') { - if ( - 'projects' in input && - (input.projects === 'self' || input.projects === '{self}') - ) { - delete input.projects; - nxJsonChanged = true; - } else if ( - 'projects' in input && - (input.projects === 'dependencies' || - input.projects === '{dependencies}') - ) { - delete input.projects; - defaults.inputs[i] = { - ...input, - dependencies: true, - }; - nxJsonChanged = true; - } - } - } - } - if (nxJsonChanged) { - updateNxJson(tree, nxJson); - } -} diff --git a/packages/nx/src/migrations/update-16-0-0/update-nx-cloud-runner.ts b/packages/nx/src/migrations/update-16-0-0/update-nx-cloud-runner.ts deleted file mode 100644 index 23b663ee4086af..00000000000000 --- a/packages/nx/src/migrations/update-16-0-0/update-nx-cloud-runner.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { - readNxJson, - updateNxJson, -} from '../../generators/utils/project-configuration'; -import { Tree } from '../../generators/tree'; -import { updateJson } from '../../generators/utils/json'; -import { formatChangedFilesWithPrettierIfAvailable } from '../../generators/internal-utils/format-changed-files-with-prettier-if-available'; - -export default async function (tree: Tree) { - updateJson(tree, 'package.json', (json) => { - if (json.dependencies && json.dependencies['@nrwl/nx-cloud']) { - json.dependencies['nx-cloud'] = json.dependencies['@nrwl/nx-cloud']; - delete json.dependencies['@nrwl/nx-cloud']; - } - - if (json.devDependencies && json.devDependencies['@nrwl/nx-cloud']) { - json.devDependencies['nx-cloud'] = json.devDependencies['@nrwl/nx-cloud']; - delete json.devDependencies['@nrwl/nx-cloud']; - } - - return json; - }); - - const nxJson = readNxJson(tree); - if (!nxJson) return; - for (let opts of Object.values(nxJson.tasksRunnerOptions ?? {})) { - if (opts.runner === '@nrwl/nx-cloud') { - opts.runner = 'nx-cloud'; - } - } - updateNxJson(tree, nxJson); - - await formatChangedFilesWithPrettierIfAvailable(tree); -} diff --git a/packages/nx/src/migrations/update-16-2-0/remove-run-commands-output-path.spec.ts b/packages/nx/src/migrations/update-16-2-0/remove-run-commands-output-path.spec.ts deleted file mode 100644 index f0d48d98fe2e30..00000000000000 --- a/packages/nx/src/migrations/update-16-2-0/remove-run-commands-output-path.spec.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { TargetConfiguration } from '../../config/workspace-json-project-json'; -import { createTreeWithEmptyWorkspace } from '../../generators/testing-utils/create-tree-with-empty-workspace'; -import { readJson, writeJson } from '../../generators/utils/json'; -import { - addProjectConfiguration, - readProjectConfiguration, -} from '../../generators/utils/project-configuration'; -import { assertRunsAgainstNxRepo } from '../../internal-testing-utils/run-migration-against-this-workspace'; -import removeRunCommandsOutputPath from './remove-run-commands-output-path'; - -describe('removeRunCommandsOutputPath', () => { - it('should migrate target options correctly', () => { - const tree = createTreeWithEmptyWorkspace(); - const startingTargets: Record = { - build: { - executor: 'nx:run-commands', - outputs: ['{options.outputPath}'], - options: { - outputPath: 'dist/apps/my-app', - commands: [], - }, - }, - other: { - executor: 'nx:run-script', - options: { - script: 'start', - }, - }, - }; - addProjectConfiguration(tree, 'my-app', { - root: 'apps/my-app', - targets: startingTargets, - }); - removeRunCommandsOutputPath(tree); - const migratedTargets = readProjectConfiguration(tree, 'my-app').targets; - expect(migratedTargets.build).not.toEqual(startingTargets.build); - expect(migratedTargets.build).toEqual({ - executor: 'nx:run-commands', - outputs: ['{workspaceRoot}/dist/apps/my-app'], - options: { - commands: [], - }, - }); - expect(migratedTargets.other).toEqual(startingTargets.other); - }); - - it('should handle null options correctly', () => { - const tree = createTreeWithEmptyWorkspace(); - const startingTargets: Record = { - build: { - executor: 'nx:run-commands', - outputs: ['dist/some/path'], - }, - }; - addProjectConfiguration(tree, 'my-app', { - root: 'apps/my-app', - targets: startingTargets, - }); - expect(() => removeRunCommandsOutputPath(tree)).not.toThrow(); - const migratedTargets = readProjectConfiguration(tree, 'my-app').targets; - expect(migratedTargets.build).toEqual(startingTargets.build); - expect(migratedTargets.other).toEqual(startingTargets.other); - }); - - it('should migrate target defaults correctly', () => { - const tree = createTreeWithEmptyWorkspace(); - const startingTargetDefaults: Record = { - build: { - executor: 'nx:run-commands', - outputs: ['{options.outputPath}'], - options: { - outputPath: 'dist/apps/my-app', - commands: [], - }, - }, - other: { - executor: 'nx:run-script', - options: { - script: 'start', - }, - }, - }; - writeJson(tree, 'nx.json', { - targetDefaults: startingTargetDefaults, - }); - removeRunCommandsOutputPath(tree); - const migratedTargetDefaults = readJson(tree, 'nx.json').targetDefaults; - expect(migratedTargetDefaults.build).not.toEqual( - startingTargetDefaults.build - ); - expect(migratedTargetDefaults.build).toEqual({ - executor: 'nx:run-commands', - outputs: ['{workspaceRoot}/dist/apps/my-app'], - options: { - commands: [], - }, - }); - expect(migratedTargetDefaults.other).toEqual(startingTargetDefaults.other); - }); - - assertRunsAgainstNxRepo(removeRunCommandsOutputPath); -}); diff --git a/packages/nx/src/migrations/update-16-2-0/remove-run-commands-output-path.ts b/packages/nx/src/migrations/update-16-2-0/remove-run-commands-output-path.ts deleted file mode 100644 index c2dc9d5c24d0fc..00000000000000 --- a/packages/nx/src/migrations/update-16-2-0/remove-run-commands-output-path.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { joinPathFragments } from '../../utils/path'; -import { NxJsonConfiguration } from '../../config/nx-json'; -import { TargetConfiguration } from '../../config/workspace-json-project-json'; -import { formatChangedFilesWithPrettierIfAvailable } from '../../generators/internal-utils/format-changed-files-with-prettier-if-available'; -import { Tree } from '../../generators/tree'; -import { updateJson } from '../../generators/utils/json'; -import { - getProjects, - updateProjectConfiguration, -} from '../../generators/utils/project-configuration'; - -export default async function removeRunCommandsOutputPath(tree: Tree) { - for (const [project, configuration] of getProjects(tree).entries()) { - const targets = configuration.targets ?? {}; - let changed = false; - for (const [, target] of Object.entries(targets)) { - changed ||= updateTargetBlock(target); - } - if (changed) { - updateProjectConfiguration(tree, project, configuration); - } - } - if (tree.exists('nx.json')) { - updateJson(tree, 'nx.json', (json) => { - for (const [, target] of Object.entries(json.targetDefaults ?? {})) { - updateTargetBlock(target); - } - return json; - }); - } - await formatChangedFilesWithPrettierIfAvailable(tree); -} - -function updateTargetBlock(target: TargetConfiguration): boolean { - let changed = false; - if (target.executor === 'nx:run-commands' && target.options?.outputPath) { - changed = true; - const outputs = new Set(target.outputs ?? []); - outputs.delete('{options.outputPath}'); - const newOutputs = Array.isArray(target.options.outputPath) - ? target.options.outputPath.map((p) => - joinPathFragments('{workspaceRoot}', p) - ) - : [joinPathFragments('{workspaceRoot}', target.options.outputPath)]; - for (const outputPath of newOutputs) { - outputs.add(outputPath); - } - delete target.options.outputPath; - target.outputs = Array.from(outputs); - } - return changed; -} diff --git a/packages/nx/src/migrations/update-16-8-0/escape-dollar-sign-env-variables.spec.ts b/packages/nx/src/migrations/update-16-8-0/escape-dollar-sign-env-variables.spec.ts deleted file mode 100644 index dc262102d10a02..00000000000000 --- a/packages/nx/src/migrations/update-16-8-0/escape-dollar-sign-env-variables.spec.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { createTreeWithEmptyWorkspace } from '../../generators/testing-utils/create-tree-with-empty-workspace'; -import { addProjectConfiguration } from '../../generators/utils/project-configuration'; -import escapeDollarSignEnvVariables from './escape-dollar-sign-env-variables'; - -describe('escape $ in env variables', () => { - let tree; - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - }); - - it('should escape $ in env variables in .env file', () => { - tree.write( - '.env', - `dollar=$ -NX_SOME_VAR=$ABC` - ); - escapeDollarSignEnvVariables(tree); - expect(tree.read('.env', 'utf-8')).toEqual(`dollar=\\$ -NX_SOME_VAR=\\$ABC`); - }); - - it('should escape $ env variables in .env file under project', () => { - addProjectConfiguration(tree, 'my-app', { - root: 'apps/my-app', - }); - addProjectConfiguration(tree, 'my-app2', { - root: 'apps/my-app2', - }); - tree.write( - 'apps/my-app/.env', - `dollar=$ -NX_SOME_VAR=$ABC` - ); - tree.write( - 'apps/my-app2/.env', - `dollar=$ -NX_SOME_VAR=$DEF` - ); - escapeDollarSignEnvVariables(tree); - expect(tree.read('apps/my-app/.env', 'utf-8')).toEqual(`dollar=\\$ -NX_SOME_VAR=\\$ABC`); - expect(tree.read('apps/my-app2/.env', 'utf-8')).toEqual(`dollar=\\$ -NX_SOME_VAR=\\$DEF`); - }); - - it('should escape $ env variables in .env for target', () => { - tree.write('.env', 'dollar=$'); - tree.write('.env.build', 'dollar=$'); - addProjectConfiguration(tree, 'my-app', { - root: 'apps/my-app', - targets: { - build: { - executor: '@nx/node:build', - configurations: { - production: {}, - }, - }, - }, - }); - tree.write( - 'apps/my-app/.build.env', - `dollar=$ -NX_SOME_VAR=$ABC` - ); - tree.write( - 'apps/my-app/.env', - `dollar=$ -NX_SOME_VAR=$ABC` - ); - escapeDollarSignEnvVariables(tree); - expect(tree.read('.env', 'utf-8')).toEqual(`dollar=\\$`); - expect(tree.read('apps/my-app/.env', 'utf-8')).toEqual(`dollar=\\$ -NX_SOME_VAR=\\$ABC`); - expect(tree.read('apps/my-app/.build.env', 'utf-8')).toEqual(`dollar=\\$ -NX_SOME_VAR=\\$ABC`); - }); - - it('should escape $ env variables in .env for configuration', () => { - tree.write('.env', 'dollar=$'); - tree.write('.env.production', 'dollar=$'); - addProjectConfiguration(tree, 'my-app', { - root: 'apps/my-app', - targets: { - build: { - executor: '@nx/node:build', - configurations: { - production: {}, - }, - }, - }, - }); - tree.write( - 'apps/my-app/.production.env', - `dollar=$ -NX_SOME_VAR=$ABC` - ); - tree.write( - 'apps/my-app/.build.production.env', - `dollar=$ -NX_SOME_VAR=$ABC` - ); - tree.write( - 'apps/my-app/.env', - `dollar=$ -NX_SOME_VAR=$ABC` - ); - escapeDollarSignEnvVariables(tree); - expect(tree.read('.env', 'utf-8')).toEqual(`dollar=\\$`); - expect(tree.read('apps/my-app/.env', 'utf-8')).toEqual(`dollar=\\$ -NX_SOME_VAR=\\$ABC`); - expect(tree.read('apps/my-app/.build.production.env', 'utf-8')) - .toEqual(`dollar=\\$ -NX_SOME_VAR=\\$ABC`); - expect(tree.read('apps/my-app/.production.env', 'utf-8')) - .toEqual(`dollar=\\$ -NX_SOME_VAR=\\$ABC`); - }); - - it('should not escape $ env variables if it is already escaped', () => { - addProjectConfiguration(tree, 'my-app', { - root: 'apps/my-app', - }); - tree.write( - 'apps/my-app/.env', - `dollar=\\$ -NX_SOME_VAR=\\$ABC` - ); - escapeDollarSignEnvVariables(tree); - expect(tree.read('apps/my-app/.env', 'utf-8')).toEqual(`dollar=\\$ -NX_SOME_VAR=\\$ABC`); - }); -}); diff --git a/packages/nx/src/migrations/update-16-8-0/escape-dollar-sign-env-variables.ts b/packages/nx/src/migrations/update-16-8-0/escape-dollar-sign-env-variables.ts deleted file mode 100644 index 279c5605d4efb4..00000000000000 --- a/packages/nx/src/migrations/update-16-8-0/escape-dollar-sign-env-variables.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { logger } from '../../utils/logger'; -import { Tree } from '../../generators/tree'; -import { getProjects } from '../../generators/utils/project-configuration'; - -/** - * This function escapes dollar sign in env variables - * It will go through: - * - '.env', '.local.env', '.env.local' - * - .env.[target-name], .[target-name].env - * - .env.[target-name].[configuration-name], .[target-name].[configuration-name].env - * - .env.[configuration-name], .[configuration-name].env - * at each project root and workspace root - * @param tree - */ -export default function escapeDollarSignEnvVariables(tree: Tree) { - const envFiles = ['.env', '.local.env', '.env.local']; - for (const [_, configuration] of getProjects(tree).entries()) { - envFiles.push( - `${configuration.root}/.env`, - `${configuration.root}/.local.env`, - `${configuration.root}/.env.local` - ); - for (const targetName in configuration.targets) { - const task = configuration.targets[targetName]; - envFiles.push( - `.env.${targetName}`, - `.${targetName}.env`, - `${configuration.root}/.env.${targetName}`, - `${configuration.root}/.${targetName}.env` - ); - - if (task.configurations) { - for (const configurationName in task.configurations) { - envFiles.push( - `.env.${targetName}.${configurationName}`, - `.${targetName}.${configurationName}.env`, - `.env.${configurationName}`, - `.${configurationName}.env`, - `${configuration.root}/.env.${targetName}.${configurationName}`, - `${configuration.root}/.${targetName}.${configurationName}.env`, - `${configuration.root}/.env.${configurationName}`, - `${configuration.root}/.${configurationName}.env` - ); - } - } - } - } - for (const envFile of new Set(envFiles)) { - parseEnvFile(tree, envFile); - } -} - -/** - * This function parse the env file and escape dollar sign - * @param tree - * @param envFilePath - * @returns - */ -function parseEnvFile(tree: Tree, envFilePath: string) { - if (!tree.exists(envFilePath)) { - return; - } - - let envFileContent = tree.read(envFilePath, 'utf-8'); - if (!envFileContent) { - // envFileContent is null if we fail to read the file for any reason - // e.g. the file is not utf-8 encoded - logger.info( - `Unable to update ${envFilePath}. Nx interpolates environment variables in the form of $VAR_NAME. To escape the dollar sign, use \\$VAR_NAME.` - ); - return; - } - - envFileContent = envFileContent - .split('\n') - .map((line) => { - line = line.trim(); - - if (!line || !line.includes('$')) { - return line; - } - - const declarations = line.split('='); - if (declarations[1].includes('$') && !declarations[1].includes(`\\$`)) { - declarations[1] = declarations[1].replace('$', `\\$`); - line = declarations.join('='); - } - return line; - }) - .join('\n'); - tree.write(envFilePath, envFileContent); -} diff --git a/packages/nx/src/nx-cloud/utilities/axios.ts b/packages/nx/src/nx-cloud/utilities/axios.ts index 7954ca282235d2..ae8d31b539399a 100644 --- a/packages/nx/src/nx-cloud/utilities/axios.ts +++ b/packages/nx/src/nx-cloud/utilities/axios.ts @@ -1,4 +1,4 @@ -import { AxiosRequestConfig } from 'axios'; +import type { AxiosRequestConfig } from 'axios'; import { join } from 'path'; import { ACCESS_TOKEN, @@ -7,8 +7,6 @@ import { } from './environment'; import { CloudTaskRunnerOptions } from '../nx-cloud-tasks-runner-shell'; -const axios = require('axios'); - export function createApiAxiosInstance(options: CloudTaskRunnerOptions) { let axiosConfigBuilder = (axiosConfig: AxiosRequestConfig) => axiosConfig; const baseUrl = @@ -31,7 +29,7 @@ export function createApiAxiosInstance(options: CloudTaskRunnerOptions) { axiosConfigBuilder = nxCloudProxyConfig ?? axiosConfigBuilder; } - return axios.create( + return require('axios').create( axiosConfigBuilder({ baseURL: baseUrl, timeout: NX_CLOUD_NO_TIMEOUTS ? UNLIMITED_TIMEOUT : 10000, diff --git a/packages/nx/src/nx-cloud/utilities/onboarding.ts b/packages/nx/src/nx-cloud/utilities/onboarding.ts index 114202a3b91462..30c9ed8f75ddad 100644 --- a/packages/nx/src/nx-cloud/utilities/onboarding.ts +++ b/packages/nx/src/nx-cloud/utilities/onboarding.ts @@ -1,9 +1,9 @@ -import { readNxJson } from '../../devkit-exports'; import type { Tree } from '../../generators/tree'; import { NxCloudOnBoardingStatus } from '../models/onboarding-status'; import { isWorkspaceClaimed } from './is-workspace-claimed'; import { createNxCloudOnboardingURL } from './url-shorten'; import { getRunnerOptions } from '../../tasks-runner/run-command'; +import { readNxJson } from '../../generators/utils/nx-json'; export async function createNxCloudOnboardingURLForWelcomeApp( tree: Tree, diff --git a/packages/nx/src/nx-cloud/utilities/url-shorten.ts b/packages/nx/src/nx-cloud/utilities/url-shorten.ts index fac7532ee54329..ffb698a3aee278 100644 --- a/packages/nx/src/nx-cloud/utilities/url-shorten.ts +++ b/packages/nx/src/nx-cloud/utilities/url-shorten.ts @@ -1,4 +1,4 @@ -import { logger } from '../../devkit-exports'; +import { logger } from '../../utils/logger'; import { getGithubSlugOrNull } from '../../utils/git-utils'; import { getCloudUrl } from './get-cloud-options'; diff --git a/packages/nx/src/project-graph/file-utils.ts b/packages/nx/src/project-graph/file-utils.ts index 6f609ae6f22e7b..a907464672ebf3 100644 --- a/packages/nx/src/project-graph/file-utils.ts +++ b/packages/nx/src/project-graph/file-utils.ts @@ -28,7 +28,7 @@ import { import { globWithWorkspaceContextSync } from '../utils/workspace-context'; import { buildProjectFromProjectJson } from '../plugins/project-json/build-nodes/project-json'; import { PackageJson } from '../utils/package-json'; -import { NxJsonConfiguration } from '../devkit-exports'; +import { NxJsonConfiguration } from '../config/nx-json'; export interface Change { type: string; @@ -135,8 +135,8 @@ function defaultReadFileAtRevision( } /** - * TODO(v20): Remove this function - * @deprecated To get projects use {@link retrieveProjectConfigurations} instead. This will be removed in v20. + * TODO(v21): Remove this function + * @deprecated To get projects use {@link retrieveProjectConfigurations} instead. This will be removed in v21. */ export function readWorkspaceConfig(opts: { format: 'angularCli' | 'nx'; diff --git a/packages/nx/src/tasks-runner/cache.ts b/packages/nx/src/tasks-runner/cache.ts index 3416e555b817b7..33882bcb210d9a 100644 --- a/packages/nx/src/tasks-runner/cache.ts +++ b/packages/nx/src/tasks-runner/cache.ts @@ -29,17 +29,14 @@ export type CachedResult = { }; export type TaskWithCachedResult = { task: Task; cachedResult: CachedResult }; -export function getCache( - nxJson: NxJsonConfiguration, - options: DefaultTasksRunnerOptions -): DbCache | Cache { +// Do not change the order of these arguments as this function is used by nx cloud +export function getCache(options: DefaultTasksRunnerOptions): DbCache | Cache { + const nxJson = readNxJson(); return process.env.NX_DISABLE_DB !== 'true' && (nxJson.enableDbCache === true || process.env.NX_DB_CACHE === 'true') ? new DbCache({ // Remove this in Nx 21 - nxCloudRemoteCache: isNxCloudUsed(readNxJson()) - ? options.remoteCache - : null, + nxCloudRemoteCache: isNxCloudUsed(nxJson) ? options.remoteCache : null, }) : new Cache(options); } diff --git a/packages/nx/src/tasks-runner/create-task-graph.spec.ts b/packages/nx/src/tasks-runner/create-task-graph.spec.ts index 6b26c3a93d9645..76b9e714259387 100644 --- a/packages/nx/src/tasks-runner/create-task-graph.spec.ts +++ b/packages/nx/src/tasks-runner/create-task-graph.spec.ts @@ -1235,7 +1235,482 @@ describe('createTaskGraph', () => { }); }); - it('should handle cycles between projects (app1:build <-> app2 <-> app3:build)', () => { + it('should handle cycles between projects where all projects contain the same task target (lib1:build -> lib2:build -> lib3:build -> lib4:build -> lib1:build)', () => { + projectGraph = { + nodes: { + lib1: { + name: 'lib1', + type: 'lib', + data: { + root: 'lib1-root', + targets: { + build: { + executor: 'nx:run-commands', + }, + }, + }, + }, + lib2: { + name: 'lib2', + type: 'lib', + data: { + root: 'lib2-root', + targets: { + build: { + executor: 'nx:run-commands', + }, + }, + }, + }, + lib3: { + name: 'lib3', + type: 'lib', + data: { + root: 'lib3-root', + targets: { + build: { + executor: 'nx:run-commands', + }, + }, + }, + }, + lib4: { + name: 'lib4', + type: 'lib', + data: { + root: 'lib4-root', + targets: { + build: { + executor: 'nx:run-commands', + }, + }, + }, + }, + }, + dependencies: { + lib1: [{ source: 'lib1', target: 'lib2', type: 'static' }], + lib2: [{ source: 'lib2', target: 'lib3', type: 'static' }], + lib3: [{ source: 'lib3', target: 'lib4', type: 'static' }], + lib4: [{ source: 'lib4', target: 'lib1', type: 'static' }], + }, + }; + + const taskGraph = createTaskGraph( + projectGraph, + { + build: [{ target: 'build', dependencies: true }], + }, + ['lib1'], + ['build'], + 'development', + { + __overrides_unparsed__: [], + } + ); + expect(taskGraph).toEqual({ + roots: [], + tasks: { + 'lib1:build': expect.objectContaining({ + id: 'lib1:build', + target: { + project: 'lib1', + target: 'build', + }, + outputs: expect.arrayContaining([expect.any(String)]), + overrides: { + __overrides_unparsed__: [], + }, + projectRoot: 'lib1-root', + parallelism: true, + }), + 'lib2:build': expect.objectContaining({ + id: 'lib2:build', + target: { + project: 'lib2', + target: 'build', + }, + outputs: expect.arrayContaining([expect.any(String)]), + overrides: { + __overrides_unparsed__: [], + }, + projectRoot: 'lib2-root', + parallelism: true, + }), + 'lib3:build': expect.objectContaining({ + id: 'lib3:build', + target: { + project: 'lib3', + target: 'build', + }, + outputs: expect.arrayContaining([expect.any(String)]), + overrides: { + __overrides_unparsed__: [], + }, + projectRoot: 'lib3-root', + parallelism: true, + }), + 'lib4:build': expect.objectContaining({ + id: 'lib4:build', + target: { + project: 'lib4', + target: 'build', + }, + outputs: expect.arrayContaining([expect.any(String)]), + overrides: { + __overrides_unparsed__: [], + }, + projectRoot: 'lib4-root', + parallelism: true, + }), + }, + dependencies: { + 'lib1:build': ['lib2:build'], + 'lib2:build': ['lib3:build'], + 'lib3:build': ['lib4:build'], + 'lib4:build': ['lib1:build'], + }, + }); + }); + + it('should handle cycles between projects where all projects do not contain the same task target (lib1:build -> lib2:build -> lib3 -> lib4:build)', () => { + projectGraph = { + nodes: { + lib1: { + name: 'lib1', + type: 'lib', + data: { + root: 'lib1-root', + targets: { + build: { + executor: 'nx:run-commands', + }, + }, + }, + }, + lib2: { + name: 'lib2', + type: 'lib', + data: { + root: 'lib2-root', + targets: { + build: { + executor: 'nx:run-commands', + }, + }, + }, + }, + lib3: { + name: 'lib3', + type: 'lib', + data: { + root: 'lib3-root', + targets: {}, + }, + }, + lib4: { + name: 'lib4', + type: 'lib', + data: { + root: 'lib4-root', + targets: { + build: { + executor: 'nx:run-commands', + }, + }, + }, + }, + }, + dependencies: { + lib1: [{ source: 'lib1', target: 'lib2', type: 'static' }], + lib2: [{ source: 'lib2', target: 'lib3', type: 'static' }], + lib3: [{ source: 'lib3', target: 'lib4', type: 'static' }], + }, + }; + + const taskGraph = createTaskGraph( + projectGraph, + { + build: [{ target: 'build', dependencies: true }], + }, + ['lib1'], + ['build'], + 'development', + { + __overrides_unparsed__: [], + } + ); + expect(taskGraph).toEqual({ + roots: ['lib4:build'], + tasks: { + 'lib1:build': expect.objectContaining({ + id: 'lib1:build', + target: { + project: 'lib1', + target: 'build', + }, + outputs: expect.arrayContaining([expect.any(String)]), + overrides: { + __overrides_unparsed__: [], + }, + projectRoot: 'lib1-root', + parallelism: true, + }), + 'lib2:build': expect.objectContaining({ + id: 'lib2:build', + target: { + project: 'lib2', + target: 'build', + }, + outputs: expect.arrayContaining([expect.any(String)]), + overrides: { + __overrides_unparsed__: [], + }, + projectRoot: 'lib2-root', + parallelism: true, + }), + 'lib4:build': expect.objectContaining({ + id: 'lib4:build', + target: { + project: 'lib4', + target: 'build', + }, + outputs: expect.arrayContaining([expect.any(String)]), + overrides: { + __overrides_unparsed__: [], + }, + projectRoot: 'lib4-root', + parallelism: true, + }), + }, + dependencies: { + 'lib1:build': ['lib2:build'], + 'lib2:build': ['lib4:build'], + 'lib4:build': [], + }, + }); + }); + + it('should handle cycles between projects where all projects do not contain the same task target (lib1:build -> lib2:build -> lib3 -> lib4:build -> lib1:build)', () => { + projectGraph = { + nodes: { + lib1: { + name: 'lib1', + type: 'lib', + data: { + root: 'lib1-root', + targets: { + build: { + executor: 'nx:run-commands', + }, + }, + }, + }, + lib2: { + name: 'lib2', + type: 'lib', + data: { + root: 'lib2-root', + targets: { + build: { + executor: 'nx:run-commands', + }, + }, + }, + }, + lib3: { + name: 'lib3', + type: 'lib', + data: { + root: 'lib3-root', + targets: {}, + }, + }, + lib4: { + name: 'lib4', + type: 'lib', + data: { + root: 'lib4-root', + targets: { + build: { + executor: 'nx:run-commands', + }, + }, + }, + }, + }, + dependencies: { + lib1: [{ source: 'lib1', target: 'lib2', type: 'static' }], + lib2: [{ source: 'lib2', target: 'lib3', type: 'static' }], + lib3: [{ source: 'lib3', target: 'lib4', type: 'static' }], + lib4: [{ source: 'lib4', target: 'lib1', type: 'static' }], + }, + }; + + const taskGraph = createTaskGraph( + projectGraph, + { + build: [{ target: 'build', dependencies: true }], + }, + ['lib1'], + ['build'], + 'development', + { + __overrides_unparsed__: [], + } + ); + expect(taskGraph).toEqual({ + roots: [], + tasks: { + 'lib1:build': expect.objectContaining({ + id: 'lib1:build', + target: { + project: 'lib1', + target: 'build', + }, + outputs: expect.arrayContaining([expect.any(String)]), + overrides: { + __overrides_unparsed__: [], + }, + projectRoot: 'lib1-root', + parallelism: true, + }), + 'lib2:build': expect.objectContaining({ + id: 'lib2:build', + target: { + project: 'lib2', + target: 'build', + }, + outputs: expect.arrayContaining([expect.any(String)]), + overrides: { + __overrides_unparsed__: [], + }, + projectRoot: 'lib2-root', + parallelism: true, + }), + 'lib4:build': expect.objectContaining({ + id: 'lib4:build', + target: { + project: 'lib4', + target: 'build', + }, + outputs: expect.arrayContaining([expect.any(String)]), + overrides: { + __overrides_unparsed__: [], + }, + projectRoot: 'lib4-root', + parallelism: true, + }), + }, + dependencies: { + 'lib1:build': ['lib2:build'], + 'lib2:build': ['lib4:build'], + 'lib4:build': ['lib1:build'], + }, + }); + }); + + it('should handle cycles between projects where all projects do not contain the same task target (lib1:build -> lib2:build -> lib3 -> lib4 -> lib1:build)', () => { + projectGraph = { + nodes: { + lib1: { + name: 'lib1', + type: 'lib', + data: { + root: 'lib1-root', + targets: { + build: { + executor: 'nx:run-commands', + }, + }, + }, + }, + lib2: { + name: 'lib2', + type: 'lib', + data: { + root: 'lib2-root', + targets: { + build: { + executor: 'nx:run-commands', + }, + }, + }, + }, + lib3: { + name: 'lib3', + type: 'lib', + data: { + root: 'lib3-root', + targets: {}, + }, + }, + lib4: { + name: 'lib4', + type: 'lib', + data: { + root: 'lib4-root', + targets: {}, + }, + }, + }, + dependencies: { + lib1: [{ source: 'lib1', target: 'lib2', type: 'static' }], + lib2: [{ source: 'lib2', target: 'lib3', type: 'static' }], + lib3: [{ source: 'lib3', target: 'lib4', type: 'static' }], + lib4: [{ source: 'lib4', target: 'lib1', type: 'static' }], + }, + }; + + const taskGraph = createTaskGraph( + projectGraph, + { + build: [{ target: 'build', dependencies: true }], + }, + ['lib1'], + ['build'], + 'development', + { + __overrides_unparsed__: [], + } + ); + expect(taskGraph).toEqual({ + roots: ['lib2:build'], + tasks: { + 'lib1:build': expect.objectContaining({ + id: 'lib1:build', + target: { + project: 'lib1', + target: 'build', + }, + outputs: expect.arrayContaining([expect.any(String)]), + overrides: { + __overrides_unparsed__: [], + }, + projectRoot: 'lib1-root', + parallelism: true, + }), + 'lib2:build': expect.objectContaining({ + id: 'lib2:build', + target: { + project: 'lib2', + target: 'build', + }, + outputs: expect.arrayContaining([expect.any(String)]), + overrides: { + __overrides_unparsed__: [], + }, + projectRoot: 'lib2-root', + parallelism: true, + }), + }, + dependencies: { + 'lib1:build': ['lib2:build'], + 'lib2:build': [], + }, + }); + }); + + it('should handle cycles between projects where all projects do not contain the same task target (app1:build <-> app2 <-> app3:build)', () => { projectGraph = { nodes: { app1: { @@ -1294,7 +1769,7 @@ describe('createTaskGraph', () => { } ); expect(taskGraph).toEqual({ - roots: [], + roots: ['app1:compile', 'app3:compile'], tasks: { 'app1:compile': { id: 'app1:compile', @@ -1324,13 +1799,13 @@ describe('createTaskGraph', () => { }, }, dependencies: { - 'app1:compile': ['app3:compile'], - 'app3:compile': ['app1:compile'], + 'app1:compile': [], + 'app3:compile': [], }, }); }); - it('should handle cycles between projects that do not create cycles between tasks (app1:build -> app2 <-> app3:build)``', () => { + it('should handle cycles between projects that do not create cycles between tasks and not contain the same task target (app1:build -> app2 <-> app3:build)``', () => { projectGraph = { nodes: { app1: { @@ -1386,7 +1861,7 @@ describe('createTaskGraph', () => { } ); expect(taskGraph).toEqual({ - roots: ['app3:compile'], + roots: ['app1:compile', 'app3:compile'], tasks: { 'app1:compile': { id: 'app1:compile', @@ -1416,7 +1891,7 @@ describe('createTaskGraph', () => { }, }, dependencies: { - 'app1:compile': ['app3:compile'], + 'app1:compile': [], 'app3:compile': [], }, }); diff --git a/packages/nx/src/tasks-runner/create-task-graph.ts b/packages/nx/src/tasks-runner/create-task-graph.ts index 909fc411beba16..5c128af4e49801 100644 --- a/packages/nx/src/tasks-runner/create-task-graph.ts +++ b/packages/nx/src/tasks-runner/create-task-graph.ts @@ -6,8 +6,10 @@ import { } from '../utils/project-graph-utils'; import { Task, TaskGraph } from '../config/task-graph'; import { TargetDefaults, TargetDependencies } from '../config/nx-json'; -import { TargetDependencyConfig } from '../devkit-exports'; import { output } from '../utils/output'; +import { TargetDependencyConfig } from '../config/workspace-json-project-json'; + +const DUMMY_TASK_TARGET = '__nx_dummy_task__'; export class ProcessTasks { private readonly seen = new Set(); @@ -81,6 +83,8 @@ export class ProcessTasks { } } + this.filterDummyTasks(); + for (const projectName of Object.keys(this.dependencies)) { if (this.dependencies[projectName].length > 1) { this.dependencies[projectName] = [ @@ -228,6 +232,14 @@ export class ProcessTasks { taskOverrides: Object | { __overrides_unparsed__: any[] }, overrides: Object ) { + if ( + !this.projectGraph.dependencies.hasOwnProperty( + projectUsedToDeriveDependencies + ) + ) { + return; + } + for (const dep of this.projectGraph.dependencies[ projectUsedToDeriveDependencies ]) { @@ -272,11 +284,26 @@ export class ProcessTasks { ); } } else { - this.processTask(task, depProject.name, configuration, overrides); + const dummyId = this.getId( + depProject.name, + DUMMY_TASK_TARGET, + undefined + ); + this.dependencies[task.id].push(dummyId); + this.dependencies[dummyId] = []; + const noopTask = this.createDummyTask(dummyId, task); + this.processTask(noopTask, depProject.name, configuration, overrides); } } } + private createDummyTask(id: string, task: Task): Task { + return { + ...task, + id, + }; + } + createTask( id: string, project: ProjectGraphProjectNode, @@ -347,6 +374,31 @@ export class ProcessTasks { } return id; } + + private filterDummyTasks() { + for (const [key, deps] of Object.entries(this.dependencies)) { + const normalizedDeps = []; + for (const dep of deps) { + if (dep.endsWith(DUMMY_TASK_TARGET)) { + normalizedDeps.push( + ...this.dependencies[dep].filter( + (d) => !d.endsWith(DUMMY_TASK_TARGET) + ) + ); + } else { + normalizedDeps.push(dep); + } + } + + this.dependencies[key] = normalizedDeps; + } + + for (const key of Object.keys(this.dependencies)) { + if (key.endsWith(DUMMY_TASK_TARGET)) { + delete this.dependencies[key]; + } + } + } } export function createTaskGraph( @@ -366,6 +418,7 @@ export function createTaskGraph( overrides, excludeTaskDependencies ); + return { roots, tasks: p.tasks, diff --git a/packages/nx/src/tasks-runner/task-orchestrator.ts b/packages/nx/src/tasks-runner/task-orchestrator.ts index 9910009cc086ad..76b1114590ab07 100644 --- a/packages/nx/src/tasks-runner/task-orchestrator.ts +++ b/packages/nx/src/tasks-runner/task-orchestrator.ts @@ -36,7 +36,7 @@ import type { TaskDetails } from '../native'; export class TaskOrchestrator { private taskDetails: TaskDetails | null = getTaskDetails(); - private cache: DbCache | Cache = getCache(this.nxJson, this.options); + private cache: DbCache | Cache = getCache(this.options); private forkedProcessTaskRunner = new ForkedProcessTaskRunner(this.options); private tasksSchedule = new TasksSchedule( diff --git a/packages/nx/src/utils/git-utils.ts b/packages/nx/src/utils/git-utils.ts index fe457e939f33cd..1a931f45d3840a 100644 --- a/packages/nx/src/utils/git-utils.ts +++ b/packages/nx/src/utils/git-utils.ts @@ -1,6 +1,6 @@ import { exec, ExecOptions, execSync } from 'child_process'; import { dirname, join, posix, sep } from 'path'; -import { logger } from '../devkit-exports'; +import { logger } from './logger'; function execAsync(command: string, execOptions: ExecOptions) { return new Promise((res, rej) => { diff --git a/packages/playwright/src/generators/configuration/configuration.ts b/packages/playwright/src/generators/configuration/configuration.ts index d884e0606714ef..bfd2c2ce3d8658 100644 --- a/packages/playwright/src/generators/configuration/configuration.ts +++ b/packages/playwright/src/generators/configuration/configuration.ts @@ -20,6 +20,7 @@ import { writeJson, } from '@nx/devkit'; import { getRelativePathToRootTsConfig } from '@nx/js'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { typescriptVersion } from '@nx/js/src/utils/versions'; import { execSync } from 'child_process'; import * as path from 'path'; @@ -39,6 +40,8 @@ export async function configurationGeneratorInternal( tree: Tree, options: ConfigurationGeneratorSchema ) { + assertNotUsingTsSolutionSetup(tree, 'playwright', 'configuration'); + const nxJson = readNxJson(tree); options.addPlugin ??= process.env.NX_ADD_PLUGINS !== 'false' && diff --git a/packages/playwright/src/generators/init/init.ts b/packages/playwright/src/generators/init/init.ts index 493b4295e2ba73..5d2fb930e2cc16 100644 --- a/packages/playwright/src/generators/init/init.ts +++ b/packages/playwright/src/generators/init/init.ts @@ -8,6 +8,7 @@ import { Tree, } from '@nx/devkit'; import { addPlugin } from '@nx/devkit/src/utils/add-plugin'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { createNodesV2 } from '../../plugins/plugin'; import { nxVersion, playwrightVersion } from '../../utils/versions'; import { InitGeneratorSchema } from './schema'; @@ -20,6 +21,8 @@ export async function initGeneratorInternal( tree: Tree, options: InitGeneratorSchema ) { + assertNotUsingTsSolutionSetup(tree, 'playwright', 'init'); + const tasks: GeneratorCallback[] = []; const nxJson = readNxJson(tree); diff --git a/packages/plugin/migrations.json b/packages/plugin/migrations.json index 38263a21f0a9bf..65a4590b7c5522 100644 --- a/packages/plugin/migrations.json +++ b/packages/plugin/migrations.json @@ -1,22 +1,3 @@ { - "generators": { - "update-remove-cli-prop": { - "version": "16.0.0-beta.1", - "cli": "nx", - "description": "Removes CLI property within schema.json files and moves generators and schematics to the proper root node in migrations.json", - "factory": "./src/migrations/update-16-0-0/cli-in-schema-json" - }, - "update-16-0-0-add-nx-packages": { - "cli": "nx", - "version": "16.0.0-beta.1", - "description": "Replace @nrwl/nx-plugin with @nx/plugin", - "implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages" - }, - "update-16-2-0-replace-e2e-executor": { - "cli": "nx", - "version": "16.2.0-beta.0", - "description": "Replace @nx/plugin:e2e with @nx/jest", - "implementation": "./src/migrations/update-16-2-0/replace-e2e-executor" - } - } + "generators": {} } diff --git a/packages/plugin/src/generators/create-package/create-package.ts b/packages/plugin/src/generators/create-package/create-package.ts index f9a7c649c49935..ac82acfcb3ab00 100644 --- a/packages/plugin/src/generators/create-package/create-package.ts +++ b/packages/plugin/src/generators/create-package/create-package.ts @@ -14,6 +14,7 @@ import { } from '@nx/devkit'; import { libraryGenerator as jsLibraryGenerator } from '@nx/js'; import { addTsLibDependencies } from '@nx/js/src/utils/typescript/add-tslib-dependencies'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { nxVersion } from 'nx/src/utils/versions'; import generatorGenerator from '../generator/generator'; import { CreatePackageSchema } from './schema'; @@ -26,6 +27,8 @@ export async function createPackageGenerator( host: Tree, schema: CreatePackageSchema ) { + assertNotUsingTsSolutionSetup(host, 'plugin', 'create-package'); + const tasks: GeneratorCallback[] = []; const options = await normalizeSchema(host, schema); diff --git a/packages/plugin/src/generators/e2e-project/e2e.ts b/packages/plugin/src/generators/e2e-project/e2e.ts index 6979c7b8c36f65..43fc8f71e7cf52 100644 --- a/packages/plugin/src/generators/e2e-project/e2e.ts +++ b/packages/plugin/src/generators/e2e-project/e2e.ts @@ -21,6 +21,7 @@ import { addPropertyToJestConfig, configurationGenerator } from '@nx/jest'; import { getRelativePathToRootTsConfig } from '@nx/js'; import { setupVerdaccio } from '@nx/js/src/generators/setup-verdaccio/generator'; import { addLocalRegistryScripts } from '@nx/js/src/utils/add-local-registry-scripts'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { Linter, LinterType, lintProjectGenerator } from '@nx/eslint'; import { join } from 'path'; import type { Schema } from './schema'; @@ -176,6 +177,8 @@ export async function e2eProjectGenerator(host: Tree, schema: Schema) { } export async function e2eProjectGeneratorInternal(host: Tree, schema: Schema) { + assertNotUsingTsSolutionSetup(host, 'plugin', 'e2e-project'); + const tasks: GeneratorCallback[] = []; validatePlugin(host, schema.pluginName); diff --git a/packages/plugin/src/generators/plugin/plugin.ts b/packages/plugin/src/generators/plugin/plugin.ts index c5a561226a8f2d..06deba1cbeff67 100644 --- a/packages/plugin/src/generators/plugin/plugin.ts +++ b/packages/plugin/src/generators/plugin/plugin.ts @@ -12,6 +12,7 @@ import { } from '@nx/devkit'; import { libraryGenerator as jsLibraryGenerator } from '@nx/js'; import { addSwcDependencies } from '@nx/js/src/utils/swc/add-swc-dependencies'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { Linter } from '@nx/eslint'; import * as path from 'path'; import { e2eProjectGenerator } from '../e2e-project/e2e'; @@ -74,6 +75,8 @@ function updatePluginConfig(host: Tree, options: NormalizedSchema) { } export async function pluginGenerator(host: Tree, schema: Schema) { + assertNotUsingTsSolutionSetup(host, 'plugin', 'plugin'); + const options = await normalizeOptions(host, schema); const tasks: GeneratorCallback[] = []; diff --git a/packages/plugin/src/generators/preset/generator.ts b/packages/plugin/src/generators/preset/generator.ts index e42d1a7126a984..58f64ac4a40415 100644 --- a/packages/plugin/src/generators/preset/generator.ts +++ b/packages/plugin/src/generators/preset/generator.ts @@ -7,12 +7,15 @@ import { updateJson, } from '@nx/devkit'; import { Linter } from '@nx/eslint'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { PackageJson } from 'nx/src/utils/package-json'; import { pluginGenerator } from '../plugin/plugin'; import { PresetGeneratorSchema } from './schema'; import createPackageGenerator from '../create-package/create-package'; export default async function (tree: Tree, options: PresetGeneratorSchema) { + assertNotUsingTsSolutionSetup(tree, 'plugin', 'preset'); + const tasks: GeneratorCallback[] = []; const pluginProjectName = names( options.pluginName.includes('/') diff --git a/packages/plugin/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts b/packages/plugin/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts deleted file mode 100644 index d4fe58f7db0d7a..00000000000000 --- a/packages/plugin/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Tree, readJson, updateJson } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import { assertRunsAgainstNxRepo } from '@nx/devkit/internal-testing-utils'; -import replacePackage from './update-16-0-0-add-nx-packages'; - -describe('update-16-0-0-add-nx-packages', () => { - let tree: Tree; - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - - updateJson(tree, 'package.json', (json) => { - json.devDependencies['@nrwl/nx-plugin'] = '16.0.0'; - return json; - }); - }); - - it('should remove the dependency on @nrwl/nx-plugin', async () => { - await replacePackage(tree); - - expect( - readJson(tree, 'package.json').dependencies['@nrwl/nx-plugin'] - ).not.toBeDefined(); - expect( - readJson(tree, 'package.json').devDependencies['@nrwl/nx-plugin'] - ).not.toBeDefined(); - }); - - it('should add a dependency on @nx/plugin', async () => { - await replacePackage(tree); - - const packageJson = readJson(tree, 'package.json'); - const newDependencyVersion = - packageJson.devDependencies['@nx/plugin'] ?? - packageJson.dependencies['@nx/plugin']; - - expect(newDependencyVersion).toBeDefined(); - }); - - assertRunsAgainstNxRepo(replacePackage); -}); diff --git a/packages/plugin/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts b/packages/plugin/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts deleted file mode 100644 index 2ea9737e96332e..00000000000000 --- a/packages/plugin/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Tree, formatFiles } from '@nx/devkit'; -import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package'; - -export default async function replacePackage(tree: Tree): Promise { - await replaceNrwlPackageWithNxPackage(tree, '@nrwl/nx-plugin', '@nx/plugin'); - - await formatFiles(tree); -} diff --git a/packages/plugin/src/migrations/update-16-0-0/cli-in-schema-json.spec.ts b/packages/plugin/src/migrations/update-16-0-0/cli-in-schema-json.spec.ts deleted file mode 100644 index e3f821bb3d0faf..00000000000000 --- a/packages/plugin/src/migrations/update-16-0-0/cli-in-schema-json.spec.ts +++ /dev/null @@ -1,281 +0,0 @@ -import 'nx/src/internal-testing-utils/mock-project-graph'; - -import { - ExecutorsJson, - GeneratorsJson, - joinPathFragments, - MigrationsJson, - readJson, - readProjectConfiguration, - Tree, - updateJson, - writeJson, -} from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import { Linter } from '@nx/eslint'; -import { assertRunsAgainstNxRepo } from '@nx/devkit/internal-testing-utils'; -import { PackageJson } from 'nx/src/utils/package-json'; -import executorGenerator from '../../generators/executor/executor'; -import generatorGenerator from '../../generators/generator/generator'; -import pluginGenerator from '../../generators/plugin/plugin'; -import { updateCliPropsForPlugins } from './cli-in-schema-json'; - -describe('updateCliPropsForPlugins', () => { - let originalEnv: string; - beforeEach(() => { - originalEnv = process.env.NX_ADD_PLUGINS; - process.env.NX_ADD_PLUGINS = 'false'; - }); - - afterAll(() => { - process.env.NX_ADD_PLUGINS = originalEnv; - }); - - it('should move non-nx generators to schematics for migrations.json', async () => { - const tree = createTreeWithEmptyWorkspace(); - const { root } = await createPlugin(tree); - updatePluginPackageJson(tree, { - 'nx-migrations': 'migrations.json', - }); - writeJson( - tree, - joinPathFragments(root, 'migrations.json'), - { - version: '1.0.0', - generators: { - 'migration-1': { - version: '1.0.0', - description: 'My Plugin 1', - factory: './migrations/my-plugin-1', - }, - }, - } - ); - await updateCliPropsForPlugins(tree); - const updated = readJson( - tree, - joinPathFragments(root, 'migrations.json') - ); - expect(updated.generators).not.toHaveProperty('migration-1'); - expect(updated.schematics).toHaveProperty('migration-1'); - }); - - it('should move nx generators to generators for migrations.json', async () => { - const tree = createTreeWithEmptyWorkspace(); - const { root } = await createPlugin(tree); - updatePluginPackageJson(tree, { - 'nx-migrations': 'migrations.json', - }); - writeJson( - tree, - joinPathFragments(root, 'migrations.json'), - { - version: '1.0.0', - schematics: { - 'migration-1': { - version: '1.0.0', - description: 'My Plugin 1', - factory: './migrations/my-plugin-1', - cli: 'nx', - }, - }, - } - ); - await updateCliPropsForPlugins(tree); - const updated = readJson( - tree, - joinPathFragments(root, 'migrations.json') - ); - expect(updated.schematics).not.toHaveProperty('migration-1'); - expect(updated.generators).toHaveProperty('migration-1'); - }); - - it('should move both nx generators to generators and non-nx schematics to schematics for migrations.json', async () => { - const tree = createTreeWithEmptyWorkspace(); - const { root } = await createPlugin(tree); - updatePluginPackageJson(tree, { - 'nx-migrations': 'migrations.json', - }); - writeJson( - tree, - joinPathFragments(root, 'migrations.json'), - { - version: '1.0.0', - schematics: { - 'migration-1': { - version: '1.0.0', - description: 'My Plugin 1', - factory: './migrations/my-plugin-1', - cli: 'nx', - }, - 'migration-2': { - version: '1.0.0', - description: 'My Plugin 2', - factory: './migrations/my-plugin-2', - }, - }, - generators: { - 'migration-3': { - version: '1.0.0', - description: 'My Plugin 3', - factory: './migrations/my-plugin-3', - cli: 'nx', - }, - 'migration-4': { - version: '1.0.0', - description: 'My Plugin 4', - factory: './migrations/my-plugin-4', - }, - }, - } - ); - await updateCliPropsForPlugins(tree); - const updated = readJson( - tree, - joinPathFragments(root, 'migrations.json') - ); - expect(updated.schematics).not.toHaveProperty('migration-1'); - expect(updated.generators).toHaveProperty('migration-1'); - expect(updated.schematics).toHaveProperty('migration-2'); - expect(updated.generators).not.toHaveProperty('migration-2'); - expect(updated.schematics).not.toHaveProperty('migration-3'); - expect(updated.generators).toHaveProperty('migration-3'); - expect(updated.schematics).toHaveProperty('migration-4'); - expect(updated.generators).not.toHaveProperty('migration-4'); - }); - - it('should remove cli property from executors', async () => { - const tree = createTreeWithEmptyWorkspace(); - const { root, name } = await createPlugin(tree); - await executorGenerator(tree, { - name: 'my-executor', - path: `${name}/src/executors/my-executor`, - unitTestRunner: 'jest', - includeHasher: false, - }); - const schemaPath = joinPathFragments( - root, - 'src/executors/my-executor/schema.json' - ); - updateJson(tree, schemaPath, (schema) => { - schema.cli = 'nx'; - return schema; - }); - await updateCliPropsForPlugins(tree); - const updated = readJson(tree, schemaPath); - expect(updated).not.toHaveProperty('cli'); - }); - - it('should remove cli property from builders', async () => { - const tree = createTreeWithEmptyWorkspace(); - const { root, name } = await createPlugin(tree); - await executorGenerator(tree, { - name: 'my-executor', - path: `${name}/src/executors/my-executor`, - unitTestRunner: 'jest', - includeHasher: false, - }); - updateJson( - tree, - joinPathFragments(root, 'executors.json'), - (json) => { - json.builders = json.executors; - delete json.builders; - return json; - } - ); - const schemaPath = joinPathFragments( - root, - 'src/executors/my-executor/schema.json' - ); - updateJson(tree, schemaPath, (schema) => { - schema.cli = 'nx'; - return schema; - }); - await updateCliPropsForPlugins(tree); - const updated = readJson(tree, schemaPath); - expect(updated).not.toHaveProperty('cli'); - }); - - it('should remove cli property from generators', async () => { - const tree = createTreeWithEmptyWorkspace(); - const { root, name } = await createPlugin(tree); - await generatorGenerator(tree, { - name: 'my-generator', - path: `${name}/src/generators/my-generator`, - unitTestRunner: 'jest', - }); - const schemaPath = joinPathFragments( - root, - 'src/generators/my-generator/schema.json' - ); - updateJson(tree, schemaPath, (schema) => { - schema.cli = 'nx'; - return schema; - }); - await updateCliPropsForPlugins(tree); - const updated = readJson(tree, schemaPath); - expect(updated).not.toHaveProperty('cli'); - }); - - it('should remove cli property from schematics', async () => { - const tree = createTreeWithEmptyWorkspace(); - const { root, name } = await createPlugin(tree); - await generatorGenerator(tree, { - name: 'my-schematic', - path: `${name}/src/generators/my-schematic`, - unitTestRunner: 'jest', - }); - updateJson( - tree, - joinPathFragments(root, 'generators.json'), - (json) => { - json.schematics = json.generators; - delete json.generators; - return json; - } - ); - const schemaPath = joinPathFragments( - root, - 'src/generators/my-schematic/schema.json' - ); - updateJson(tree, schemaPath, (schema) => { - schema.cli = 'nx'; - return schema; - }); - await updateCliPropsForPlugins(tree); - const updated = readJson(tree, schemaPath); - expect(updated).not.toHaveProperty('cli'); - }); - - assertRunsAgainstNxRepo(updateCliPropsForPlugins); -}); - -async function createPlugin(tree: Tree) { - await pluginGenerator(tree, { - directory: 'my-plugin', - compiler: 'tsc', - linter: Linter.EsLint, - unitTestRunner: 'jest', - skipFormat: true, - skipLintChecks: false, - skipTsConfig: false, - }); - return readProjectConfiguration(tree, 'my-plugin'); -} - -function updatePluginPackageJson( - tree: Tree, - packageJsonProps: Partial -) { - const { root } = readProjectConfiguration(tree, 'my-plugin'); - updateJson(tree, root + '/package.json', (json) => { - const base = { json, ...packageJsonProps }; - for (const prop in base) { - if (base[prop] === null || base[prop] === undefined) { - delete json[prop]; - } - } - return base; - }); -} diff --git a/packages/plugin/src/migrations/update-16-0-0/cli-in-schema-json.ts b/packages/plugin/src/migrations/update-16-0-0/cli-in-schema-json.ts deleted file mode 100644 index 3364aa74e79bfa..00000000000000 --- a/packages/plugin/src/migrations/update-16-0-0/cli-in-schema-json.ts +++ /dev/null @@ -1,177 +0,0 @@ -import { - GeneratorsJson, - getProjects, - joinPathFragments, - MigrationsJson, - ExecutorsJson, - readJson, - Tree, - updateJson, - output, -} from '@nx/devkit'; -import { - ExecutorsJsonEntry, - GeneratorsJsonEntry, -} from 'nx/src/config/misc-interfaces'; -import { PackageJson, readNxMigrateConfig } from 'nx/src/utils/package-json'; -import { dirname } from 'path'; - -export function updateCliPropsForPlugins(tree: Tree) { - const projects = getProjects(tree); - for (const project of projects.values()) { - if (tree.exists(joinPathFragments(project.root, 'package.json'))) { - const packageJson: PackageJson = readJson( - tree, - joinPathFragments(project.root, 'package.json') - ); - const migrateConfig = readNxMigrateConfig(packageJson); - if (migrateConfig.migrations) { - const migrationsPath = joinPathFragments( - project.root, - migrateConfig.migrations - ); - if (tree.exists(migrationsPath)) { - updateMigrationsJsonForPlugin(tree, migrationsPath); - } else { - output.warn({ - title: `Migrations file specified for ${packageJson.name} does not exist: ${migrationsPath}`, - bodyLines: [ - 'Please ensure that migrations that use the Angular Devkit are placed inside the `schematics` property, and migrations that use the Nx Devkit are placed inside the `generators` property.', - ], - }); - } - } - if (packageJson.generators) { - const generatorsPath = joinPathFragments( - project.root, - packageJson.generators - ); - if (tree.exists(generatorsPath)) { - removeCliFromGeneratorSchemaJsonFiles(tree, generatorsPath); - } else { - output.warn({ - title: `Generators file specified for ${packageJson.name} does not exist: ${generatorsPath}`, - bodyLines: [ - "The `cli` property inside generator's `schema.json` files is no longer supported.", - ], - }); - } - } - if (packageJson.executors) { - const executorsPath = joinPathFragments( - project.root, - packageJson.executors - ); - if (tree.exists(executorsPath)) { - removeCliFromExecutorSchemaJsonFiles(tree, executorsPath); - } else { - output.warn({ - title: `Executors file specified for ${packageJson.name} does not exist: ${executorsPath}`, - bodyLines: [ - "The `cli` property inside executor's `schema.json` files is no longer supported.", - ], - }); - } - } - if (packageJson.builders) { - const buildersPath = joinPathFragments( - project.root, - packageJson.builders - ); - if (tree.exists(buildersPath)) { - removeCliFromExecutorSchemaJsonFiles(tree, buildersPath); - } else { - output.warn({ - title: `Builders file specified for ${packageJson.name} does not exist: ${buildersPath}`, - bodyLines: [ - "The `cli` property inside builder's `schema.json` files is no longer supported.", - ], - }); - } - } - if (packageJson.schematics) { - const schematicsPath = joinPathFragments( - project.root, - packageJson.schematics - ); - if (tree.exists(schematicsPath)) { - removeCliFromGeneratorSchemaJsonFiles(tree, schematicsPath); - } else { - output.warn({ - title: `Schematics file specified for ${packageJson.name} does not exist: ${schematicsPath}`, - bodyLines: [ - "The `cli` property inside schematic's `schema.json` files is no longer supported.", - ], - }); - } - } - } - } -} - -function removeCliFromExecutorSchemaJsonFiles( - tree: Tree, - collectionPath: string -) { - const collection: ExecutorsJson = readJson(tree, collectionPath); - for (const [name, entry] of Object.entries(collection.executors ?? {}).concat( - Object.entries(collection.builders ?? {}) - )) { - deleteCliPropFromSchemaFile(collectionPath, entry, tree); - } -} - -function removeCliFromGeneratorSchemaJsonFiles( - tree: Tree, - collectionPath: string -) { - const collection: GeneratorsJson = readJson(tree, collectionPath); - for (const [name, entry] of Object.entries( - collection.generators ?? {} - ).concat(Object.entries(collection.schematics ?? {}))) { - deleteCliPropFromSchemaFile(collectionPath, entry, tree); - } -} - -function updateMigrationsJsonForPlugin(tree: Tree, collectionPath: string) { - updateJson(tree, collectionPath, (json) => { - for (const migration in json.generators ?? {}) { - if (!(json.generators[migration].cli === 'nx')) { - json.schematics ??= {}; - json.schematics[migration] = json.generators[migration]; - delete json.generators[migration]; - } - } - for (const migration in json.schematics ?? {}) { - if (json.schematics[migration].cli === 'nx') { - json.generators ??= {}; - json.generators[migration] = json.schematics[migration]; - delete json.schematics[migration]; - } - } - return json; - }); -} - -export default updateCliPropsForPlugins; - -function deleteCliPropFromSchemaFile( - collectionPath: string, - entry: ExecutorsJsonEntry | GeneratorsJsonEntry, - tree: Tree -) { - if (typeof entry === 'string' || !entry.schema) { - return; - } - const schemaPath = joinPathFragments(dirname(collectionPath), entry.schema); - if (tree.exists(schemaPath)) { - updateJson(tree, schemaPath, (json) => { - if (json.cli) { - delete json.cli; - } - return json; - }); - } else { - console.warn(`Could not find schema file ${schemaPath}`); - } -} diff --git a/packages/plugin/src/migrations/update-16-2-0/replace-e2e-executor.spec.ts b/packages/plugin/src/migrations/update-16-2-0/replace-e2e-executor.spec.ts deleted file mode 100644 index dad32acac23c84..00000000000000 --- a/packages/plugin/src/migrations/update-16-2-0/replace-e2e-executor.spec.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { - Tree, - readJson, - updateJson, - addProjectConfiguration, - readProjectConfiguration, -} from '@nx/devkit'; -import { assertRunsAgainstNxRepo } from '@nx/devkit/internal-testing-utils'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import replaceE2EExecutor from './replace-e2e-executor'; - -describe('update-16-0-0-add-nx-packages', () => { - let tree: Tree; - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - - addProjectConfiguration(tree, 'proj1', { - root: 'proj1', - targets: { - build: { - executor: '@nx/js:rollup', - }, - e2e: { - executor: '@nx/plugin:e2e', - options: { - target: 'proj1:build', - }, - configurations: { - ci: { - ci: true, - }, - }, - }, - }, - }); - }); - - it('should replace @nrwl/nx-plugin:e2e with @nx/jest:jest', async () => { - await replaceE2EExecutor(tree); - - expect(readProjectConfiguration(tree, 'proj1')).toMatchInlineSnapshot(` - { - "$schema": "../node_modules/nx/schemas/project-schema.json", - "name": "proj1", - "root": "proj1", - "targets": { - "build": { - "executor": "@nx/js:rollup", - }, - "e2e": { - "configurations": { - "ci": { - "ci": true, - "runInBand": true, - }, - }, - "dependsOn": [ - "proj1:build", - ], - "executor": "@nx/jest:jest", - "options": { - "runInBand": true, - }, - }, - }, - } - `); - }); - - assertRunsAgainstNxRepo(replaceE2EExecutor); -}); diff --git a/packages/plugin/src/migrations/update-16-2-0/replace-e2e-executor.ts b/packages/plugin/src/migrations/update-16-2-0/replace-e2e-executor.ts deleted file mode 100644 index 7a140369a7c3a1..00000000000000 --- a/packages/plugin/src/migrations/update-16-2-0/replace-e2e-executor.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { - Tree, - formatFiles, - getProjects, - updateProjectConfiguration, -} from '@nx/devkit'; -import { forEachExecutorOptions } from '@nx/devkit/src/generators/executor-options-utils'; -import { JestExecutorOptions } from '@nx/jest/src/executors/jest/schema'; - -export interface NxPluginE2EExecutorOptions extends JestExecutorOptions { - target: string; - jestConfig: string; -} - -export default async function replaceE2EExecutor(tree: Tree): Promise { - const projects = getProjects(tree); - for (const executor of ['@nx/plugin:e2e', '@nrwl/nx-plugin:e2e']) { - forEachExecutorOptions( - tree, - executor, - (options, project, target, configuration) => { - const projectConfiguration = projects.get(project); - - const config = { - ...options, - target: undefined, - runInBand: true, - }; - if (configuration) { - projectConfiguration.targets[target].configurations[configuration] = - config; - } else { - projectConfiguration.targets[target].dependsOn = [ - ...(projectConfiguration.targets[target].dependsOn ?? []), - options.target, - ]; - projectConfiguration.targets[target].executor = '@nx/jest:jest'; - projectConfiguration.targets[target].options = config; - } - - updateProjectConfiguration(tree, project, projectConfiguration); - } - ); - } - - await formatFiles(tree); -} diff --git a/packages/react-native/migrations.json b/packages/react-native/migrations.json index 35476cfed632dc..5b5d62a0500867 100644 --- a/packages/react-native/migrations.json +++ b/packages/react-native/migrations.json @@ -1,35 +1,5 @@ { "generators": { - "update-16-0-0-add-nx-packages": { - "cli": "nx", - "version": "16.0.0-beta.1", - "description": "Replace @nrwl/react-native with @nx/react-native", - "implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages" - }, - "update-16-1-0-upgrade-storybook-6-5": { - "cli": "nx", - "version": "16.1.0-beta.0", - "description": "Upgrade @storybook/react-native to 6.5", - "implementation": "./src/migrations/update-16-1-0/upgrade-storybook-6-5" - }, - "update-16-6-0-add-dependsOn": { - "cli": "nx", - "version": "16.6.0-beta.0", - "description": "Add dependsOn like ensure-symlink or sync-deps to targets", - "implementation": "./src/migrations/update-16-6-0/add-depends-on" - }, - "update-16-6-0-update-metro-config": { - "cli": "nx", - "version": "16.6.0-beta.0", - "description": "Update metro.config.js to use the new metro config format", - "implementation": "./src/migrations/update-16-6-0/update-metro-config" - }, - "update-16-9-0-remove-types-react-native": { - "cli": "nx", - "version": "16.9.0-beta.1", - "description": "Remove @types/react-native from package.json", - "implementation": "./src/migrations/update-16-9-0/remove-types-react-native" - }, "update-18-0-0-add-web-configuration": { "cli": "nx", "version": "18.0.0-beta.0", @@ -74,189 +44,6 @@ } }, "packageJsonUpdates": { - "16.0.0": { - "version": "16.0.0-beta.0", - "packages": { - "@react-native-community/cli": { - "version": "10.2.2", - "alwaysAddToPackageJson": false - }, - "react-native": { - "version": "0.71.7", - "alwaysAddToPackageJson": false - }, - "@types/react-native": { - "version": "0.71.6", - "alwaysAddToPackageJson": false - }, - "@testing-library/react-native": { - "version": "12.0.1", - "alwaysAddToPackageJson": false - }, - "react-native-svg": { - "version": "13.9.0", - "alwaysAddToPackageJson": false - } - } - }, - "16.0.2": { - "version": "16.0.2-beta.0", - "packages": { - "@react-native-async-storage/async-storage": { - "version": "1.18.1", - "alwaysAddToPackageJson": false - }, - "react-native-safe-area-context": { - "version": "4.5.1", - "alwaysAddToPackageJson": false - } - } - }, - "16.1.5": { - "version": "16.1.5-beta.0", - "packages": { - "react-native": { - "version": "0.71.8", - "alwaysAddToPackageJson": false - }, - "@types/react-native": { - "version": "0.71.7", - "alwaysAddToPackageJson": false - }, - "@testing-library/react-native": { - "version": "12.1.2", - "alwaysAddToPackageJson": false - }, - "react-native-safe-area-context": { - "version": "4.5.2", - "alwaysAddToPackageJson": false - } - } - }, - "16.4.0": { - "version": "16.4.0-beta.5", - "packages": { - "react-native": { - "version": "0.71.10", - "alwaysAddToPackageJson": false - }, - "@react-native-async-storage/async-storage": { - "version": "1.18.2", - "alwaysAddToPackageJson": false - }, - "react-native-safe-area-context": { - "version": "4.5.3", - "alwaysAddToPackageJson": false - } - } - }, - "16.6.0": { - "version": "16.6.0-beta.0", - "packages": { - "react-native": { - "version": "0.72.3", - "alwaysAddToPackageJson": false - }, - "@types/react-native": { - "version": "0.72.2", - "alwaysAddToPackageJson": false - }, - "metro": { - "version": "0.76.7", - "alwaysAddToPackageJson": false - }, - "metro-resolver": { - "version": "0.76.7", - "alwaysAddToPackageJson": false - }, - "metro-config": { - "version": "0.76.7", - "alwaysAddToPackageJson": false - }, - "metro-react-native-babel-preset": { - "version": "0.76.7", - "alwaysAddToPackageJson": false - }, - "metro-babel-register": { - "version": "0.76.7", - "alwaysAddToPackageJson": false - }, - "metro-react-native-babel-transformer": { - "version": "0.76.7", - "alwaysAddToPackageJson": false - }, - "@react-native/metro-config": { - "version": "^0.72.9", - "alwaysAddToPackageJson": false, - "addToPackageJson": "devDependencies" - }, - "@react-native-community/cli": { - "version": "11.3.5", - "alwaysAddToPackageJson": false - }, - "@react-native-community/cli-platform-android": { - "version": "11.3.5", - "alwaysAddToPackageJson": false - }, - "@react-native-community/cli-platform-ios": { - "version": "11.3.5", - "alwaysAddToPackageJson": false - }, - "@babel/runtime": { - "version": "7.22.6", - "alwaysAddToPackageJson": false - }, - "@react-native-async-storage/async-storage": { - "version": "1.19.0", - "alwaysAddToPackageJson": false - }, - "react-native-safe-area-context": { - "version": "4.7.1", - "alwaysAddToPackageJson": false - } - } - }, - "16.9.0": { - "version": "16.9.0-beta.1", - "packages": { - "react-native": { - "version": "0.72.4", - "alwaysAddToPackageJson": false - }, - "@react-native/metro-config": { - "version": "^0.72.11", - "alwaysAddToPackageJson": false - }, - "@react-native-community/cli": { - "version": "11.3.6", - "alwaysAddToPackageJson": false - }, - "@react-native-community/cli-platform-android": { - "version": "11.3.6", - "alwaysAddToPackageJson": false - }, - "@react-native-community/cli-platform-ios": { - "version": "11.3.6", - "alwaysAddToPackageJson": false - }, - "@testing-library/react-native": { - "version": "~12.3.0", - "alwaysAddToPackageJson": false - }, - "@testing-library/jest-native": { - "version": "~5.4.3", - "alwaysAddToPackageJson": false - }, - "@react-native-async-storage/async-storage": { - "version": "~1.19.3", - "alwaysAddToPackageJson": false - }, - "react-native-safe-area-context": { - "version": "~4.7.2", - "alwaysAddToPackageJson": false - } - } - }, "17.1.0": { "version": "17.1.0-beta.1", "packages": { diff --git a/packages/react-native/src/generators/application/application.ts b/packages/react-native/src/generators/application/application.ts index 98bc965814522c..69a39350d0eccd 100644 --- a/packages/react-native/src/generators/application/application.ts +++ b/packages/react-native/src/generators/application/application.ts @@ -9,6 +9,7 @@ import { } from '@nx/devkit'; import { initGenerator as jsInitGenerator } from '@nx/js'; import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { addLinting } from '../../utils/add-linting'; import { addJest } from '../../utils/add-jest'; @@ -40,6 +41,8 @@ export async function reactNativeApplicationGeneratorInternal( host: Tree, schema: Schema ): Promise { + assertNotUsingTsSolutionSetup(host, 'react-native', 'application'); + const options = await normalizeOptions(host, schema); const tasks: GeneratorCallback[] = []; diff --git a/packages/react-native/src/generators/init/init.ts b/packages/react-native/src/generators/init/init.ts index c4719d5bf6e959..aba59a20254d60 100644 --- a/packages/react-native/src/generators/init/init.ts +++ b/packages/react-native/src/generators/init/init.ts @@ -9,6 +9,7 @@ import { Tree, } from '@nx/devkit'; import { addPluginV1 } from '@nx/devkit/src/utils/add-plugin'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { createNodes } from '../../../plugins/plugin'; import { nxVersion, @@ -30,6 +31,8 @@ export async function reactNativeInitGeneratorInternal( host: Tree, schema: Schema ) { + assertNotUsingTsSolutionSetup(host, 'react-native', 'init'); + addGitIgnoreEntry(host); const nxJson = readNxJson(host); diff --git a/packages/react-native/src/generators/library/library.ts b/packages/react-native/src/generators/library/library.ts index a39765c036f818..01c65d63cf2a10 100644 --- a/packages/react-native/src/generators/library/library.ts +++ b/packages/react-native/src/generators/library/library.ts @@ -32,6 +32,7 @@ import { NormalizedSchema, normalizeOptions } from './lib/normalize-options'; import { Schema } from './schema'; import { ensureDependencies } from '../../utils/ensure-dependencies'; import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; export async function reactNativeLibraryGenerator( host: Tree, @@ -47,6 +48,8 @@ export async function reactNativeLibraryGeneratorInternal( host: Tree, schema: Schema ): Promise { + assertNotUsingTsSolutionSetup(host, 'react-native', 'library'); + const options = await normalizeOptions(host, schema); if (options.publishable === true && !schema.importPath) { throw new Error( diff --git a/packages/react-native/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts b/packages/react-native/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts deleted file mode 100644 index 3342dbf72ee028..00000000000000 --- a/packages/react-native/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Tree, readJson, updateJson } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import replacePackage from './update-16-0-0-add-nx-packages'; - -describe('update-16-0-0-add-nx-packages', () => { - let tree: Tree; - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - - updateJson(tree, 'package.json', (json) => { - json.devDependencies['@nrwl/react-native'] = '16.0.0'; - return json; - }); - }); - - it('should remove the dependency on @nrwl/react-native', async () => { - await replacePackage(tree); - - expect( - readJson(tree, 'package.json').dependencies['@nrwl/react-native'] - ).not.toBeDefined(); - expect( - readJson(tree, 'package.json').devDependencies['@nrwl/react-native'] - ).not.toBeDefined(); - }); - - it('should add a dependency on @nx/react-native', async () => { - await replacePackage(tree); - - const packageJson = readJson(tree, 'package.json'); - const newDependencyVersion = - packageJson.devDependencies['@nx/react-native'] ?? - packageJson.dependencies['@nx/react-native']; - - expect(newDependencyVersion).toBeDefined(); - }); -}); diff --git a/packages/react-native/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts b/packages/react-native/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts deleted file mode 100644 index e2ddecb068c785..00000000000000 --- a/packages/react-native/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Tree, formatFiles } from '@nx/devkit'; -import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package'; - -export default async function replacePackage(tree: Tree): Promise { - await replaceNrwlPackageWithNxPackage( - tree, - '@nrwl/react-native', - '@nx/react-native' - ); - - await formatFiles(tree); -} diff --git a/packages/react-native/src/migrations/update-16-1-0/upgrade-storybook-6-5.ts b/packages/react-native/src/migrations/update-16-1-0/upgrade-storybook-6-5.ts deleted file mode 100644 index 9eac7e956053e9..00000000000000 --- a/packages/react-native/src/migrations/update-16-1-0/upgrade-storybook-6-5.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Tree, updateJson } from '@nx/devkit'; - -/** - * This migration is to upgrade storybook to 6.5. - * - remove react-native-storybook-loader - */ -export default function update(tree: Tree) { - if (tree.exists('package.json')) { - updateJson(tree, 'package.json', (packageJson) => { - if (packageJson.dependencies?.['react-native-storybook-loader']) { - delete packageJson.dependencies['react-native-storybook-loader']; - } - if (packageJson.devDependencies?.['react-native-storybook-loader']) { - delete packageJson.devDependencies['react-native-storybook-loader']; - } - return packageJson; - }); - } -} diff --git a/packages/react-native/src/migrations/update-16-6-0/add-depends-on.ts b/packages/react-native/src/migrations/update-16-6-0/add-depends-on.ts deleted file mode 100644 index f2c45816dc0bb7..00000000000000 --- a/packages/react-native/src/migrations/update-16-6-0/add-depends-on.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { Tree, getProjects, updateProjectConfiguration } from '@nx/devkit'; - -/** - * This migration adds dependsOn to project.json. - * - */ -export default async function update(tree: Tree) { - const projects = getProjects(tree); - - for (const [name, config] of projects.entries()) { - if (config.targets?.['start']?.executor === '@nx/react-native:start') { - config.targets['start'].dependsOn = [ - 'ensure-symlink', - 'sync-deps', - 'pod-install', - ]; - if ( - config.targets?.['run-ios']?.executor === '@nx/react-native:run-ios' - ) { - config.targets['run-ios'].dependsOn = [ - 'ensure-symlink', - 'sync-deps', - 'pod-install', - ]; - } - if ( - config.targets?.['bundle-ios']?.executor === '@nx/react-native:bundle' - ) { - config.targets['bundle-ios'].dependsOn = ['ensure-symlink']; - } - if ( - config.targets?.['run-android']?.executor === - '@nx/react-native:run-android' - ) { - config.targets['run-android'].dependsOn ??= [ - 'ensure-symlink', - 'sync-deps', - ]; - } - if ( - config.targets?.['build-android']?.executor === - '@nx/react-native:build-android' - ) { - config.targets['build-android'].dependsOn = [ - 'ensure-symlink', - 'sync-deps', - ]; - } - if ( - config.targets?.['build-ios']?.executor === '@nx/react-native:build-ios' - ) { - config.targets['build-ios'].dependsOn ??= [ - 'ensure-symlink', - 'sync-deps', - 'pod-install', - ]; - } - if ( - config.targets?.['pod-instal']?.executor === - '@nx/react-native:pod-install' - ) { - config.targets['pod-install'].dependsOn ??= [ - 'ensure-symlink', - 'sync-deps', - ]; - } - if ( - config.targets?.['bundle-android']?.executor === - '@nx/react-native:bundle' - ) { - config.targets['bundle-android'].dependsOn ??= ['ensure-symlink']; - } - - updateProjectConfiguration(tree, name, config); - } - } -} diff --git a/packages/react-native/src/migrations/update-16-6-0/update-metro-config.ts b/packages/react-native/src/migrations/update-16-6-0/update-metro-config.ts deleted file mode 100644 index 0b32312e6d71e3..00000000000000 --- a/packages/react-native/src/migrations/update-16-6-0/update-metro-config.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { Tree, getProjects } from '@nx/devkit'; -import { join } from 'path'; - -/** - * This migration updates metro.config.js to export config as a default. - * - */ -export default async function update(tree: Tree) { - const projects = getProjects(tree); - - for (const [_, config] of projects.entries()) { - if (config.targets?.['start']?.executor === '@nx/react-native:start') { - if (tree.exists(join(config.root, 'metro.config.js'))) { - const oldConfig = tree - .read(join(config.root, 'metro.config.js')) - .toString(); - tree.write( - join(config.root, 'metro-v71.config.js'), - oldConfigComment + oldConfig - ); - tree.write(join(config.root, 'metro.config.js'), content); - } - } - } -} - -const oldConfigComment = `/** - * Old custom configuration for React Native v0.71. - * From @react-native/metro-config 0.72.1, it is no longer necessary to use a config function to access the complete default config. - * Please port your custom configuration to metro.config.js. - * Please see https://reactnative.dev/docs/metro to learn about configuration. - */ -`; - -const content = ` -const { withNxMetro } = require('@nx/react-native'); -const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config'); - -const defaultConfig = getDefaultConfig(__dirname); -const { assetExts, sourceExts } = defaultConfig.resolver; - -/** - * Metro configuration - * https://facebook.github.io/metro/docs/configuration - * - * @type {import('metro-config').MetroConfig} - */ -const customConfig = { - transformer: { - babelTransformerPath: require.resolve('react-native-svg-transformer'), - }, - resolver: { - assetExts: assetExts.filter((ext) => ext !== 'svg'), - sourceExts: [...sourceExts, 'cjs', 'mjs', 'svg'], - }, -}; - -module.exports = withNxMetro(mergeConfig(defaultConfig, customConfig), { - // Change this to true to see debugging info. - // Useful if you have issues resolving modules - debug: false, - // all the file extensions used for imports other than 'ts', 'tsx', 'js', 'jsx', 'json' - extensions: [], - // Specify folders to watch, in addition to Nx defaults (workspace libraries and node_modules) - watchFolders: [], -}); -`; diff --git a/packages/react-native/src/migrations/update-16-9-0/remove-types-react-native.ts b/packages/react-native/src/migrations/update-16-9-0/remove-types-react-native.ts deleted file mode 100644 index a2a9daabb16909..00000000000000 --- a/packages/react-native/src/migrations/update-16-9-0/remove-types-react-native.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { - formatFiles, - removeDependenciesFromPackageJson, - Tree, -} from '@nx/devkit'; - -/** - * Remove @types/react-native package since it is no longer required. It would be a part of react native package. - * @param tree - * @returns - */ -export default async function update(tree: Tree) { - removeDependenciesFromPackageJson(tree, [], ['@types/react-native']); - await formatFiles(tree); -} diff --git a/packages/react/migrations.json b/packages/react/migrations.json index 3791f1d66fab95..7c1aae730b7b4c 100644 --- a/packages/react/migrations.json +++ b/packages/react/migrations.json @@ -1,35 +1,5 @@ { "generators": { - "update-16-0-0-add-nx-packages": { - "cli": "nx", - "version": "16.0.0-beta.1", - "description": "Replace @nrwl/react with @nx/react", - "implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages" - }, - "update-16-2-0-remove-package": { - "cli": "nx", - "version": "16.2.0-beta.0", - "description": "Remove react-test-renderer from package.json", - "implementation": "./src/migrations/update-16-2-0-remove-package/update-16-2-0-remove-package" - }, - "remove-types-react-router-dom": { - "cli": "nx", - "version": "16.3.0-beta.2", - "description": "Remove @types/react-router-dom from package.json", - "implementation": "./src/migrations/update-16-3-0/remove-types-react-router-dom-package" - }, - "add-babel-core": { - "cli": "nx", - "version": "16.7.0-beta.2", - "description": "Add @babel/core to package.json if @babel/preset-react is present", - "implementation": "./src/migrations/update-16-7-0/add-babel-core" - }, - "update-16-7-0-add-typings": { - "cli": "nx", - "version": "16.7.0-beta.2", - "description": "Add @nx/react types to tsconfig types array", - "implementation": "./src/migrations/update-16-7-0-add-typings/update-16-7-0-add-typings" - }, "add-module-federation-env-var-to-target-defaults": { "cli": "nx", "version": "18.0.0-beta.0", @@ -62,88 +32,6 @@ } }, "packageJsonUpdates": { - "16.3.0": { - "version": "16.3.0-beta.2", - "packages": { - "react-router-dom": { - "version": "6.11.2", - "alwaysAddToPackageJson": false - }, - "@svgr/rollup": { - "version": "^8.0.1", - "alwaysAddToPackageJson": false - } - } - }, - "16.4.0-beta.4": { - "version": "16.4.0-beta.4", - "packages": { - "stylus": { - "version": "^0.59.0", - "alwaysAddToPackageJson": false - } - } - }, - "16.4.0-beta.7": { - "version": "16.4.0-beta.7", - "packages": { - "@types/react": { - "version": "18.2.12", - "alwaysAddToPackageJson": false - }, - "@types/react-dom": { - "version": "18.2.5", - "alwaysAddToPackageJson": false - }, - "@types/react-is": { - "version": "18.2.0", - "alwaysAddToPackageJson": false - } - } - }, - "16.4.0-beta.8": { - "version": "16.4.0-beta.8", - "packages": { - "@emotion/styled": { - "version": "11.11.0", - "alwaysAddToPackageJson": false - }, - "@emotion/react": { - "version": "11.11.1", - "alwaysAddToPackageJson": false - }, - "@emotion/babel-plugin": { - "version": "11.11.0", - "alwaysAddToPackageJson": false - } - } - }, - "16.4.0-beta.11": { - "version": "16.4.0-beta.11", - "packages": { - "@types/react": { - "version": "18.2.13", - "alwaysAddToPackageJson": false - }, - "@types/react-dom": { - "version": "18.2.6", - "alwaysAddToPackageJson": false - }, - "@types/react-is": { - "version": "18.2.1", - "alwaysAddToPackageJson": false - } - } - }, - "16.5.0-beta.4": { - "version": "16.5.0-beta.4", - "packages": { - "@types/react": { - "version": "18.2.14", - "alwaysAddToPackageJson": false - } - } - }, "17.0.0-beta.0": { "version": "17.0.0-beta.0", "packages": { diff --git a/packages/react/src/generators/application/application.ts b/packages/react/src/generators/application/application.ts index fef45c787c1f2c..158fa20eb2f668 100644 --- a/packages/react/src/generators/application/application.ts +++ b/packages/react/src/generators/application/application.ts @@ -46,6 +46,7 @@ import { initGenerator as jsInitGenerator } from '@nx/js'; import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command'; import { setupTailwindGenerator } from '../setup-tailwind/setup-tailwind'; import { useFlatConfig } from '@nx/eslint/src/utils/flat-config'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; async function addLinting(host: Tree, options: NormalizedSchema) { const tasks: GeneratorCallback[] = []; @@ -113,6 +114,8 @@ export async function applicationGeneratorInternal( host: Tree, schema: Schema ): Promise { + assertNotUsingTsSolutionSetup(host, 'react', 'application'); + const tasks = []; const options = await normalizeOptions(host, schema); diff --git a/packages/react/src/generators/host/host.ts b/packages/react/src/generators/host/host.ts index 95a7393b09c3af..28b261050fe492 100644 --- a/packages/react/src/generators/host/host.ts +++ b/packages/react/src/generators/host/host.ts @@ -25,11 +25,14 @@ import { addMfEnvToTargetDefaultInputs } from '../../utils/add-mf-env-to-inputs' import { isValidVariable } from '@nx/js'; import { moduleFederationEnhancedVersion } from '../../utils/versions'; import { ensureProjectName } from '@nx/devkit/src/generators/project-name-and-root-utils'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; export async function hostGenerator( host: Tree, schema: Schema ): Promise { + assertNotUsingTsSolutionSetup(host, 'react', 'host'); + const tasks: GeneratorCallback[] = []; const options: NormalizedSchema = { ...(await normalizeOptions(host, schema)), diff --git a/packages/react/src/generators/init/init.ts b/packages/react/src/generators/init/init.ts index 105e863d62793d..2f63ee51df9596 100755 --- a/packages/react/src/generators/init/init.ts +++ b/packages/react/src/generators/init/init.ts @@ -6,10 +6,13 @@ import { type GeneratorCallback, type Tree, } from '@nx/devkit'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { nxVersion, reactDomVersion, reactVersion } from '../../utils/versions'; import { InitSchema } from './schema'; export async function reactInitGenerator(host: Tree, schema: InitSchema) { + assertNotUsingTsSolutionSetup(host, 'react', 'init'); + const tasks: GeneratorCallback[] = []; if (!schema.skipPackageJson) { diff --git a/packages/react/src/generators/library/library.ts b/packages/react/src/generators/library/library.ts index b60bc0cf6753ee..337d90cb451b47 100644 --- a/packages/react/src/generators/library/library.ts +++ b/packages/react/src/generators/library/library.ts @@ -12,6 +12,7 @@ import { import { getRelativeCwd } from '@nx/devkit/src/generators/artifact-name-and-directory-utils'; import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command'; import { addTsConfigPath, initGenerator as jsInitGenerator } from '@nx/js'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { nxVersion } from '../../utils/versions'; import { maybeJs } from '../../utils/maybe-js'; @@ -36,6 +37,8 @@ export async function libraryGenerator(host: Tree, schema: Schema) { } export async function libraryGeneratorInternal(host: Tree, schema: Schema) { + assertNotUsingTsSolutionSetup(host, 'react', 'library'); + const tasks: GeneratorCallback[] = []; const options = await normalizeOptions(host, schema); diff --git a/packages/react/src/generators/remote/remote.ts b/packages/react/src/generators/remote/remote.ts index c5d52219bb8654..de6c4557bf5b0d 100644 --- a/packages/react/src/generators/remote/remote.ts +++ b/packages/react/src/generators/remote/remote.ts @@ -27,6 +27,7 @@ import { maybeJs } from '../../utils/maybe-js'; import { isValidVariable } from '@nx/js'; import { moduleFederationEnhancedVersion } from '../../utils/versions'; import { ensureProjectName } from '@nx/devkit/src/generators/project-name-and-root-utils'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; export function addModuleFederationFiles( host: Tree, @@ -90,6 +91,8 @@ export function addModuleFederationFiles( } export async function remoteGenerator(host: Tree, schema: Schema) { + assertNotUsingTsSolutionSetup(host, 'react', 'remote'); + const tasks: GeneratorCallback[] = []; const options: NormalizedSchema = { ...(await normalizeOptions(host, schema)), diff --git a/packages/react/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts b/packages/react/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts deleted file mode 100644 index 63e3112c5825d7..00000000000000 --- a/packages/react/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Tree, readJson, updateJson } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import replacePackage from './update-16-0-0-add-nx-packages'; - -describe('update-16-0-0-add-nx-packages', () => { - let tree: Tree; - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - - updateJson(tree, 'package.json', (json) => { - json.devDependencies['@nrwl/react'] = '16.0.0'; - return json; - }); - }); - - it('should remove the dependency on @nrwl/react', async () => { - await replacePackage(tree); - - expect( - readJson(tree, 'package.json').dependencies['@nrwl/react'] - ).not.toBeDefined(); - expect( - readJson(tree, 'package.json').devDependencies['@nrwl/react'] - ).not.toBeDefined(); - }); - - it('should add a dependency on @nx/react', async () => { - await replacePackage(tree); - - const packageJson = readJson(tree, 'package.json'); - const newDependencyVersion = - packageJson.devDependencies['@nx/react'] ?? - packageJson.dependencies['@nx/react']; - - expect(newDependencyVersion).toBeDefined(); - }); -}); diff --git a/packages/react/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts b/packages/react/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts deleted file mode 100644 index 951796732f0416..00000000000000 --- a/packages/react/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Tree, formatFiles } from '@nx/devkit'; -import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package'; - -export default async function replacePackage(tree: Tree): Promise { - await replaceNrwlPackageWithNxPackage(tree, '@nrwl/react', '@nx/react'); - - await formatFiles(tree); -} diff --git a/packages/react/src/migrations/update-16-2-0-remove-package/update-16-2-0-remove-package.spec.ts b/packages/react/src/migrations/update-16-2-0-remove-package/update-16-2-0-remove-package.spec.ts deleted file mode 100644 index d9901b11370841..00000000000000 --- a/packages/react/src/migrations/update-16-2-0-remove-package/update-16-2-0-remove-package.spec.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Tree, readJson, updateJson } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from 'nx/src/devkit-testing-exports'; -import removePackage from './update-16-2-0-remove-package'; - -describe('update-16-2-0-remove-package', () => { - let tree: Tree; - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - - updateJson(tree, 'package.json', (json) => { - json.devDependencies['react-test-renderer'] = '18.2.0'; - return json; - }); - }); - - it('should remove react-test-renderer from package.json', async () => { - await removePackage(tree); - - expect( - readJson(tree, 'package.json').devDependencies['react-test-renderer'] - ).not.toBeDefined(); - }); -}); diff --git a/packages/react/src/migrations/update-16-2-0-remove-package/update-16-2-0-remove-package.ts b/packages/react/src/migrations/update-16-2-0-remove-package/update-16-2-0-remove-package.ts deleted file mode 100644 index 00b761a1855088..00000000000000 --- a/packages/react/src/migrations/update-16-2-0-remove-package/update-16-2-0-remove-package.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { - Tree, - formatFiles, - removeDependenciesFromPackageJson, -} from '@nx/devkit'; - -export default async function removePackage(tree: Tree): Promise { - removeDependenciesFromPackageJson(tree, [], ['react-test-renderer']); - await formatFiles(tree); -} diff --git a/packages/react/src/migrations/update-16-3-0/remove-types-react-router-dom-package.spec.ts b/packages/react/src/migrations/update-16-3-0/remove-types-react-router-dom-package.spec.ts deleted file mode 100644 index f83bb5555288be..00000000000000 --- a/packages/react/src/migrations/update-16-3-0/remove-types-react-router-dom-package.spec.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Tree, readJson, updateJson } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from 'nx/src/devkit-testing-exports'; -import removePackage from './remove-types-react-router-dom-package'; - -describe('update-16-3-0-remove-types-react-router-dom-package', () => { - let tree: Tree; - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - - updateJson(tree, 'package.json', (json) => { - json.devDependencies['@types/react-router-dom'] = '*'; - return json; - }); - }); - - it('should remove react-test-renderer from package.json', async () => { - await removePackage(tree); - - expect( - readJson(tree, 'package.json').devDependencies['react-test-renderer'] - ).not.toBeDefined(); - }); -}); diff --git a/packages/react/src/migrations/update-16-3-0/remove-types-react-router-dom-package.ts b/packages/react/src/migrations/update-16-3-0/remove-types-react-router-dom-package.ts deleted file mode 100644 index 00b761a1855088..00000000000000 --- a/packages/react/src/migrations/update-16-3-0/remove-types-react-router-dom-package.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { - Tree, - formatFiles, - removeDependenciesFromPackageJson, -} from '@nx/devkit'; - -export default async function removePackage(tree: Tree): Promise { - removeDependenciesFromPackageJson(tree, [], ['react-test-renderer']); - await formatFiles(tree); -} diff --git a/packages/react/src/migrations/update-16-7-0-add-typings/update-16-7-0-add-typings.spec.ts b/packages/react/src/migrations/update-16-7-0-add-typings/update-16-7-0-add-typings.spec.ts deleted file mode 100644 index 29e71519903f79..00000000000000 --- a/packages/react/src/migrations/update-16-7-0-add-typings/update-16-7-0-add-typings.spec.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { Tree, addProjectConfiguration } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from 'nx/src/devkit-testing-exports'; -import addTypings from './update-16-7-0-add-typings'; - -describe('Add typings to react projects', () => { - let tree: Tree; - - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - }); - - it('should update tsconfig to include react typings', async () => { - tree.write( - 'package.json', - JSON.stringify({ - dependencies: {}, - devDependencies: {}, - }) - ); - - addProjectConfiguration(tree, 'myapp', { - root: 'myapp', - targets: { - build: { - executor: '@nx/webpack:webpack', - }, - serve: { - executor: '@nx/webpack:dev-server', - }, - }, - }); - tree.write( - 'myapp/tsconfig.json', - JSON.stringify({ - compilerOptions: { - jsx: 'react-jsx', - }, - }) - ); - tree.write( - 'myapp/tsconfig.app.json', - JSON.stringify({ - compilerOptions: {}, - }) - ); - - await addTypings(tree); - const tsconfigTypes = JSON.parse( - tree.read('myapp/tsconfig.app.json', 'utf-8') - ); - - expect(tsconfigTypes.compilerOptions.types).toContain( - '@nx/react/typings/cssmodule.d.ts' - ); - expect(tsconfigTypes.compilerOptions.types).toContain( - '@nx/react/typings/image.d.ts' - ); - }); - - it('should not update tsconfig of node app to include react typings', async () => { - tree.write( - 'package.json', - JSON.stringify({ - dependencies: {}, - devDependencies: {}, - }) - ); - - addProjectConfiguration(tree, 'myapp', { - root: 'myapp', - targets: { - build: { - executor: '@nx/webpack:webpack', - }, - serve: { - executor: '@nx/js:node', - }, - }, - }); - tree.write( - 'myapp/tsconfig.app.json', - JSON.stringify({ - compilerOptions: { - types: [], - }, - }) - ); - - await addTypings(tree); - const tsconfigTypes = JSON.parse( - tree.read('myapp/tsconfig.app.json', 'utf-8') - ); - - expect(tsconfigTypes.compilerOptions.types).not.toContain( - '@nx/react/typings/cssmodule.d.ts' - ); - expect(tsconfigTypes.compilerOptions.types).not.toContain( - '@nx/react/typings/image.d.ts' - ); - }); -}); diff --git a/packages/react/src/migrations/update-16-7-0-add-typings/update-16-7-0-add-typings.ts b/packages/react/src/migrations/update-16-7-0-add-typings/update-16-7-0-add-typings.ts deleted file mode 100644 index abca89a6ba78ad..00000000000000 --- a/packages/react/src/migrations/update-16-7-0-add-typings/update-16-7-0-add-typings.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { - Tree, - formatFiles, - getProjects, - joinPathFragments, - readJson, - updateJson, -} from '@nx/devkit'; - -export default async function addTypings(tree: Tree) { - const projects = getProjects(tree); - const buildExecutors = [ - '@nx/webpack:webpack', - '@nx/vite:build', - '@nx/rspack:rspack', - ]; - const serveExecutors = [ - '@nx/webpack:dev-server', - '@nx/vite:dev-server', - '@nx/rspack:dev-server', - ]; - const relatedTsConfigs = [ - 'tsconfig.app.json', - 'tsconfig.lib.json', - 'tsconfig.spec.json', - ]; - - const typesToAdd = [ - '@nx/react/typings/cssmodule.d.ts', - '@nx/react/typings/image.d.ts', - ]; - - for (const [, config] of projects) { - if (!buildExecutors.includes(config?.targets?.build?.executor)) { - continue; - } - if ( - config?.targets?.serve?.executor && - !serveExecutors.includes(config?.targets?.serve?.executor) - ) { - continue; - } - const rootPath = config.root; - const projectTsConfigPath = joinPathFragments(rootPath, 'tsconfig.json'); - const projectTsConfig = readJson(tree, projectTsConfigPath); - if (projectTsConfig.compilerOptions?.jsx !== 'react-jsx') { - continue; - } - - relatedTsConfigs.forEach((tsConfig) => { - const tsConfigPath = joinPathFragments(rootPath, tsConfig); - if (tree.exists(tsConfigPath)) { - updateJson(tree, tsConfigPath, (json) => { - const compilerOptions = json.compilerOptions || {}; - compilerOptions.types = [ - ...new Set([...(compilerOptions.types || []), ...typesToAdd]), - ]; - if (json.files?.length > 0) { - json.files = json.files.filter( - (file: string) => !['cssmodule.d.ts', 'image.d.ts'].includes(file) - ); - } - return { ...json, compilerOptions }; - }); - } - }); - } - await formatFiles(tree); -} diff --git a/packages/react/src/migrations/update-16-7-0/add-babel-core.spec.ts b/packages/react/src/migrations/update-16-7-0/add-babel-core.spec.ts deleted file mode 100644 index 5489bcc0b8a821..00000000000000 --- a/packages/react/src/migrations/update-16-7-0/add-babel-core.spec.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Tree, readJson, updateJson } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import addBabelCore from './add-babel-core'; - -describe('update-16-7-0-add-babel-core', () => { - let tree: Tree; - - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - }); - - it('should add @babel/core to package.json', async () => { - updateJson(tree, 'package.json', (json) => { - json.devDependencies['@babel/preset-react'] = '*'; - return json; - }); - - await addBabelCore(tree); - - expect( - readJson(tree, 'package.json').devDependencies['@babel/core'] - ).toBeDefined(); - }); - - it('should not add @babel/core to package.json if preset-react is not available', async () => { - await addBabelCore(tree); - - expect( - readJson(tree, 'package.json').devDependencies['@babel/core'] - ).not.toBeDefined(); - }); -}); diff --git a/packages/react/src/migrations/update-16-7-0/add-babel-core.ts b/packages/react/src/migrations/update-16-7-0/add-babel-core.ts deleted file mode 100644 index 660a5db55fd840..00000000000000 --- a/packages/react/src/migrations/update-16-7-0/add-babel-core.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { - Tree, - addDependenciesToPackageJson, - formatFiles, - readJson, -} from '@nx/devkit'; -import { babelCoreVersion } from '../../utils/versions'; - -export default async function addBabelCore(tree: Tree): Promise { - const packageJson = readJson(tree, 'package.json'); - if (packageJson?.devDependencies['@babel/preset-react']) { - addDependenciesToPackageJson( - tree, - {}, - { - '@babel/core': babelCoreVersion, - } - ); - await formatFiles(tree); - } -} diff --git a/packages/react/src/module-federation/with-module-federation-ssr.ts b/packages/react/src/module-federation/with-module-federation-ssr.ts index a396f28954e142..a852b93b36843a 100644 --- a/packages/react/src/module-federation/with-module-federation-ssr.ts +++ b/packages/react/src/module-federation/with-module-federation-ssr.ts @@ -28,7 +28,7 @@ export async function withModuleFederationForSSR( config.plugins.push( new (require('@module-federation/enhanced').ModuleFederationPlugin)( { - name: options.name, + name: options.name.replace(/-/g, '_'), filename: 'remoteEntry.js', exposes: options.exposes, remotes: mappedRemotes, diff --git a/packages/react/src/module-federation/with-module-federation.ts b/packages/react/src/module-federation/with-module-federation.ts index 6ca1a841009b11..885da9165eb1f8 100644 --- a/packages/react/src/module-federation/with-module-federation.ts +++ b/packages/react/src/module-federation/with-module-federation.ts @@ -41,7 +41,7 @@ export async function withModuleFederation( config.plugins.push( new ModuleFederationPlugin({ - name: options.name, + name: options.name.replace(/-/g, '_'), filename: 'remoteEntry.js', exposes: options.exposes, remotes: mappedRemotes, diff --git a/packages/remix/src/generators/application/application.impl.ts b/packages/remix/src/generators/application/application.impl.ts index da5aba5cede10d..ad6acdf5405dba 100644 --- a/packages/remix/src/generators/application/application.impl.ts +++ b/packages/remix/src/generators/application/application.impl.ts @@ -20,6 +20,7 @@ import { addBuildTargetDefaults } from '@nx/devkit/src/generators/target-default import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command'; import { initGenerator as jsInitGenerator } from '@nx/js'; import { extractTsConfigBase } from '@nx/js/src/utils/typescript/create-ts-config'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { dirname } from 'node:path'; import { createNxCloudOnboardingURLForWelcomeApp, @@ -56,6 +57,8 @@ export async function remixApplicationGeneratorInternal( tree: Tree, _options: NxRemixGeneratorSchema ) { + assertNotUsingTsSolutionSetup(tree, 'remix', 'application'); + const options = await normalizeOptions(tree, _options); const tasks: GeneratorCallback[] = [ await initGenerator(tree, { diff --git a/packages/remix/src/generators/init/init.ts b/packages/remix/src/generators/init/init.ts index edbd94bf2c7718..470d6e9d879f84 100644 --- a/packages/remix/src/generators/init/init.ts +++ b/packages/remix/src/generators/init/init.ts @@ -11,6 +11,7 @@ import { addPlugin, generateCombinations, } from '@nx/devkit/src/utils/add-plugin'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { createNodesV2 } from '../../plugins/plugin'; import { nxVersion, remixVersion } from '../../utils/versions'; import { type Schema } from './schema'; @@ -20,6 +21,8 @@ export function remixInitGenerator(tree: Tree, options: Schema) { } export async function remixInitGeneratorInternal(tree: Tree, options: Schema) { + assertNotUsingTsSolutionSetup(tree, 'remix', 'init'); + const tasks: GeneratorCallback[] = []; if (!options.skipPackageJson) { diff --git a/packages/remix/src/generators/library/library.impl.ts b/packages/remix/src/generators/library/library.impl.ts index 6473918c778118..d08496214c424e 100644 --- a/packages/remix/src/generators/library/library.impl.ts +++ b/packages/remix/src/generators/library/library.impl.ts @@ -1,6 +1,7 @@ import type { Tree } from '@nx/devkit'; import { formatFiles, GeneratorCallback, runTasksInSerial } from '@nx/devkit'; import { Linter } from '@nx/eslint'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { libraryGenerator } from '@nx/react'; import { addTsconfigEntryPoints, @@ -21,6 +22,8 @@ export async function remixLibraryGeneratorInternal( tree: Tree, schema: NxRemixGeneratorSchema ) { + assertNotUsingTsSolutionSetup(tree, 'remix', 'library'); + const tasks: GeneratorCallback[] = []; const options = await normalizeOptions(tree, schema); diff --git a/packages/rollup/migrations.json b/packages/rollup/migrations.json index fb636fa151b6f4..4b77be7bb6791a 100644 --- a/packages/rollup/migrations.json +++ b/packages/rollup/migrations.json @@ -1,24 +1,5 @@ { - "generators": { - "update-16-0-0-add-nx-packages": { - "cli": "nx", - "version": "16.0.0-beta.1", - "description": "Replace @nrwl/rollup with @nx/rollup", - "implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages" - }, - "update-16-3-3-add-babel-upward-root-mode-flag": { - "cli": "nx", - "version": "16.3.3-beta.0", - "description": "Add babelUpwardRootMode if not already defined", - "implementation": "./src/migrations/update-16-3-3-add-babel-upward-root-mode-flag/update-16-3-3-add-babel-upward-root-mode-flag" - }, - "explicitly-set-projects-to-update-buildable-deps": { - "cli": "nx", - "version": "16.6.0-beta.0", - "description": "Explicitly set 'updateBuildableProjectDepsInPackageJson' to 'true' in targets that rely on that value as the default.", - "factory": "./src/migrations/update-16-6-0/explicitly-set-projects-to-update-buildable-deps" - } - }, + "generators": {}, "packageJsonUpdates": { "18.2.0": { "version": "18.2.0-beta.1", diff --git a/packages/rollup/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts b/packages/rollup/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts deleted file mode 100644 index 6b5307270d6bfd..00000000000000 --- a/packages/rollup/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Tree, readJson, updateJson } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import replacePackage from './update-16-0-0-add-nx-packages'; - -describe('update-16-0-0-add-nx-packages', () => { - let tree: Tree; - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - - updateJson(tree, 'package.json', (json) => { - json.devDependencies['@nrwl/rollup'] = '16.0.0'; - return json; - }); - }); - - it('should remove the dependency on @nrwl/rollup', async () => { - await replacePackage(tree); - - expect( - readJson(tree, 'package.json').dependencies['@nrwl/rollup'] - ).not.toBeDefined(); - expect( - readJson(tree, 'package.json').devDependencies['@nrwl/rollup'] - ).not.toBeDefined(); - }); - - it('should add a dependency on @nx/rollup', async () => { - await replacePackage(tree); - - const packageJson = readJson(tree, 'package.json'); - const newDependencyVersion = - packageJson.devDependencies['@nx/rollup'] ?? - packageJson.dependencies['@nx/rollup']; - - expect(newDependencyVersion).toBeDefined(); - }); -}); diff --git a/packages/rollup/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts b/packages/rollup/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts deleted file mode 100644 index 785c3859ba5aab..00000000000000 --- a/packages/rollup/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Tree, formatFiles } from '@nx/devkit'; -import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package'; - -export default async function replacePackage(tree: Tree): Promise { - await replaceNrwlPackageWithNxPackage(tree, '@nrwl/rollup', '@nx/rollup'); - - await formatFiles(tree); -} diff --git a/packages/rollup/src/migrations/update-16-3-3-add-babel-upward-root-mode-flag/update-16-3-3-add-babel-upward-root-mode-flag.spec.ts b/packages/rollup/src/migrations/update-16-3-3-add-babel-upward-root-mode-flag/update-16-3-3-add-babel-upward-root-mode-flag.spec.ts deleted file mode 100644 index d041cd5fac4be6..00000000000000 --- a/packages/rollup/src/migrations/update-16-3-3-add-babel-upward-root-mode-flag/update-16-3-3-add-babel-upward-root-mode-flag.spec.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import { - addProjectConfiguration, - readProjectConfiguration, - Tree, -} from '@nx/devkit'; -import addBabelUpwardRootModeFlag from './update-16-3-3-add-babel-upward-root-mode-flag'; - -describe('16.3.0 migration (add babelUpwardRootMode flag)', () => { - let tree: Tree; - - beforeEach(async () => { - tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); - }); - - it('should add the babelUpwardRootMode flag to rollup projects', async () => { - addProjectConfiguration(tree, 'app1', { - root: 'apps/app1', - targets: { - build: { - executor: '@nx/rollup:rollup', - options: {}, - }, - }, - }); - addProjectConfiguration(tree, 'app2', { - root: 'apps/app2', - targets: { - build: { - executor: '@nx/rollup:rollup', - options: { - babelUpwardRootMode: false, - }, - }, - }, - }); - - addProjectConfiguration(tree, 'app3', { - root: 'apps/app3', - targets: { - build: { - executor: '@nx/esbuild:esbuild', - options: {}, - }, - }, - }); - - await addBabelUpwardRootModeFlag(tree); - - const app1 = readProjectConfiguration(tree, 'app1'); - const app2 = readProjectConfiguration(tree, 'app2'); - const app3 = readProjectConfiguration(tree, 'app3'); - - expect(app1.targets['build'].options.babelUpwardRootMode).toBeTruthy(); - expect(app2.targets['build'].options.babelUpwardRootMode).toBeFalsy(); - expect(app3.targets['build'].options.babelUpwardRootMode).toBeUndefined(); - }); -}); diff --git a/packages/rollup/src/migrations/update-16-3-3-add-babel-upward-root-mode-flag/update-16-3-3-add-babel-upward-root-mode-flag.ts b/packages/rollup/src/migrations/update-16-3-3-add-babel-upward-root-mode-flag/update-16-3-3-add-babel-upward-root-mode-flag.ts deleted file mode 100644 index 35e02941539e5e..00000000000000 --- a/packages/rollup/src/migrations/update-16-3-3-add-babel-upward-root-mode-flag/update-16-3-3-add-babel-upward-root-mode-flag.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { - formatFiles, - readProjectConfiguration, - Tree, - updateProjectConfiguration, -} from '@nx/devkit'; -import { forEachExecutorOptions } from '@nx/devkit/src/generators/executor-options-utils'; -import { RollupExecutorOptions } from '../../executors/rollup/schema'; - -export default async function (tree: Tree) { - forEachExecutorOptions( - tree, - '@nx/rollup:rollup', - ( - options: RollupExecutorOptions, - projectName, - targetName, - _configurationName - ) => { - if (options.babelUpwardRootMode !== undefined) { - return; - } - - const projectConfiguration = readProjectConfiguration(tree, projectName); - projectConfiguration.targets[targetName].options.babelUpwardRootMode = - true; - updateProjectConfiguration(tree, projectName, projectConfiguration); - } - ); - - await formatFiles(tree); -} diff --git a/packages/rollup/src/migrations/update-16-6-0/explicitly-set-projects-to-update-buildable-deps.spec.ts b/packages/rollup/src/migrations/update-16-6-0/explicitly-set-projects-to-update-buildable-deps.spec.ts deleted file mode 100644 index e507d75aeaca30..00000000000000 --- a/packages/rollup/src/migrations/update-16-6-0/explicitly-set-projects-to-update-buildable-deps.spec.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { - ProjectConfiguration, - ProjectGraph, - Tree, - addProjectConfiguration, - readProjectConfiguration, -} from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import migration from './explicitly-set-projects-to-update-buildable-deps'; - -let projectGraph: ProjectGraph; -jest.mock('@nx/devkit', () => ({ - ...jest.requireActual('@nx/devkit'), - createProjectGraphAsync: () => Promise.resolve(projectGraph), -})); - -describe('explicitly-set-projects-to-update-buildable-deps migration', () => { - let tree: Tree; - - beforeEach(() => { - tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); - }); - - it.each(['@nx/rollup:rollup', '@nrwl/rollup:rollup'])( - 'should set updateBuildableProjectDepsInPackageJson option to "true" when not specified in target using "%s"', - async (executor) => { - addProject(tree, 'lib1', { - root: 'libs/lib1', - projectType: 'library', - targets: { build: { executor, options: {} } }, - }); - - await migration(tree); - - const project = readProjectConfiguration(tree, 'lib1'); - expect( - project.targets.build.options.updateBuildableProjectDepsInPackageJson - ).toBe(true); - } - ); - - it.each(['@nx/rollup:rollup', '@nrwl/rollup:rollup'])( - 'should set updateBuildableProjectDepsInPackageJson option to "true" when target has no options object defined using "%s"', - async (executor) => { - addProject(tree, 'lib1', { - root: 'libs/lib1', - projectType: 'library', - targets: { build: { executor } }, - }); - - await migration(tree); - - const project = readProjectConfiguration(tree, 'lib1'); - expect( - project.targets.build.options.updateBuildableProjectDepsInPackageJson - ).toBe(true); - } - ); - - it.each(['@nx/js:swc', '@nrwl/js:swc', '@nx/js:tsc', '@nrwl/js:tsc'])( - 'should not overwrite updateBuildableProjectDepsInPackageJson option when it is specified in target using "%s"', - async (executor) => { - addProject(tree, 'lib1', { - root: 'libs/lib1', - projectType: 'library', - targets: { - build: { - executor, - options: { updateBuildableProjectDepsInPackageJson: false }, - }, - }, - }); - - await migration(tree); - - const project = readProjectConfiguration(tree, 'lib1'); - expect( - project.targets.build.options.updateBuildableProjectDepsInPackageJson - ).toBe(false); - } - ); - - it('should not update targets using other executors', async () => { - const originalProjectConfig: ProjectConfiguration = { - root: 'libs/lib1', - projectType: 'library', - targets: { - build: { - executor: 'some-executor', - options: {}, - }, - }, - }; - addProject(tree, 'lib1', originalProjectConfig); - - await migration(tree); - - const project = readProjectConfiguration(tree, 'lib1'); - expect(project.targets).toStrictEqual(originalProjectConfig.targets); - }); -}); - -function addProject( - tree: Tree, - projectName: string, - config: ProjectConfiguration -): void { - projectGraph = { - dependencies: {}, - nodes: { - [projectName]: { - data: config, - name: projectName, - type: config.projectType === 'application' ? 'app' : 'lib', - }, - }, - }; - addProjectConfiguration(tree, projectName, config); -} diff --git a/packages/rollup/src/migrations/update-16-6-0/explicitly-set-projects-to-update-buildable-deps.ts b/packages/rollup/src/migrations/update-16-6-0/explicitly-set-projects-to-update-buildable-deps.ts deleted file mode 100644 index 5af99c4f5b181c..00000000000000 --- a/packages/rollup/src/migrations/update-16-6-0/explicitly-set-projects-to-update-buildable-deps.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { - createProjectGraphAsync, - formatFiles, - readProjectConfiguration, - Tree, - updateProjectConfiguration, -} from '@nx/devkit'; - -const executors = new Set(['@nx/rollup:rollup', '@nrwl/rollup:rollup']); - -export default async function (tree: Tree) { - // use project graph to get the expanded target configurations - const projectGraph = await createProjectGraphAsync(); - - for (const [projectName, { data: projectData }] of Object.entries( - projectGraph.nodes - )) { - if (projectData.projectType !== 'library') { - continue; - } - - for (const [targetName, target] of Object.entries( - projectData.targets || {} - )) { - if (!executors.has(target.executor)) { - continue; - } - - if ( - !target.options || - target.options.updateBuildableProjectDepsInPackageJson === undefined - ) { - // read the project configuration to write the explicit project configuration - // and avoid writing the expanded target configuration - const project = readProjectConfiguration(tree, projectName); - project.targets[targetName].options ??= {}; - project.targets[ - targetName - ].options.updateBuildableProjectDepsInPackageJson = true; - updateProjectConfiguration(tree, projectName, project); - } - } - } - - await formatFiles(tree); -} diff --git a/packages/rspack/migrations.json b/packages/rspack/migrations.json index 88f20a517d0b2d..549dd79a0163b8 100644 --- a/packages/rspack/migrations.json +++ b/packages/rspack/migrations.json @@ -1,30 +1,6 @@ { - "generators": { - "update-16-0-0-add-nx-packages": { - "cli": "nx", - "version": "16.0.0-beta.1", - "description": "Replace @nrwl/rspack with @nx/rspack", - "implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages" - } - }, + "generators": {}, "packageJsonUpdates": { - "16.1.3": { - "version": "16.1.3-beta.0", - "packages": { - "@rspack/core": { - "version": "~0.1.12", - "alwaysAddToPackageJson": false - }, - "@rspack/dev-server": { - "version": "~0.1.12", - "alwaysAddToPackageJson": false - }, - "@rspack/plugin-minify": { - "version": "~0.1.12", - "alwaysAddToPackageJson": false - } - } - }, "18.1.0": { "version": "18.1.0-beta.0", "packages": { diff --git a/packages/rspack/src/generators/application/application.ts b/packages/rspack/src/generators/application/application.ts index 77ae88c8680b60..60d01c7b85f149 100644 --- a/packages/rspack/src/generators/application/application.ts +++ b/packages/rspack/src/generators/application/application.ts @@ -1,4 +1,5 @@ import { ensurePackage, formatFiles, runTasksInSerial, Tree } from '@nx/devkit'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { version as nxVersion } from 'nx/package.json'; import configurationGenerator from '../configuration/configuration'; import rspackInitGenerator from '../init/init'; @@ -9,6 +10,8 @@ export default async function ( tree: Tree, _options: ApplicationGeneratorSchema ) { + assertNotUsingTsSolutionSetup(tree, 'rspack', 'application'); + const tasks = []; const initTask = await rspackInitGenerator(tree, { ..._options, diff --git a/packages/rspack/src/generators/configuration/configuration.ts b/packages/rspack/src/generators/configuration/configuration.ts index 4a977e450f3201..53be9571c22724 100644 --- a/packages/rspack/src/generators/configuration/configuration.ts +++ b/packages/rspack/src/generators/configuration/configuration.ts @@ -5,6 +5,7 @@ import { readProjectConfiguration, Tree, } from '@nx/devkit'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { addOrChangeBuildTarget, addOrChangeServeTarget, @@ -25,6 +26,8 @@ export async function configurationGenerator( tree: Tree, options: ConfigurationSchema ) { + assertNotUsingTsSolutionSetup(tree, 'rspack', 'configuration'); + const task = await rspackInitGenerator(tree, { ...options, // TODO: Crystalize the default rspack.config.js file. diff --git a/packages/rspack/src/generators/init/init.ts b/packages/rspack/src/generators/init/init.ts index f32af80d9c6968..6e43253f46ef04 100644 --- a/packages/rspack/src/generators/init/init.ts +++ b/packages/rspack/src/generators/init/init.ts @@ -9,6 +9,7 @@ import { } from '@nx/devkit'; import { addPlugin } from '@nx/devkit/src/utils/add-plugin'; import { initGenerator } from '@nx/js'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { createNodesV2 } from '../../../plugin'; import { lessLoaderVersion, @@ -24,6 +25,8 @@ export async function rspackInitGenerator( tree: Tree, schema: InitGeneratorSchema ) { + assertNotUsingTsSolutionSetup(tree, 'rspack', 'init'); + const tasks: GeneratorCallback[] = []; const nxJson = readNxJson(tree); diff --git a/packages/rspack/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts b/packages/rspack/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts deleted file mode 100644 index 8fc2324fb4e19c..00000000000000 --- a/packages/rspack/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { readJson, Tree, updateJson } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import replacePackage from './update-16-0-0-add-nx-packages'; - -describe('update-16-0-0-add-nx-packages', () => { - let tree: Tree; - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - - updateJson(tree, 'package.json', (json) => { - json.devDependencies['@nrwl/rspack'] = '16.0.0'; - return json; - }); - }); - - it('should remove the dependency on @nrwl/rspack', async () => { - await replacePackage(tree); - - expect( - readJson(tree, 'package.json').dependencies['@nrwl/rspack'] - ).not.toBeDefined(); - expect( - readJson(tree, 'package.json').devDependencies['@nrwl/rspack'] - ).not.toBeDefined(); - }); - - it('should add a dependency on @nx/rspack', async () => { - await replacePackage(tree); - - const packageJson = readJson(tree, 'package.json'); - const newDependencyVersion = - packageJson.devDependencies['@nx/rspack'] ?? - packageJson.dependencies['@nx/rspack']; - - expect(newDependencyVersion).toBeDefined(); - }); -}); diff --git a/packages/rspack/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts b/packages/rspack/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts deleted file mode 100644 index bf44165b3c4d4a..00000000000000 --- a/packages/rspack/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { formatFiles, Tree } from '@nx/devkit'; -import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package'; - -export default async function replacePackage(tree: Tree): Promise { - await replaceNrwlPackageWithNxPackage(tree, '@nrwl/rspack', '@nx/rspack'); - - await formatFiles(tree); -} diff --git a/packages/rspack/src/utils/module-federation/remotes.ts b/packages/rspack/src/utils/module-federation/remotes.ts index de98778fb9754a..8c000da93f0bec 100644 --- a/packages/rspack/src/utils/module-federation/remotes.ts +++ b/packages/rspack/src/utils/module-federation/remotes.ts @@ -18,7 +18,8 @@ export function mapRemotes( for (const remote of remotes) { if (Array.isArray(remote)) { - mappedRemotes[remote[0]] = handleArrayRemote(remote, remoteEntryExt); + const remoteName = normalizeRemoteName(remote[0]); + mappedRemotes[remoteName] = handleArrayRemote(remote, remoteEntryExt); } else if (typeof remote === 'string') { mappedRemotes[remote] = handleStringRemote(remote, determineRemoteUrl); } @@ -32,7 +33,8 @@ function handleArrayRemote( remote: [string, string], remoteEntryExt: 'js' | 'mjs' ): string { - const [remoteName, remoteLocation] = remote; + let [remoteName, remoteLocation] = remote; + remoteName = normalizeRemoteName(remoteName); const remoteLocationExt = extname(remoteLocation); // If remote location already has .js or .mjs extension @@ -82,7 +84,8 @@ export function mapRemotesForSSR( for (const remote of remotes) { if (Array.isArray(remote)) { - const [remoteName, remoteLocation] = remote; + let [remoteName, remoteLocation] = remote; + remoteName = normalizeRemoteName(remoteName); const remoteLocationExt = extname(remoteLocation); mappedRemotes[remoteName] = `${remoteName}@${ ['.js', '.mjs'].includes(remoteLocationExt) @@ -94,9 +97,14 @@ export function mapRemotesForSSR( }/remoteEntry.${remoteEntryExt}` }`; } else if (typeof remote === 'string') { - mappedRemotes[remote] = `${remote}@${determineRemoteUrl(remote)}`; + const remoteName = normalizeRemoteName(remote); + mappedRemotes[remoteName] = `${remoteName}@${determineRemoteUrl(remote)}`; } } return mappedRemotes; } + +function normalizeRemoteName(remote: string): string { + return remote.replace(/-/g, '_'); +} diff --git a/packages/rspack/src/utils/module-federation/with-module-federation/with-module-federation-ssr.ts b/packages/rspack/src/utils/module-federation/with-module-federation/with-module-federation-ssr.ts index b6fa214ae4fce0..492aa612a33057 100644 --- a/packages/rspack/src/utils/module-federation/with-module-federation/with-module-federation-ssr.ts +++ b/packages/rspack/src/utils/module-federation/with-module-federation/with-module-federation-ssr.ts @@ -31,7 +31,7 @@ export async function withModuleFederationForSSR( // eslint-disable-next-line @typescript-eslint/no-var-requires new (require('@module-federation/enhanced/rspack').ModuleFederationPlugin)( { - name: options.name, + name: options.name.replace(/-/g, '_'), filename: 'remoteEntry.js', exposes: options.exposes, remotes: mappedRemotes, diff --git a/packages/rspack/src/utils/module-federation/with-module-federation/with-module-federation.ts b/packages/rspack/src/utils/module-federation/with-module-federation/with-module-federation.ts index 7e3245a76652bc..7f43b02c63cd4c 100644 --- a/packages/rspack/src/utils/module-federation/with-module-federation/with-module-federation.ts +++ b/packages/rspack/src/utils/module-federation/with-module-federation/with-module-federation.ts @@ -55,7 +55,7 @@ export async function withModuleFederation( config.plugins.push( new ModuleFederationPlugin({ - name: options.name, + name: options.name.replace(/-/g, '_'), filename: 'remoteEntry.js', exposes: options.exposes, remotes: mappedRemotes, diff --git a/packages/storybook/migrations.json b/packages/storybook/migrations.json index fd69b51476d9f4..8b1ec9aefc278a 100644 --- a/packages/storybook/migrations.json +++ b/packages/storybook/migrations.json @@ -1,29 +1,5 @@ { "generators": { - "update-16-0-0-add-nx-packages": { - "cli": "nx", - "version": "16.0.0-beta.1", - "description": "Replace @nrwl/storybook with @nx/storybook", - "implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages" - }, - "update-16-0-0-migrate-7": { - "cli": "nx", - "version": "16.0.0-beta.1", - "description": "Update workspace to use Storybook v7", - "implementation": "./src/migrations/update-16-0-0/update-sb-7" - }, - "update-16-1-0": { - "cli": "nx", - "version": "16.1.0-beta.0", - "description": "Ignore @nx/react/plugins/storybook in Storybook eslint rules.", - "factory": "./src/migrations/update-16-1-0/eslint-ignore-react-plugin" - }, - "update-16-5-0": { - "cli": "nx", - "version": "16.5.0-beta.0", - "description": "Move .storybook/tsconfig.json to tsconfig.storybook.json for non-Angular projects.", - "factory": "./src/migrations/update-16-5-0/move-storybook-tsconfig" - }, "update-19-6-0-add-nx-packages": { "cli": "nx", "version": "19.6.0-beta.0", @@ -272,593 +248,6 @@ } } }, - "16.7.0": { - "version": "16.7.0-beta.3", - "packages": { - "@storybook/test-runner": { - "version": "^0.13.0", - "alwaysAddToPackageJson": false - }, - "@storybook/core-server": { - "version": "^7.2.1", - "alwaysAddToPackageJson": false - }, - "@storybook/angular": { - "version": "^7.2.1", - "alwaysAddToPackageJson": false - }, - "@storybook/react": { - "version": "^7.2.1", - "alwaysAddToPackageJson": false - }, - "@storybook/react-vite": { - "version": "^7.2.1", - "alwaysAddToPackageJson": false - }, - "@storybook/react-webpack5": { - "version": "^7.2.1", - "alwaysAddToPackageJson": false - }, - "@storybook/web-components-vite": { - "version": "^7.2.1", - "alwaysAddToPackageJson": false - }, - "@storybook/web-components-webpack5": { - "version": "^7.2.1", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-a11y": { - "version": "^7.2.1", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-actions": { - "version": "^7.2.1", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-backgrounds": { - "version": "^7.2.1", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-controls": { - "version": "^7.2.1", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-docs": { - "version": "^7.2.1", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-essentials": { - "version": "^7.2.1", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-interactions": { - "version": "^7.2.1", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-mdx-gfm": { - "version": "^7.2.1", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-highlight": { - "version": "^7.2.1", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-jest": { - "version": "^7.2.1", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-links": { - "version": "^7.2.1", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-measure": { - "version": "^7.2.1", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-outline": { - "version": "^7.2.1", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-storyshots": { - "version": "^7.2.1", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-storyshots-puppeteer": { - "version": "^7.2.1", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-storysource": { - "version": "^7.2.1", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-toolbars": { - "version": "^7.2.1", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-viewport": { - "version": "^7.2.1", - "alwaysAddToPackageJson": false - } - } - }, - "16.6.0": { - "version": "16.6.0-beta.6", - "packages": { - "@storybook/test-runner": { - "version": "^0.11.0", - "alwaysAddToPackageJson": false - }, - "@storybook/core-server": { - "version": "^7.1.0", - "alwaysAddToPackageJson": false - }, - "@storybook/angular": { - "version": "^7.1.0", - "alwaysAddToPackageJson": false - }, - "@storybook/react": { - "version": "^7.1.0", - "alwaysAddToPackageJson": false - }, - "@storybook/react-vite": { - "version": "^7.1.0", - "alwaysAddToPackageJson": false - }, - "@storybook/react-webpack5": { - "version": "^7.1.0", - "alwaysAddToPackageJson": false - }, - "@storybook/web-components-vite": { - "version": "^7.1.0", - "alwaysAddToPackageJson": false - }, - "@storybook/web-components-webpack5": { - "version": "^7.1.0", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-a11y": { - "version": "^7.1.0", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-actions": { - "version": "^7.1.0", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-backgrounds": { - "version": "^7.1.0", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-controls": { - "version": "^7.1.0", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-docs": { - "version": "^7.1.0", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-essentials": { - "version": "^7.1.0", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-interactions": { - "version": "^7.1.0", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-mdx-gfm": { - "version": "^7.1.0", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-highlight": { - "version": "^7.1.0", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-jest": { - "version": "^7.1.0", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-links": { - "version": "^7.1.0", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-measure": { - "version": "^7.1.0", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-outline": { - "version": "^7.1.0", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-storyshots": { - "version": "^7.1.0", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-storyshots-puppeteer": { - "version": "^7.1.0", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-storysource": { - "version": "^7.1.0", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-toolbars": { - "version": "^7.1.0", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-viewport": { - "version": "^7.1.0", - "alwaysAddToPackageJson": false - } - } - }, - "16.5.0": { - "version": "16.5.0-beta.0", - "requires": { - "@storybook/core-server": ">=7.0.0 <7.0.24" - }, - "packages": { - "@storybook/core-server": { - "version": "^7.0.24", - "alwaysAddToPackageJson": false - }, - "@storybook/angular": { - "version": "^7.0.24", - "alwaysAddToPackageJson": false - }, - "@storybook/react": { - "version": "^7.0.24", - "alwaysAddToPackageJson": false - }, - "@storybook/web-components-vite": { - "version": "^7.0.24", - "alwaysAddToPackageJson": false - }, - "@storybook/web-components-webpack5": { - "version": "^7.0.24", - "alwaysAddToPackageJson": false - }, - "@storybook/builder-vite": { - "version": "^7.0.24", - "alwaysAddToPackageJson": false - }, - "@storybook/builder-webpack5": { - "version": "^7.0.24", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-a11y": { - "version": "^7.0.24", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-actions": { - "version": "^7.0.24", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-backgrounds": { - "version": "^7.0.24", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-controls": { - "version": "^7.0.24", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-docs": { - "version": "^7.0.24", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-essentials": { - "version": "^7.0.24", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-mdx-gfm": { - "version": "^7.0.24", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-highlight": { - "version": "^7.0.24", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-interactions": { - "version": "^7.0.24", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-jest": { - "version": "^7.0.24", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-links": { - "version": "^7.0.24", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-measure": { - "version": "^7.0.24", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-outline": { - "version": "^7.0.24", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-storyshots": { - "version": "^7.0.24", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-storyshots-puppeteer": { - "version": "^7.0.24", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-storysource": { - "version": "^7.0.24", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-toolbars": { - "version": "^7.0.24", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-viewport": { - "version": "^7.0.24", - "alwaysAddToPackageJson": false - } - } - }, - "16.1.3": { - "version": "16.1.3-beta.0", - "requires": { - "@storybook/core-server": ">=7.0.0 <7.0.9" - }, - "packages": { - "@storybook/core-server": { - "version": "^7.0.9", - "alwaysAddToPackageJson": false - }, - "@storybook/angular": { - "version": "^7.0.9", - "alwaysAddToPackageJson": false - }, - "@storybook/react": { - "version": "^7.0.9", - "alwaysAddToPackageJson": false - }, - "@storybook/web-components-vite": { - "version": "^7.0.9", - "alwaysAddToPackageJson": false - }, - "@storybook/web-components-webpack5": { - "version": "^7.0.9", - "alwaysAddToPackageJson": false - }, - "@storybook/builder-vite": { - "version": "^7.0.9", - "alwaysAddToPackageJson": false - }, - "@storybook/builder-webpack5": { - "version": "^7.0.9", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-a11y": { - "version": "^7.0.9", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-actions": { - "version": "^7.0.9", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-backgrounds": { - "version": "^7.0.9", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-controls": { - "version": "^7.0.9", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-docs": { - "version": "^7.0.9", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-essentials": { - "version": "^7.0.9", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-mdx-gfm": { - "version": "^7.0.9", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-highlight": { - "version": "^7.0.9", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-interactions": { - "version": "^7.0.9", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-jest": { - "version": "^7.0.9", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-links": { - "version": "^7.0.9", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-measure": { - "version": "^7.0.9", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-outline": { - "version": "^7.0.9", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-storyshots": { - "version": "^7.0.9", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-storyshots-puppeteer": { - "version": "^7.0.9", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-storysource": { - "version": "^7.0.9", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-toolbars": { - "version": "^7.0.9", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-viewport": { - "version": "^7.0.9", - "alwaysAddToPackageJson": false - } - } - }, - "16.1.0": { - "version": "16.1.0-beta.0", - "requires": { - "@storybook/core-server": ">=7.0.0 <7.0.8" - }, - "packages": { - "eslint-plugin-storybook": { - "version": "^0.6.12", - "alwaysAddToPackageJson": false - }, - "@storybook/core-server": { - "version": "^7.0.8", - "alwaysAddToPackageJson": false - }, - "@storybook/angular": { - "version": "^7.0.8", - "alwaysAddToPackageJson": false - }, - "@storybook/react": { - "version": "^7.0.8", - "alwaysAddToPackageJson": false - }, - "@storybook/web-components-vite": { - "version": "^7.0.8", - "alwaysAddToPackageJson": false - }, - "@storybook/web-components-webpack5": { - "version": "^7.0.8", - "alwaysAddToPackageJson": false - }, - "@storybook/builder-vite": { - "version": "^7.0.8", - "alwaysAddToPackageJson": false - }, - "@storybook/builder-webpack5": { - "version": "^7.0.8", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-a11y": { - "version": "^7.0.8", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-actions": { - "version": "^7.0.8", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-backgrounds": { - "version": "^7.0.8", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-controls": { - "version": "^7.0.8", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-docs": { - "version": "^7.0.8", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-essentials": { - "version": "^7.0.8", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-mdx-gfm": { - "version": "^7.0.8", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-highlight": { - "version": "^7.0.8", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-interactions": { - "version": "^7.0.8", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-jest": { - "version": "^7.0.8", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-links": { - "version": "^7.0.8", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-measure": { - "version": "^7.0.8", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-outline": { - "version": "^7.0.8", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-storyshots": { - "version": "^7.0.8", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-storyshots-puppeteer": { - "version": "^7.0.8", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-storysource": { - "version": "^7.0.8", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-toolbars": { - "version": "^7.0.8", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-viewport": { - "version": "^7.0.8", - "alwaysAddToPackageJson": false - }, - "@storybook/react-native": { - "version": "^6.5.3", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-ondevice-actions": { - "version": "^6.5.3", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-ondevice-backgrounds": { - "version": "^6.5.3", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-ondevice-controls": { - "version": "^6.5.3", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-ondevice-notes": { - "version": "^6.5.3", - "alwaysAddToPackageJson": false - } - } - }, - "16.0.0": { - "version": "16.0.0-beta.1", - "packages": { - "@storybook/core-server": { - "version": "^7.0.5", - "alwaysAddToPackageJson": false - }, - "@storybook/angular": { - "version": "^7.0.5", - "alwaysAddToPackageJson": false - }, - "@storybook/react": { - "version": "^7.0.5", - "alwaysAddToPackageJson": false - }, - "@storybook/addon-essentials": { - "version": "^7.0.5", - "alwaysAddToPackageJson": false - } - } - }, "18.2.0": { "version": "18.2.0-beta.1", "packages": { diff --git a/packages/storybook/src/generators/configuration/configuration.ts b/packages/storybook/src/generators/configuration/configuration.ts index 8fd73406d42d0d..43d2233dc11e9c 100644 --- a/packages/storybook/src/generators/configuration/configuration.ts +++ b/packages/storybook/src/generators/configuration/configuration.ts @@ -9,6 +9,7 @@ import { Tree, } from '@nx/devkit'; import { initGenerator as jsInitGenerator } from '@nx/js'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { StorybookConfigureSchema } from './schema'; import { initGenerator } from '../init/init'; @@ -59,6 +60,8 @@ export async function configurationGeneratorInternal( tree: Tree, rawSchema: StorybookConfigureSchema ) { + assertNotUsingTsSolutionSetup(tree, 'storybook', 'configuration'); + const storybookMajor = storybookMajorVersion(); if (storybookMajor > 0 && storybookMajor === 6) { throw new Error(pleaseUpgrade()); diff --git a/packages/storybook/src/generators/cypress-project/cypress-project.ts b/packages/storybook/src/generators/cypress-project/cypress-project.ts index ee2af4b0cdaa57..a05185f061d7aa 100644 --- a/packages/storybook/src/generators/cypress-project/cypress-project.ts +++ b/packages/storybook/src/generators/cypress-project/cypress-project.ts @@ -15,6 +15,7 @@ import { } from '@nx/devkit'; import { Linter, LinterType } from '@nx/eslint'; import { determineProjectNameAndRootOptions } from '@nx/devkit/src/generators/project-name-and-root-utils'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { join } from 'path'; import { safeFileDelete } from '../../utils/utilities'; @@ -34,6 +35,8 @@ export async function cypressProjectGenerator( tree: Tree, schema: CypressConfigureSchema ) { + assertNotUsingTsSolutionSetup(tree, 'cypress', 'cypress-project'); + logger.warn( `Use 'interactionTests' instead when running '@nx/storybook:configuration'. This generator will be removed in v21.` ); diff --git a/packages/storybook/src/generators/init/init.ts b/packages/storybook/src/generators/init/init.ts index 452031928ea725..f6c77b871c2df4 100644 --- a/packages/storybook/src/generators/init/init.ts +++ b/packages/storybook/src/generators/init/init.ts @@ -11,6 +11,7 @@ import { updateNxJson, } from '@nx/devkit'; import { addPluginV1 } from '@nx/devkit/src/utils/add-plugin'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { gte } from 'semver'; import { createNodes } from '../../plugins/plugin'; import { @@ -95,6 +96,8 @@ export function initGenerator(tree: Tree, schema: Schema) { } export async function initGeneratorInternal(tree: Tree, schema: Schema) { + assertNotUsingTsSolutionSetup(tree, 'storybook', 'init'); + const nxJson = readNxJson(tree); const addPluginDefault = process.env.NX_ADD_PLUGINS !== 'false' && diff --git a/packages/storybook/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts b/packages/storybook/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts deleted file mode 100644 index 741918e260e60b..00000000000000 --- a/packages/storybook/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Tree, readJson, updateJson } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import replacePackage from './update-16-0-0-add-nx-packages'; - -describe('update-16-0-0-add-nx-packages', () => { - let tree: Tree; - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - - updateJson(tree, 'package.json', (json) => { - json.devDependencies['@nrwl/storybook'] = '16.0.0'; - return json; - }); - }); - - it('should remove the dependency on @nrwl/storybook', async () => { - await replacePackage(tree); - - expect( - readJson(tree, 'package.json').dependencies['@nrwl/storybook'] - ).not.toBeDefined(); - expect( - readJson(tree, 'package.json').devDependencies['@nrwl/storybook'] - ).not.toBeDefined(); - }); - - it('should add a dependency on @nx/storybook', async () => { - await replacePackage(tree); - - const packageJson = readJson(tree, 'package.json'); - const newDependencyVersion = - packageJson.devDependencies['@nx/storybook'] ?? - packageJson.dependencies['@nx/storybook']; - - expect(newDependencyVersion).toBeDefined(); - }); -}); diff --git a/packages/storybook/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts b/packages/storybook/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts deleted file mode 100644 index 52e070036430a8..00000000000000 --- a/packages/storybook/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Tree, formatFiles } from '@nx/devkit'; -import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package'; - -export default async function replacePackage(tree: Tree): Promise { - await replaceNrwlPackageWithNxPackage( - tree, - '@nrwl/storybook', - '@nx/storybook' - ); - - await formatFiles(tree); -} diff --git a/packages/storybook/src/migrations/update-16-0-0/update-sb-7.ts b/packages/storybook/src/migrations/update-16-0-0/update-sb-7.ts deleted file mode 100644 index 2c8b3f66b05e0e..00000000000000 --- a/packages/storybook/src/migrations/update-16-0-0/update-sb-7.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Tree } from '@nx/devkit'; -import { output } from 'nx/src/utils/output'; -import migrate7Generator from '../../generators/migrate-7/migrate-7'; -import { storybookMajorVersion } from '../../utils/utilities'; - -export default async function changeStorybookTargets(tree: Tree) { - const storybookVersion = storybookMajorVersion(); - if (!storybookVersion) { - /** - * This just checks if Storybook is installed in the workspace. - * The thing here is that during the previous step of the migration, - * during packageJsonUpdates, Nx has already set Storybook - * to version 7, if Storybook exists in the workspace. - * So, it makes no sense here to check if the version is - * 7, because it will always be. - */ - return; - } - - output.log({ - title: 'Migrating Storybook to v7', - bodyLines: [ - `🚀 This migration will update your Storybook configuration to v7.`, - `It will call the @nx/storybook:migrate-7 generator for you.`, - `You can read more about the migration and how this generator works here:`, - `https://nx.dev/nx-api/storybook/generators/migrate-7`, - ], - }); - return migrate7Generator(tree, { autoAcceptAllPrompts: true }); -} diff --git a/packages/storybook/src/migrations/update-16-1-0/eslint-ignore-react-plugin.spec.ts b/packages/storybook/src/migrations/update-16-1-0/eslint-ignore-react-plugin.spec.ts deleted file mode 100644 index 7cdae11d3cd53a..00000000000000 --- a/packages/storybook/src/migrations/update-16-1-0/eslint-ignore-react-plugin.spec.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { - addProjectConfiguration, - ProjectConfiguration, - readJson, - Tree, - updateJson, -} from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import * as variousProjects from './test-configs/various-configs.json'; -import eslintIgnoreReactPlugin from './eslint-ignore-react-plugin'; - -describe('Ignore @nx/react/plugins/storybook in Storybook eslint plugin', () => { - let tree: Tree; - - beforeEach(async () => { - tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); - addProjectConfiguration( - tree, - variousProjects['main-vite'].name, - variousProjects['main-vite'] as ProjectConfiguration - ); - tree.write('apps/main-vite/tsconfig.json', `{}`); - tree.write( - `apps/main-vite/.storybook/main.js`, - ` - module.exports = { - stories: ['../src/lib/**/*.stories.@(mdx|js|jsx|ts|tsx)'], - addons: ['@storybook/addon-essentials'], - framework: { - name: '@storybook/react-vite', - options: {}, - }, - }; - ` - ); - addProjectConfiguration( - tree, - variousProjects['main-webpack'].name, - variousProjects['main-webpack'] as ProjectConfiguration - ); - - if (!tree.exists('.eslintrc.json')) { - tree.write('.eslintrc.json', `{}`); - } - }); - - it('should not ignore the plugin if it is not used', async () => { - await eslintIgnoreReactPlugin(tree); - const eslintConfig = readJson(tree, '.eslintrc.json'); - expect(eslintConfig).toEqual({}); - expect(eslintConfig.rules).toBeUndefined(); - }); - - it('should not ignore the plugin if "plugin:storybook/recommended" is not included', async () => { - tree.write('apps/main-webpack/tsconfig.json', `{}`); - tree.write( - `apps/main-webpack/.storybook/main.js`, - ` - module.exports = { - stories: ['../src/lib/**/*.stories.@(mdx|js|jsx|ts|tsx)'], - addons: ['@storybook/addon-essentials', '@nx/react/plugins/storybook'], - framework: { - name: '@storybook/react-webpack5', - options: {}, - }, - }; - ` - ); - - await eslintIgnoreReactPlugin(tree); - - const eslintConfig = readJson(tree, '.eslintrc.json'); - expect(eslintConfig).toEqual({}); - expect(eslintConfig.rules).toBeUndefined(); - }); - - it(`should add ignore @nx/react/plugins/storybook to eslint config`, async () => { - tree.write('apps/main-webpack/tsconfig.json', `{}`); - tree.write( - `apps/main-webpack/.storybook/main.js`, - ` - module.exports = { - stories: ['../src/lib/**/*.stories.@(mdx|js|jsx|ts|tsx)'], - addons: ['@storybook/addon-essentials', '@nx/react/plugins/storybook'], - framework: { - name: '@storybook/react-webpack5', - options: {}, - }, - }; - ` - ); - - updateJson(tree, '.eslintrc.json', (json) => { - json.extends ??= []; - json.extends.push('plugin:storybook/recommended'); - return json; - }); - - await eslintIgnoreReactPlugin(tree); - - const eslintConfig = readJson(tree, '.eslintrc.json'); - expect(eslintConfig.rules).toHaveProperty( - 'storybook/no-uninstalled-addons' - ); - - expect(eslintConfig.rules['storybook/no-uninstalled-addons']).toMatchObject( - [ - 'error', - { - ignore: ['@nx/react/plugins/storybook'], - }, - ] - ); - }); -}); diff --git a/packages/storybook/src/migrations/update-16-1-0/eslint-ignore-react-plugin.ts b/packages/storybook/src/migrations/update-16-1-0/eslint-ignore-react-plugin.ts deleted file mode 100644 index eeb6d8a8cc528a..00000000000000 --- a/packages/storybook/src/migrations/update-16-1-0/eslint-ignore-react-plugin.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { - getProjects, - joinPathFragments, - Tree, - formatFiles, - updateJson, -} from '@nx/devkit'; - -export default async function (tree: Tree) { - const projects = getProjects(tree); - const reactPlugin = '@nx/react/plugins/storybook'; - let shouldIgnoreReactPlugin = false; - - for (const [, config] of projects) { - let sbConfigPath = joinPathFragments(config.root, '.storybook/main.ts'); - - if (!tree.exists(sbConfigPath)) { - sbConfigPath = joinPathFragments(config.root, '.storybook/main.js'); - } - - if (!tree.exists(sbConfigPath)) { - continue; - } - - const sbConfig = tree.read(sbConfigPath, 'utf-8'); - if (sbConfig.includes(reactPlugin)) { - shouldIgnoreReactPlugin = true; - break; - } - } - - if (shouldIgnoreReactPlugin && tree.exists('.eslintrc.json')) { - updateJson(tree, '.eslintrc.json', (json) => { - if (json.extends?.includes('plugin:storybook/recommended')) { - json.rules ??= {}; - json.rules['storybook/no-uninstalled-addons'] = [ - 'error', - { - ignore: ['@nx/react/plugins/storybook'], - }, - ]; - } - return json; - }); - } - - await formatFiles(tree); -} diff --git a/packages/storybook/src/migrations/update-16-5-0/__snapshots__/move-storybook-tsconfig.spec.ts.snap b/packages/storybook/src/migrations/update-16-5-0/__snapshots__/move-storybook-tsconfig.spec.ts.snap deleted file mode 100644 index 8fa23d4051066d..00000000000000 --- a/packages/storybook/src/migrations/update-16-5-0/__snapshots__/move-storybook-tsconfig.spec.ts.snap +++ /dev/null @@ -1,206 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Ignore @nx/react/plugins/storybook in Storybook eslint plugin should update Storybook tsconfig.json 1`] = ` -"{ - "extends": "./tsconfig.json", - "compilerOptions": { - "emitDecoratorMetadata": true, - "outDir": "" - }, - "files": [ - "../../node_modules/@nx/react/typings/styled-jsx.d.ts", - "../../node_modules/@nx/react/typings/cssmodule.d.ts", - "../../node_modules/@nx/react/typings/image.d.ts" - ], - "exclude": [ - "src/**/*.spec.ts", - "src/**/*.spec.js", - "src/**/*.spec.tsx", - "src/**/*.spec.jsx" - ], - "include": [ - "src/**/*.stories.ts", - "src/**/*.stories.js", - "src/**/*.stories.jsx", - "src/**/*.stories.tsx", - "src/**/*.stories.mdx", - ".storybook/*.js" - ] -} -" -`; - -exports[`Ignore @nx/react/plugins/storybook in Storybook eslint plugin should update Storybook tsconfig.json 2`] = ` -"{ - "extends": "./tsconfig.json", - "compilerOptions": { - "emitDecoratorMetadata": true, - "outDir": "" - }, - "files": [ - "../../node_modules/@nx/react/typings/styled-jsx.d.ts", - "../../node_modules/@nx/react/typings/cssmodule.d.ts", - "../../node_modules/@nx/react/typings/image.d.ts" - ], - "exclude": [ - "src/**/*.spec.ts", - "src/**/*.spec.js", - "src/**/*.spec.tsx", - "src/**/*.spec.jsx" - ], - "include": [ - "src/**/*.stories.ts", - "src/**/*.stories.js", - "src/**/*.stories.jsx", - "src/**/*.stories.tsx", - "src/**/*.stories.mdx", - ".storybook/*.js" - ] -} -" -`; - -exports[`Ignore @nx/react/plugins/storybook in Storybook eslint plugin should update Storybook tsconfig.json 3`] = ` -"{ - "extends": "./tsconfig.json", - "compilerOptions": { - "emitDecoratorMetadata": true, - "outDir": "" - }, - "files": [ - "../../../../../node_modules/@nx/react/typings/styled-jsx.d.ts", - "../../../../../node_modules/@nx/react/typings/cssmodule.d.ts", - "../../../../../node_modules/@nx/react/typings/image.d.ts" - ], - "exclude": [ - "src/**/*.spec.ts", - "src/**/*.spec.js", - "src/**/*.spec.tsx", - "src/**/*.spec.jsx" - ], - "include": [ - "src/**/*.stories.ts", - "src/**/*.stories.js", - "src/**/*.stories.jsx", - "src/**/*.stories.tsx", - "src/**/*.stories.mdx", - ".storybook/*.js" - ] -} -" -`; - -exports[`Ignore @nx/react/plugins/storybook in Storybook eslint plugin should update nx.json inputs 1`] = ` -{ - "affected": { - "defaultBase": "main", - }, - "namedInputs": { - "production": [ - "default", - "!{projectRoot}/**/*.stories.@(js|jsx|ts|tsx|mdx)", - "!{projectRoot}/.storybook/**/*", - "!{projectRoot}/tsconfig.storybook.json", - ], - }, - "targetDefaults": { - "build": { - "cache": true, - }, - "build-storybook": { - "inputs": [ - "default", - "^production", - "{projectRoot}/.storybook/**/*", - "{projectRoot}/tsconfig.storybook.json", - ], - }, - "lint": { - "cache": true, - }, - }, -} -`; - -exports[`Ignore @nx/react/plugins/storybook in Storybook eslint plugin should update projects tsconfig.json 1`] = ` -"{ - "compilerOptions": { - "jsx": "react-jsx", - "allowJs": false, - "esModuleInterop": false, - "allowSyntheticDefaultImports": true, - "strict": true - }, - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.app.json" - }, - { - "path": "./tsconfig.spec.json" - }, - { - "path": "./tsconfig.storybook.json" - } - ], - "extends": "../../tsconfig.base.json" -} -" -`; - -exports[`Ignore @nx/react/plugins/storybook in Storybook eslint plugin should update projects tsconfig.json 2`] = ` -"{ - "compilerOptions": { - "jsx": "react-jsx", - "allowJs": false, - "esModuleInterop": false, - "allowSyntheticDefaultImports": true, - "strict": true, - "types": ["vite/client", "vitest"] - }, - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.app.json" - }, - { - "path": "./tsconfig.spec.json" - }, - { - "path": "./tsconfig.storybook.json" - } - ], - "extends": "../../tsconfig.base.json" -} -" -`; - -exports[`Ignore @nx/react/plugins/storybook in Storybook eslint plugin should update projects tsconfig.json 3`] = ` -"{ - "compilerOptions": { - "jsx": "react-jsx", - "allowJs": false, - "esModuleInterop": false, - "allowSyntheticDefaultImports": true, - "strict": true, - "types": ["vite/client", "vitest"] - }, - "files": [], - "include": [], - "references": [ - { - "path": "./tsconfig.app.json" - }, - { - "path": "./tsconfig.spec.json" - }, - { - "path": "./tsconfig.storybook.json" - } - ], - "extends": "../../../../../tsconfig.base.json" -} -" -`; diff --git a/packages/storybook/src/migrations/update-16-5-0/move-storybook-tsconfig.spec.ts b/packages/storybook/src/migrations/update-16-5-0/move-storybook-tsconfig.spec.ts deleted file mode 100644 index a4748a2b5f2c47..00000000000000 --- a/packages/storybook/src/migrations/update-16-5-0/move-storybook-tsconfig.spec.ts +++ /dev/null @@ -1,243 +0,0 @@ -import { - NxJsonConfiguration, - ProjectConfiguration, - Tree, - addProjectConfiguration, - updateJson, - readNxJson, -} from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import * as variousProjects from './test-configs/storybook-projects.json'; -import moveStorybookTsconfig from './move-storybook-tsconfig'; - -describe('Ignore @nx/react/plugins/storybook in Storybook eslint plugin', () => { - let tree: Tree; - - beforeEach(async () => { - tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); - updateJson(tree, 'nx.json', (json) => { - json.namedInputs = { - production: ['default'], - }; - return json; - }); - setupProjects(tree); - await moveStorybookTsconfig(tree); - }); - - it('should update projects tsconfig.json', async () => { - expect( - tree.read(`apps/webpack-app/tsconfig.json`).toString() - ).toMatchSnapshot(); - expect( - tree.read(`apps/vite-app/tsconfig.json`).toString() - ).toMatchSnapshot(); - expect( - tree.read(`apps/my/custom/place/nested-app/tsconfig.json`).toString() - ).toMatchSnapshot(); - }); - - it('should update Storybook tsconfig.json', async () => { - expect( - tree.read(`apps/webpack-app/tsconfig.storybook.json`).toString() - ).toMatchSnapshot(); - expect( - tree.read(`apps/vite-app/tsconfig.storybook.json`).toString() - ).toMatchSnapshot(); - expect( - tree - .read(`apps/my/custom/place/nested-app/tsconfig.storybook.json`) - .toString() - ).toMatchSnapshot(); - }); - - it('should delete old Storybook tsconfig.json', async () => { - expect(tree.exists(`apps/vite-app/.storybook/tsconfig.json`)).toBeFalsy(); - expect( - tree.exists(`apps/webpack-app/.storybook/tsconfig.json`) - ).toBeFalsy(); - expect( - tree.exists(`apps/my/custom/place/nested-app/.storybook/tsconfig.json`) - ).toBeFalsy(); - }); - - it('should update nx.json inputs', () => { - expect(readNxJson(tree)).toMatchSnapshot(); - }); -}); - -function setupProjects(tree: Tree) { - for (const [name, project] of Object.entries(variousProjects)) { - addProjectConfiguration(tree, name, project as ProjectConfiguration); - } - tree.write( - `apps/my/custom/place/nested-app/tsconfig.json`, - JSON.stringify({ - compilerOptions: { - jsx: 'react-jsx', - allowJs: false, - esModuleInterop: false, - allowSyntheticDefaultImports: true, - strict: true, - types: ['vite/client', 'vitest'], - }, - files: [], - include: [], - references: [ - { - path: './tsconfig.app.json', - }, - { - path: './tsconfig.spec.json', - }, - { - path: './.storybook/tsconfig.json', - }, - ], - extends: '../../../../../tsconfig.base.json', - }) - ); - tree.write( - `apps/webpack-app/tsconfig.json`, - JSON.stringify({ - compilerOptions: { - jsx: 'react-jsx', - allowJs: false, - esModuleInterop: false, - allowSyntheticDefaultImports: true, - strict: true, - }, - files: [], - include: [], - references: [ - { - path: './tsconfig.app.json', - }, - { - path: './tsconfig.spec.json', - }, - { - path: './.storybook/tsconfig.json', - }, - ], - extends: '../../tsconfig.base.json', - }) - ); - tree.write( - 'apps/vite-app/tsconfig.json', - JSON.stringify({ - compilerOptions: { - jsx: 'react-jsx', - allowJs: false, - esModuleInterop: false, - allowSyntheticDefaultImports: true, - strict: true, - types: ['vite/client', 'vitest'], - }, - files: [], - include: [], - references: [ - { - path: './tsconfig.app.json', - }, - { - path: './tsconfig.spec.json', - }, - { - path: './.storybook/tsconfig.json', - }, - ], - extends: '../../tsconfig.base.json', - }) - ); - - tree.write( - 'apps/my/custom/place/nested-app/.storybook/tsconfig.json', - JSON.stringify({ - extends: '../tsconfig.json', - compilerOptions: { - emitDecoratorMetadata: true, - outDir: '', - }, - files: [ - '../../../../../../node_modules/@nx/react/typings/styled-jsx.d.ts', - '../../../../../../node_modules/@nx/react/typings/cssmodule.d.ts', - '../../../../../../node_modules/@nx/react/typings/image.d.ts', - ], - exclude: [ - '../**/*.spec.ts', - '../**/*.spec.js', - '../**/*.spec.tsx', - '../**/*.spec.jsx', - ], - include: [ - '../src/**/*.stories.ts', - '../src/**/*.stories.js', - '../src/**/*.stories.jsx', - '../src/**/*.stories.tsx', - '../src/**/*.stories.mdx', - '*.js', - ], - }) - ); - - tree.write( - 'apps/vite-app/.storybook/tsconfig.json', - JSON.stringify({ - extends: '../tsconfig.json', - compilerOptions: { - emitDecoratorMetadata: true, - outDir: '', - }, - files: [ - '../../../node_modules/@nx/react/typings/styled-jsx.d.ts', - '../../../node_modules/@nx/react/typings/cssmodule.d.ts', - '../../../node_modules/@nx/react/typings/image.d.ts', - ], - exclude: [ - '../**/*.spec.ts', - '../**/*.spec.js', - '../**/*.spec.tsx', - '../**/*.spec.jsx', - ], - include: [ - '../src/**/*.stories.ts', - '../src/**/*.stories.js', - '../src/**/*.stories.jsx', - '../src/**/*.stories.tsx', - '../src/**/*.stories.mdx', - '*.js', - ], - }) - ); - - tree.write( - 'apps/webpack-app/.storybook/tsconfig.json', - JSON.stringify({ - extends: '../tsconfig.json', - compilerOptions: { - emitDecoratorMetadata: true, - outDir: '', - }, - files: [ - '../../../node_modules/@nx/react/typings/styled-jsx.d.ts', - '../../../node_modules/@nx/react/typings/cssmodule.d.ts', - '../../../node_modules/@nx/react/typings/image.d.ts', - ], - exclude: [ - '../**/*.spec.ts', - '../**/*.spec.js', - '../**/*.spec.tsx', - '../**/*.spec.jsx', - ], - include: [ - '../src/**/*.stories.ts', - '../src/**/*.stories.js', - '../src/**/*.stories.jsx', - '../src/**/*.stories.tsx', - '../src/**/*.stories.mdx', - '*.js', - ], - }) - ); -} diff --git a/packages/storybook/src/migrations/update-16-5-0/move-storybook-tsconfig.ts b/packages/storybook/src/migrations/update-16-5-0/move-storybook-tsconfig.ts deleted file mode 100644 index baeea742ceacc0..00000000000000 --- a/packages/storybook/src/migrations/update-16-5-0/move-storybook-tsconfig.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { getProjects, joinPathFragments, Tree, formatFiles } from '@nx/devkit'; -import { forEachExecutorOptions } from '@nx/devkit/src/generators/executor-options-utils'; -import { - addStorybookToNamedInputs, - addStorybookToTargetDefaults, - renameAndMoveOldTsConfig, -} from '../../generators/configuration/lib/util-functions'; - -export default async function (tree: Tree) { - forEachExecutorOptions( - tree, - '@nx/storybook:storybook', - (options, projectName) => { - const projectConfiguration = getProjects(tree).get(projectName); - const projectRoot = projectConfiguration.root; - if (options?.['configDir'] === undefined) { - return; - } - - const pathToStorybookConfigFile = joinPathFragments( - options?.['configDir'], - 'tsconfig.json' - ); - - renameAndMoveOldTsConfig(projectRoot, pathToStorybookConfigFile, tree); - } - ); - - addStorybookToNamedInputs(tree); - addStorybookToTargetDefaults(tree, false); - await formatFiles(tree); -} diff --git a/packages/vite/migrations.json b/packages/vite/migrations.json index 4c54200bab4270..1280a6da694032 100644 --- a/packages/vite/migrations.json +++ b/packages/vite/migrations.json @@ -1,23 +1,5 @@ { "generators": { - "update-16-0-0-add-nx-packages": { - "cli": "nx", - "version": "16.0.0-beta.1", - "description": "Replace @nrwl/vite with @nx/vite", - "implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages" - }, - "update-16-4-1-test-file-config": { - "version": "16.4.1-beta.0", - "description": "Changes the testFile config in the vite:test exectutor from a string to an array of strings", - "cli": "nx", - "implementation": "./src/migrations/update-16-4-1-update-test-file-config/update-16-4-1-test-file-config" - }, - "16-6-0-change-ts-paths-plugin": { - "version": "16.6.0-beta.4", - "description": "Change vite-tsconfig-paths plugin for first party nx-vite-tsconfig-paths plugin", - "cli": "nx", - "implementation": "./src/migrations/update-16-6-0-change-ts-paths-plugin/change-ts-paths-plugin" - }, "move-target-defaults": { "version": "17.1.0-beta.2", "description": "Move target defaults", @@ -114,81 +96,6 @@ "alwaysAddToPackageJson": false } } - }, - "16.4.0-beta.7": { - "version": "16.4.0-beta.7", - "packages": { - "vite": { - "version": "^4.3.9", - "alwaysAddToPackageJson": false - } - } - }, - "16.4.0-beta.4": { - "version": "16.4.0-beta.4", - "packages": { - "@vitejs/plugin-react": { - "version": "^4.0.0", - "alwaysAddToPackageJson": false - }, - "@vitejs/plugin-react-swc": { - "version": "^3.3.2", - "alwaysAddToPackageJson": false - }, - "jsdom": { - "version": "~22.1.0", - "alwaysAddToPackageJson": false - }, - "vite-plugin-dts": { - "version": "~2.3.0", - "alwaysAddToPackageJson": false - }, - "vitest": { - "version": "^0.32.0", - "alwaysAddToPackageJson": false - }, - "@vitest/coverage-c8": { - "version": "^0.32.0", - "alwaysAddToPackageJson": false - }, - "@vitest/ui": { - "version": "^0.32.0", - "alwaysAddToPackageJson": false - }, - "@vitest/coverage-istanbul": { - "version": "^0.32.0", - "alwaysAddToPackageJson": false - } - } - }, - "16.1.0-beta.0": { - "version": "16.1.0-beta.0", - "packages": { - "vite": { - "version": "^4.3.4", - "alwaysAddToPackageJson": false - }, - "vite-tsconfig-paths": { - "version": "^4.2.0", - "alwaysAddToPackageJson": false - }, - "vitest": { - "version": "^0.31.0", - "alwaysAddToPackageJson": false - }, - "@vitest/coverage-c8": { - "version": "^0.31.0", - "alwaysAddToPackageJson": false - }, - "@vitest/ui": { - "version": "^0.31.0", - "alwaysAddToPackageJson": false - }, - "@vitest/coverage-istanbul": { - "version": "^0.31.0", - "alwaysAddToPackageJson": false - } - } } } } diff --git a/packages/vite/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts b/packages/vite/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts deleted file mode 100644 index 2d2cf0571de3b8..00000000000000 --- a/packages/vite/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Tree, readJson, updateJson } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import replacePackage from './update-16-0-0-add-nx-packages'; - -describe('update-16-0-0-add-nx-packages', () => { - let tree: Tree; - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - - updateJson(tree, 'package.json', (json) => { - json.devDependencies['@nrwl/vite'] = '16.0.0'; - return json; - }); - }); - - it('should remove the dependency on @nrwl/vite', async () => { - await replacePackage(tree); - - expect( - readJson(tree, 'package.json').dependencies['@nrwl/vite'] - ).not.toBeDefined(); - expect( - readJson(tree, 'package.json').devDependencies['@nrwl/vite'] - ).not.toBeDefined(); - }); - - it('should add a dependency on @nx/vite', async () => { - await replacePackage(tree); - - const packageJson = readJson(tree, 'package.json'); - const newDependencyVersion = - packageJson.devDependencies['@nx/vite'] ?? - packageJson.dependencies['@nx/vite']; - - expect(newDependencyVersion).toBeDefined(); - }); -}); diff --git a/packages/vite/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts b/packages/vite/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts deleted file mode 100644 index 8e629b564c3164..00000000000000 --- a/packages/vite/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Tree, formatFiles } from '@nx/devkit'; -import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package'; - -export default async function replacePackage(tree: Tree): Promise { - await replaceNrwlPackageWithNxPackage(tree, '@nrwl/vite', '@nx/vite'); - - await formatFiles(tree); -} diff --git a/packages/vite/src/migrations/update-16-4-1-update-test-file-config/update-16-4-1-test-file-config.spec.ts b/packages/vite/src/migrations/update-16-4-1-update-test-file-config/update-16-4-1-test-file-config.spec.ts deleted file mode 100644 index 12f47c52ec6a0c..00000000000000 --- a/packages/vite/src/migrations/update-16-4-1-update-test-file-config/update-16-4-1-test-file-config.spec.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import { - Tree, - addProjectConfiguration, - readProjectConfiguration, -} from '@nx/devkit'; - -import updateTestFileOption from './update-16-4-1-test-file-config'; - -describe('update-16-5-0-vite-test-file-config migration', () => { - let tree: Tree; - - beforeEach(() => { - tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); - }); - - it('should run successfully when testFile does not exist in the config', () => { - addProjectConfiguration(tree, 'vitest', { - root: 'vitest', - targets: { - test: { - executor: '@nx/vite:test', - options: { - ci: true, - watch: true, - }, - }, - }, - }); - updateTestFileOption(tree); - expect(readProjectConfiguration(tree, 'vitest')).toMatchInlineSnapshot(` - { - "$schema": "../node_modules/nx/schemas/project-schema.json", - "name": "vitest", - "root": "vitest", - "targets": { - "test": { - "executor": "@nx/vite:test", - "options": { - "ci": true, - "watch": true, - }, - }, - }, - } - `); - }); - - it('should run successfully when testFile exists in options and configurations', () => { - addProjectConfiguration(tree, 'vitest', { - root: 'vitest', - targets: { - test: { - executor: '@nx/vite:test', - options: { - testFile: 'test-file.ts', - config: 'vite.config.ts', - }, - configurations: { - one: { - testFile: 'test-file-one.ts', - ci: true, - }, - two: { - testFile: 'test-file-two.ts', - watch: true, - }, - }, - }, - }, - }); - updateTestFileOption(tree); - expect(readProjectConfiguration(tree, 'vitest')).toMatchInlineSnapshot(` - { - "$schema": "../node_modules/nx/schemas/project-schema.json", - "name": "vitest", - "root": "vitest", - "targets": { - "test": { - "configurations": { - "one": { - "ci": true, - "testFiles": [ - "test-file-one.ts", - ], - }, - "two": { - "testFiles": [ - "test-file-two.ts", - ], - "watch": true, - }, - }, - "executor": "@nx/vite:test", - "options": { - "config": "vite.config.ts", - "testFiles": [ - "test-file.ts", - ], - }, - }, - }, - } - `); - }); -}); diff --git a/packages/vite/src/migrations/update-16-4-1-update-test-file-config/update-16-4-1-test-file-config.ts b/packages/vite/src/migrations/update-16-4-1-update-test-file-config/update-16-4-1-test-file-config.ts deleted file mode 100644 index 64f59dc34c49b5..00000000000000 --- a/packages/vite/src/migrations/update-16-4-1-update-test-file-config/update-16-4-1-test-file-config.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Tree, getProjects, updateProjectConfiguration } from '@nx/devkit'; -import { forEachExecutorOptions } from '@nx/devkit/src/generators/executor-options-utils'; -import { VitestExecutorOptions } from '../../executors/test/schema'; - -type OldVitestExecutorOptions = Omit & { - testFile: string; -}; - -export default function update(tree: Tree) { - const projects = getProjects(tree); - - forEachExecutorOptions( - tree, - '@nx/vite:test', - (options, projectName, targetName, configuration) => { - const projectConfig = projects.get(projectName); - - if (!options.testFile) { - return; - } - - const newTestFileArgs = [options.testFile]; - - delete options.testFile; - - if (configuration) { - projectConfig.targets[targetName].configurations[configuration] = { - ...options, - testFiles: newTestFileArgs, - }; - } else { - projectConfig.targets[targetName].options = { - ...options, - testFiles: newTestFileArgs, - }; - } - - updateProjectConfiguration(tree, projectName, projectConfig); - } - ); -} diff --git a/packages/vite/src/migrations/update-16-6-0-change-ts-paths-plugin/change-ts-paths-plugin.spec.ts b/packages/vite/src/migrations/update-16-6-0-change-ts-paths-plugin/change-ts-paths-plugin.spec.ts deleted file mode 100644 index 8cbcac9d428f3e..00000000000000 --- a/packages/vite/src/migrations/update-16-6-0-change-ts-paths-plugin/change-ts-paths-plugin.spec.ts +++ /dev/null @@ -1,148 +0,0 @@ -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import { Tree, addProjectConfiguration } from '@nx/devkit'; - -import changeTsPathsPlugin from './change-ts-paths-plugin'; - -describe('change-vite-ts-paths-plugin migration', () => { - let tree: Tree; - - beforeEach(() => { - tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); - }); - - it('should update viteTsConfigPaths to nxViteTsPaths plugin', () => { - addProject(tree, 'demo'); - - changeTsPathsPlugin(tree); - - expect(tree.read('apps/demo/vite.config.ts', 'utf-8')) - .toMatchInlineSnapshot(` - " - /// - import { defineConfig } from 'vite'; - import react from '@vitejs/plugin-react'; - import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin'; - - export default defineConfig({ - cacheDir: '../../node_modules/.vite/demo', - server: { - port: 4200, - host: 'localhost', - }, - - preview: { - port: 4300, - host: 'localhost', - }, - - plugins: [ - react(), - nxViteTsPaths() - ], - - // Uncomment this if you are using workers. - // worker: { - // plugins: [ - // viteTsConfigPaths({ - // root: '../../', - // }), - // ], - // }, - - test: { - globals: true, - cache: { - dir: '../../node_modules/.vitest', - }, - environment: 'jsdom', - include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], - }, - }); - - " - `); - }); - - it('should not change anything if viteTsConfigPaths is not used', () => { - addProject(tree, 'demo'); - tree.delete('apps/demo/vite.config.ts'); - - expect(() => changeTsPathsPlugin(tree)).not.toThrow(); - expect(tree.exists('apps/demo/vite.config.ts')).toBeFalsy(); - }); -}); - -function addProject(tree: Tree, name: string) { - addProjectConfiguration(tree, name, { - root: `apps/${name}`, - sourceRoot: `apps/${name}/src`, - targets: { - build: { - executor: '@nx/vite:build', - outputs: ['{options.outputPath}'], - defaultConfiguration: 'production', - options: { - outputPath: `dist/apps/${name}`, - buildLibsFromSource: false, - }, - configurations: { - development: { - mode: 'development', - }, - production: { - mode: 'production', - }, - }, - }, - }, - }); - - tree.write( - `apps/${name}/vite.config.ts`, - ` -/// -import { defineConfig } from 'vite'; -import react from '@vitejs/plugin-react'; -import viteTsConfigPaths from 'vite-tsconfig-paths'; - -export default defineConfig({ - cacheDir: '../../node_modules/.vite/${name}', - server: { - port: 4200, - host: 'localhost', - }, - - preview: { - port: 4300, - host: 'localhost', - }, - - plugins: [ - react(), - viteTsConfigPaths({ - root: '../../' - }) - ], - - // Uncomment this if you are using workers. - // worker: { - // plugins: [ - // viteTsConfigPaths({ - // root: '../../', - // }), - // ], - // }, - - test: { - globals: true, - cache: { - dir: '../../node_modules/.vitest', - }, - environment: 'jsdom', - include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'], - }, -}); - -` - ); -} diff --git a/packages/vite/src/migrations/update-16-6-0-change-ts-paths-plugin/change-ts-paths-plugin.ts b/packages/vite/src/migrations/update-16-6-0-change-ts-paths-plugin/change-ts-paths-plugin.ts deleted file mode 100644 index 44c5e10c1cefdf..00000000000000 --- a/packages/vite/src/migrations/update-16-6-0-change-ts-paths-plugin/change-ts-paths-plugin.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { Tree, getProjects, joinPathFragments } from '@nx/devkit'; -import { forEachExecutorOptions } from '@nx/devkit/src/generators/executor-options-utils'; -import { ViteBuildExecutorOptions } from '../../executors/build/schema'; -import { tsquery } from '@phenomnomnominal/tsquery'; -import { findViteConfig } from '../../utils/find-vite-config'; - -export default function update(tree: Tree) { - const projects = getProjects(tree); - forEachExecutorOptions( - tree, - '@nx/vite:build', - (options, projectName) => { - const projectConfig = projects.get(projectName); - const config = - options.configFile || findViteConfig(tree, projectConfig.root); - if (!config || !tree.exists(config)) { - return; - } - - const configContents = tree.read(config, 'utf-8'); - - const oldTsConfigPathPlugin = - tsquery.query( - configContents, - 'ImportDeclaration:has(StringLiteral[value="vite-tsconfig-paths"])' - ) ?? []; - - if (oldTsConfigPathPlugin.length === 0) { - return; - } - - const importName = - oldTsConfigPathPlugin[0]?.['importClause']?.name?.text ?? - 'viteTsConfigPaths'; - const updatedContent = tsquery.replace( - configContents, - `PropertyAssignment:has(Identifier[name="plugins"]) CallExpression:has(Identifier[name="${importName}"])`, - () => { - return `nxViteTsPaths()`; - } - ); - - const withImportChange = tsquery.replace( - updatedContent, - 'ImportDeclaration:has(StringLiteral[value="vite-tsconfig-paths"])', - () => { - return "import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';"; - } - ); - - tree.write(config, withImportChange); - } - ); -} diff --git a/packages/vue/src/generators/application/application.ts b/packages/vue/src/generators/application/application.ts index 5769dda6e48a2c..3b85e58abfd9cf 100644 --- a/packages/vue/src/generators/application/application.ts +++ b/packages/vue/src/generators/application/application.ts @@ -9,6 +9,7 @@ import { } from '@nx/devkit'; import { Linter } from '@nx/eslint'; import { initGenerator as jsInitGenerator } from '@nx/js'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { Schema } from './schema'; import { normalizeOptions } from './lib/normalize-options'; import { vueInitGenerator } from '../init/init'; @@ -28,6 +29,8 @@ export async function applicationGeneratorInternal( tree: Tree, _options: Schema ): Promise { + assertNotUsingTsSolutionSetup(tree, 'vue', 'application'); + const options = await normalizeOptions(tree, _options); const nxJson = readNxJson(tree); diff --git a/packages/vue/src/generators/init/init.ts b/packages/vue/src/generators/init/init.ts index dc258ca2f940d3..d3bcdb0ed90cd7 100755 --- a/packages/vue/src/generators/init/init.ts +++ b/packages/vue/src/generators/init/init.ts @@ -6,6 +6,7 @@ import { runTasksInSerial, Tree, } from '@nx/devkit'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { nxVersion, vueVersion } from '../../utils/versions'; import { InitSchema } from './schema'; @@ -27,6 +28,8 @@ function updateDependencies(host: Tree, schema: InitSchema) { } export async function vueInitGenerator(host: Tree, schema: InitSchema) { + assertNotUsingTsSolutionSetup(host, 'vue', 'init'); + let installTask: GeneratorCallback = () => {}; if (!schema.skipPackageJson) { installTask = updateDependencies(host, schema); diff --git a/packages/vue/src/generators/library/library.ts b/packages/vue/src/generators/library/library.ts index 220fae7308c10c..25a721b9da1e8f 100644 --- a/packages/vue/src/generators/library/library.ts +++ b/packages/vue/src/generators/library/library.ts @@ -9,6 +9,7 @@ import { updateJson, } from '@nx/devkit'; import { addTsConfigPath, initGenerator as jsInitGenerator } from '@nx/js'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { vueInitGenerator } from '../init/init'; import { Schema } from './schema'; import { normalizeOptions } from './lib/normalize-options'; @@ -27,6 +28,8 @@ export function libraryGenerator(tree: Tree, schema: Schema) { } export async function libraryGeneratorInternal(tree: Tree, schema: Schema) { + assertNotUsingTsSolutionSetup(tree, 'vue', 'library'); + const tasks: GeneratorCallback[] = []; const options = await normalizeOptions(tree, schema); diff --git a/packages/web/migrations.json b/packages/web/migrations.json index 7c71d46c9081d0..2736252dcb28bb 100644 --- a/packages/web/migrations.json +++ b/packages/web/migrations.json @@ -1,18 +1,5 @@ { - "generators": { - "update-16-0-0-add-nx-packages": { - "cli": "nx", - "version": "16.0.0-beta.1", - "description": "Replace @nrwl/web with @nx/web", - "implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages" - }, - "update-16-0-0-update-executors": { - "cli": "nx", - "version": "16.0.0-beta.4", - "description": "Replace @nrwl/web executors with @nx/webpack and @nx/rollup", - "implementation": "./src/migrations/update-16-0-0-update-executors/update-16-0-0-update-executors" - } - }, + "generators": {}, "packageJsonUpdates": { "17.3.0": { "version": "17.3.0-beta.3", diff --git a/packages/web/src/generators/application/application.ts b/packages/web/src/generators/application/application.ts index 46fd9785f9740b..4c3a0a8bc60b02 100644 --- a/packages/web/src/generators/application/application.ts +++ b/packages/web/src/generators/application/application.ts @@ -49,6 +49,7 @@ import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-com import staticServeConfiguration from '../static-serve/static-serve-configuration'; import { findPluginForConfigFile } from '@nx/devkit/src/utils/find-plugin-for-config-file'; import { E2EWebServerDetails } from '@nx/devkit/src/generators/e2e-web-server-info-utils'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; interface NormalizedSchema extends Schema { projectName: string; @@ -257,6 +258,8 @@ export async function applicationGenerator(host: Tree, schema: Schema) { } export async function applicationGeneratorInternal(host: Tree, schema: Schema) { + assertNotUsingTsSolutionSetup(host, 'web', 'application'); + const options = await normalizeOptions(host, schema); const tasks: GeneratorCallback[] = []; diff --git a/packages/web/src/generators/init/init.ts b/packages/web/src/generators/init/init.ts index a95eb936db794e..bd1104750472aa 100644 --- a/packages/web/src/generators/init/init.ts +++ b/packages/web/src/generators/init/init.ts @@ -6,6 +6,7 @@ import { runTasksInSerial, Tree, } from '@nx/devkit'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { nxVersion } from '../../utils/versions'; import { Schema } from './schema'; @@ -26,6 +27,8 @@ function updateDependencies(tree: Tree, schema: Schema) { } export async function webInitGenerator(tree: Tree, schema: Schema) { + assertNotUsingTsSolutionSetup(tree, 'web', 'init'); + let installTask: GeneratorCallback = () => {}; if (!schema.skipPackageJson) { installTask = updateDependencies(tree, schema); diff --git a/packages/web/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts b/packages/web/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts deleted file mode 100644 index b30cdd58958c0f..00000000000000 --- a/packages/web/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Tree, readJson, updateJson } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import replacePackage from './update-16-0-0-add-nx-packages'; - -describe('update-16-0-0-add-nx-packages', () => { - let tree: Tree; - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - - updateJson(tree, 'package.json', (json) => { - json.devDependencies['@nrwl/web'] = '16.0.0'; - return json; - }); - }); - - it('should remove the dependency on @nrwl/web', async () => { - await replacePackage(tree); - - expect( - readJson(tree, 'package.json').dependencies['@nrwl/web'] - ).not.toBeDefined(); - expect( - readJson(tree, 'package.json').devDependencies['@nrwl/web'] - ).not.toBeDefined(); - }); - - it('should add a dependency on @nx/web', async () => { - await replacePackage(tree); - - const packageJson = readJson(tree, 'package.json'); - const newDependencyVersion = - packageJson.devDependencies['@nx/web'] ?? - packageJson.dependencies['@nx/web']; - - expect(newDependencyVersion).toBeDefined(); - }); -}); diff --git a/packages/web/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts b/packages/web/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts deleted file mode 100644 index 58d705a1a25b4e..00000000000000 --- a/packages/web/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Tree, formatFiles } from '@nx/devkit'; -import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package'; - -export default async function replacePackage(tree: Tree): Promise { - await replaceNrwlPackageWithNxPackage(tree, '@nrwl/web', '@nx/web'); - - await formatFiles(tree); -} diff --git a/packages/web/src/migrations/update-16-0-0-update-executors/update-16-0-0-update-executors.ts b/packages/web/src/migrations/update-16-0-0-update-executors/update-16-0-0-update-executors.ts deleted file mode 100644 index 5e17cdd90bf063..00000000000000 --- a/packages/web/src/migrations/update-16-0-0-update-executors/update-16-0-0-update-executors.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { - formatFiles, - getProjects, - Tree, - updateProjectConfiguration, - addDependenciesToPackageJson, -} from '@nx/devkit'; -import { nxVersion } from '../../utils/versions'; - -export default async function update(host: Tree) { - const projects = getProjects(host); - const deps = {}; - - for (const [name, config] of projects.entries()) { - let updated = false; - - // webpack - if (config?.targets?.build?.executor === '@nrwl/web:webpack') { - config.targets.build.executor = '@nx/webpack:webpack'; - deps['@nx/webpack'] = nxVersion; - updated = true; - } - if (config?.targets?.serve?.executor === '@nrwl/web:dev-server') { - config.targets.serve.executor = '@nx/webpack:dev-server'; - deps['@nx/webpack'] = nxVersion; - updated = true; - } - - // rollup - if (config?.targets?.build?.executor === '@nrwl/web:rollup') { - config.targets.build.executor = '@nx/rollup:rollup'; - deps['@nx/rollup'] = nxVersion; - updated = true; - } - - if (updated) { - updateProjectConfiguration(host, name, config); - } - } - - await formatFiles(host); - - return addDependenciesToPackageJson(host, {}, deps); -} diff --git a/packages/webpack/migrations.json b/packages/webpack/migrations.json index bd975630d607a3..b7600347b67077 100644 --- a/packages/webpack/migrations.json +++ b/packages/webpack/migrations.json @@ -1,11 +1,5 @@ { "generators": { - "update-16-0-0-add-nx-packages": { - "cli": "nx", - "version": "16.0.0-beta.1", - "description": "Replace @nrwl/webpack with @nx/webpack", - "implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages" - }, "update-17-2-1-webpack-config-setup": { "cli": "nx", "version": "17.2.1-beta.0", @@ -20,24 +14,6 @@ } }, "packageJsonUpdates": { - "16.3.0": { - "version": "16.3.0-beta.8", - "packages": { - "@svgr/webpack": { - "version": "^8.0.1", - "alwaysAddToPackageJson": false - } - } - }, - "16.4.1": { - "version": "16.4.1-beta.0", - "packages": { - "webpack": { - "version": "^5.80.0", - "alwaysAddToPackageJson": false - } - } - }, "19.6.0": { "version": "19.6.0-beta.1", "packages": { diff --git a/packages/webpack/src/generators/configuration/configuration.ts b/packages/webpack/src/generators/configuration/configuration.ts index f4cd67321e3209..e4b9de0c972246 100644 --- a/packages/webpack/src/generators/configuration/configuration.ts +++ b/packages/webpack/src/generators/configuration/configuration.ts @@ -17,6 +17,7 @@ import { WebpackExecutorOptions } from '../../executors/webpack/schema'; import { hasPlugin } from '../../utils/has-plugin'; import { addBuildTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils'; import { ensureDependencies } from '../../utils/ensure-dependencies'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; export function configurationGenerator( tree: Tree, @@ -29,6 +30,8 @@ export async function configurationGeneratorInternal( tree: Tree, options: ConfigurationGeneratorSchema ) { + assertNotUsingTsSolutionSetup(tree, 'webpack', 'configuration'); + const tasks: GeneratorCallback[] = []; const nxJson = readNxJson(tree); const addPluginDefault = diff --git a/packages/webpack/src/generators/init/init.ts b/packages/webpack/src/generators/init/init.ts index 24f10417e6036e..ec19d0f2f1419e 100644 --- a/packages/webpack/src/generators/init/init.ts +++ b/packages/webpack/src/generators/init/init.ts @@ -7,6 +7,7 @@ import { Tree, } from '@nx/devkit'; import { addPluginV1 } from '@nx/devkit/src/utils/add-plugin'; +import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup'; import { createNodes } from '../../plugins/plugin'; import { nxVersion, webpackCliVersion } from '../../utils/versions'; import { Schema } from './schema'; @@ -16,6 +17,8 @@ export function webpackInitGenerator(tree: Tree, schema: Schema) { } export async function webpackInitGeneratorInternal(tree: Tree, schema: Schema) { + assertNotUsingTsSolutionSetup(tree, 'webpack', 'init'); + const nxJson = readNxJson(tree); const addPluginDefault = process.env.NX_ADD_PLUGINS !== 'false' && diff --git a/packages/webpack/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts b/packages/webpack/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts deleted file mode 100644 index c890c2cc1f468c..00000000000000 --- a/packages/webpack/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Tree, readJson, updateJson } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import replacePackage from './update-16-0-0-add-nx-packages'; - -describe('update-16-0-0-add-nx-packages', () => { - let tree: Tree; - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - - updateJson(tree, 'package.json', (json) => { - json.devDependencies['@nrwl/webpack'] = '16.0.0'; - return json; - }); - }); - - it('should remove the dependency on @nrwl/webpack', async () => { - await replacePackage(tree); - - expect( - readJson(tree, 'package.json').dependencies['@nrwl/webpack'] - ).not.toBeDefined(); - expect( - readJson(tree, 'package.json').devDependencies['@nrwl/webpack'] - ).not.toBeDefined(); - }); - - it('should add a dependency on @nx/webpack', async () => { - await replacePackage(tree); - - const packageJson = readJson(tree, 'package.json'); - const newDependencyVersion = - packageJson.devDependencies['@nx/webpack'] ?? - packageJson.dependencies['@nx/webpack']; - - expect(newDependencyVersion).toBeDefined(); - }); -}); diff --git a/packages/webpack/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts b/packages/webpack/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts deleted file mode 100644 index bfe97ade6961fb..00000000000000 --- a/packages/webpack/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Tree, formatFiles } from '@nx/devkit'; -import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package'; - -export default async function replacePackage(tree: Tree): Promise { - await replaceNrwlPackageWithNxPackage(tree, '@nrwl/webpack', '@nx/webpack'); - - await formatFiles(tree); -} diff --git a/packages/webpack/src/utils/module-federation/remotes.ts b/packages/webpack/src/utils/module-federation/remotes.ts index ad29d5d3bc5878..1651d37cd1245f 100644 --- a/packages/webpack/src/utils/module-federation/remotes.ts +++ b/packages/webpack/src/utils/module-federation/remotes.ts @@ -19,14 +19,16 @@ export function mapRemotes( for (const remote of remotes) { if (Array.isArray(remote)) { - mappedRemotes[remote[0]] = handleArrayRemote( + const remoteName = normalizeRemoteName(remote[0]); + mappedRemotes[remoteName] = handleArrayRemote( remote, remoteEntryExt, isRemoteGlobal ); } else if (typeof remote === 'string') { - mappedRemotes[remote] = handleStringRemote( - remote, + const remoteName = normalizeRemoteName(remote); + mappedRemotes[remoteName] = handleStringRemote( + remoteName, determineRemoteUrl, isRemoteGlobal ); @@ -42,7 +44,8 @@ function handleArrayRemote( remoteEntryExt: 'js' | 'mjs', isRemoteGlobal: boolean ): string { - const [remoteName, remoteLocation] = remote; + let [remoteName, remoteLocation] = remote; + remoteName = normalizeRemoteName(remoteName); const remoteLocationExt = extname(remoteLocation); // If remote location already has .js or .mjs extension @@ -95,7 +98,8 @@ export function mapRemotesForSSR( for (const remote of remotes) { if (Array.isArray(remote)) { - const [remoteName, remoteLocation] = remote; + let [remoteName, remoteLocation] = remote; + remoteName = normalizeRemoteName(remoteName); const remoteLocationExt = extname(remoteLocation); mappedRemotes[remoteName] = `${remoteName}@${ ['.js', '.mjs'].includes(remoteLocationExt) @@ -107,9 +111,14 @@ export function mapRemotesForSSR( }/remoteEntry.${remoteEntryExt}` }`; } else if (typeof remote === 'string') { - mappedRemotes[remote] = `${remote}@${determineRemoteUrl(remote)}`; + const remoteName = normalizeRemoteName(remote); + mappedRemotes[remoteName] = `${remoteName}@${determineRemoteUrl(remote)}`; } } return mappedRemotes; } + +function normalizeRemoteName(remote: string) { + return remote.replace(/-/g, '_'); +} diff --git a/packages/workspace/migrations.json b/packages/workspace/migrations.json index 473aac9dfecd52..311cefc8dc53a8 100644 --- a/packages/workspace/migrations.json +++ b/packages/workspace/migrations.json @@ -1,49 +1,6 @@ { - "generators": { - "update-16-0-0-add-nx-packages": { - "cli": "nx", - "version": "16.0.0-beta.1", - "description": "Replace @nrwl/workspace with @nx/workspace", - "implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages" - }, - "16-0-0-move-workspace-generators-into-local-plugin": { - "version": "16.0.0-beta.4", - "description": "Generates a plugin called 'workspace-plugin' containing your workspace generators.", - "cli": "nx", - "implementation": "./src/migrations/update-16-0-0/move-workspace-generators-to-local-plugin" - }, - "16-0-0-fix-invalid-babelrc": { - "version": "16.0.0-beta.9", - "description": "Fix .babelrc presets if it contains an invalid entry for @nx/web/babel.", - "cli": "nx", - "implementation": "./src/migrations/update-16-0-0/fix-invalid-babelrc" - } - }, + "generators": {}, "packageJsonUpdates": { - "16.1.0": { - "version": "16.1.0-beta.0", - "x-prompt": "Do you want to update to TypeScript v5.0?", - "requires": { - "typescript": ">=4.9.5 <5.0.0" - }, - "packages": { - "typescript": { - "version": "~5.0.2" - } - } - }, - "16.4.0": { - "version": "16.4.0-beta.11", - "x-prompt": "Do you want to update to TypeScript v5.1?", - "requires": { - "typescript": ">=5.0.0 <5.1.0" - }, - "packages": { - "typescript": { - "version": "~5.1.3" - } - } - }, "17.1.0": { "version": "17.1.0-beta.4", "x-prompt": "Do you want to update to TypeScript v5.2?", diff --git a/packages/workspace/src/generators/new/__snapshots__/generate-workspace-files.spec.ts.snap b/packages/workspace/src/generators/new/__snapshots__/generate-workspace-files.spec.ts.snap index 1f9800bab83f02..84a888fb32b34a 100644 --- a/packages/workspace/src/generators/new/__snapshots__/generate-workspace-files.spec.ts.snap +++ b/packages/workspace/src/generators/new/__snapshots__/generate-workspace-files.spec.ts.snap @@ -1563,6 +1563,24 @@ Pass \`--dry-run\` to see what would happen without actually releasing the libra [Learn more about Nx release »](hhttps://nx.dev/features/manage-releases?utm_source=nx_project&utm_medium=readme&utm_campaign=nx_projects) +## Keep TypeScript project references up to date + +Nx automatically updates TypeScript [project references](https://www.typescriptlang.org/docs/handbook/project-references.html) in \`tsconfig.json\` files to ensure they remain accurate based on your project dependencies (\`import\` or \`require\` statements). This sync is automatically done when running tasks such as \`build\` or \`typecheck\`, which require updated references to function correctly. + +To manually trigger the process to sync the project graph dependencies information to the TypeScript project references, run the following command: + +\`\`\`sh +npx nx sync +\`\`\` + +You can enforce that the TypeScript project references are always in the correct state when running in CI by adding a step to your CI job configuration that runs the following command: + +\`\`\`sh +npx nx sync:check +\`\`\` + +[Learn more about nx sync](https://nx.dev/reference/nx-commands#sync) + [Learn more about Nx on CI](https://nx.dev/ci/intro/ci-with-nx#ready-get-started-with-your-provider?utm_source=nx_project&utm_medium=readme&utm_campaign=nx_projects) ## Install Nx Console @@ -3832,6 +3850,24 @@ Pass \`--dry-run\` to see what would happen without actually releasing the libra [Learn more about Nx release »](hhttps://nx.dev/features/manage-releases?utm_source=nx_project&utm_medium=readme&utm_campaign=nx_projects) +## Keep TypeScript project references up to date + +Nx automatically updates TypeScript [project references](https://www.typescriptlang.org/docs/handbook/project-references.html) in \`tsconfig.json\` files to ensure they remain accurate based on your project dependencies (\`import\` or \`require\` statements). This sync is automatically done when running tasks such as \`build\` or \`typecheck\`, which require updated references to function correctly. + +To manually trigger the process to sync the project graph dependencies information to the TypeScript project references, run the following command: + +\`\`\`sh +npx nx sync +\`\`\` + +You can enforce that the TypeScript project references are always in the correct state when running in CI by adding a step to your CI job configuration that runs the following command: + +\`\`\`sh +npx nx sync:check +\`\`\` + +[Learn more about nx sync](https://nx.dev/reference/nx-commands#sync) + ## Set up CI! ### Step 1 @@ -5836,6 +5872,24 @@ Pass \`--dry-run\` to see what would happen without actually releasing the libra [Learn more about Nx release »](hhttps://nx.dev/features/manage-releases?utm_source=nx_project&utm_medium=readme&utm_campaign=nx_projects) +## Keep TypeScript project references up to date + +Nx automatically updates TypeScript [project references](https://www.typescriptlang.org/docs/handbook/project-references.html) in \`tsconfig.json\` files to ensure they remain accurate based on your project dependencies (\`import\` or \`require\` statements). This sync is automatically done when running tasks such as \`build\` or \`typecheck\`, which require updated references to function correctly. + +To manually trigger the process to sync the project graph dependencies information to the TypeScript project references, run the following command: + +\`\`\`sh +npx nx sync +\`\`\` + +You can enforce that the TypeScript project references are always in the correct state when running in CI by adding a step to your CI job configuration that runs the following command: + +\`\`\`sh +npx nx sync:check +\`\`\` + +[Learn more about nx sync](https://nx.dev/reference/nx-commands#sync) + [Learn more about Nx on CI](https://nx.dev/ci/intro/ci-with-nx#ready-get-started-with-your-provider?utm_source=nx_project&utm_medium=readme&utm_campaign=nx_projects) ## Install Nx Console diff --git a/packages/workspace/src/generators/new/files-package-based-repo/__dot__vscode/extensions.json__tmpl__ b/packages/workspace/src/generators/new/files-package-based-repo/__dot__vscode/extensions.json__tmpl__ index 35ad27269d7da1..06b24f939e0515 100644 --- a/packages/workspace/src/generators/new/files-package-based-repo/__dot__vscode/extensions.json__tmpl__ +++ b/packages/workspace/src/generators/new/files-package-based-repo/__dot__vscode/extensions.json__tmpl__ @@ -1,8 +1,6 @@ { - "recommendations": [ - <% if(cliCommand === 'ng') { %> - "angular.ng-template",<% } - %> + "recommendations": [<% if(cliCommand === 'ng') { %> + "angular.ng-template",<% } %> "nrwl.angular-console" ] } diff --git a/packages/workspace/src/generators/new/generate-workspace-files.ts b/packages/workspace/src/generators/new/generate-workspace-files.ts index 2c1d792cead104..877ca6bcfcadcd 100644 --- a/packages/workspace/src/generators/new/generate-workspace-files.ts +++ b/packages/workspace/src/generators/new/generate-workspace-files.ts @@ -276,7 +276,7 @@ function createFiles(tree: Tree, options: NormalizedSchema) { ? './files-root-app' : (options.preset === Preset.TS && process.env.NX_ADD_PLUGINS !== 'false' && - process.env.NX_ADD_TS_PLUGIN === 'true') || + process.env.NX_ADD_TS_PLUGIN !== 'false') || options.preset === Preset.NPM ? './files-package-based-repo' : './files-integrated-repo'; @@ -315,7 +315,7 @@ async function createReadme( isTsPreset: preset === Preset.TS, isUsingNewTsSolutionSetup: process.env.NX_ADD_PLUGINS !== 'false' && - process.env.NX_ADD_TS_PLUGIN === 'true', + process.env.NX_ADD_TS_PLUGIN !== 'false', isEmptyRepo: !appName, appName, generateAppCmd: presetInfo.generateAppCmd, @@ -416,7 +416,7 @@ function setUpWorkspacesInPackageJson(tree: Tree, options: NormalizedSchema) { options.preset === Preset.NPM || (options.preset === Preset.TS && process.env.NX_ADD_PLUGINS !== 'false' && - process.env.NX_ADD_TS_PLUGIN === 'true') + process.env.NX_ADD_TS_PLUGIN !== 'false') ) { if (options.packageManager === 'pnpm') { tree.write( diff --git a/packages/workspace/src/generators/preset/preset.ts b/packages/workspace/src/generators/preset/preset.ts index 4c9fc5a055fba3..d2a305d424f784 100644 --- a/packages/workspace/src/generators/preset/preset.ts +++ b/packages/workspace/src/generators/preset/preset.ts @@ -262,7 +262,7 @@ async function createPreset(tree: Tree, options: Schema) { formatter: options.formatter, addTsPlugin: process.env.NX_ADD_PLUGINS !== 'false' && - process.env.NX_ADD_TS_PLUGIN === 'true', + process.env.NX_ADD_TS_PLUGIN !== 'false', }); } else if (options.preset === Preset.TsStandalone) { const { libraryGenerator } = require('@nx' + '/js'); diff --git a/packages/workspace/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts b/packages/workspace/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts deleted file mode 100644 index 70f3b546b161c8..00000000000000 --- a/packages/workspace/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Tree, readJson, updateJson } from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import replacePackage from './update-16-0-0-add-nx-packages'; - -describe('update-16-0-0-add-nx-packages', () => { - let tree: Tree; - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - - updateJson(tree, 'package.json', (json) => { - json.devDependencies['@nrwl/workspace'] = '16.0.0'; - return json; - }); - }); - - it('should remove the dependency on @nrwl/workspace', async () => { - await replacePackage(tree); - - expect( - readJson(tree, 'package.json').dependencies['@nrwl/workspace'] - ).not.toBeDefined(); - expect( - readJson(tree, 'package.json').devDependencies['@nrwl/workspace'] - ).not.toBeDefined(); - }); - - it('should add a dependency on @nx/workspace', async () => { - await replacePackage(tree); - - const packageJson = readJson(tree, 'package.json'); - const newDependencyVersion = - packageJson.devDependencies['@nx/workspace'] ?? - packageJson.dependencies['@nx/workspace']; - - expect(newDependencyVersion).toBeDefined(); - }); -}); diff --git a/packages/workspace/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts b/packages/workspace/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts deleted file mode 100644 index b2b9c4844a2380..00000000000000 --- a/packages/workspace/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Tree, formatFiles } from '@nx/devkit'; -import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package'; - -export default async function replacePackage(tree: Tree): Promise { - await replaceNrwlPackageWithNxPackage( - tree, - '@nrwl/workspace', - '@nx/workspace' - ); - - await formatFiles(tree); -} diff --git a/packages/workspace/src/migrations/update-16-0-0/fix-invalid-babelrc.spec.ts b/packages/workspace/src/migrations/update-16-0-0/fix-invalid-babelrc.spec.ts deleted file mode 100644 index 6725e1dfc96377..00000000000000 --- a/packages/workspace/src/migrations/update-16-0-0/fix-invalid-babelrc.spec.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { - addProjectConfiguration, - readJson, - Tree, - updateJson, - writeJson, -} from '@nx/devkit'; -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import update from './fix-invalid-babelrc'; - -describe('fix-invalid-babelrc', () => { - let tree: Tree; - - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - }); - - it.each` - webPlugin - ${'@nrwl/web'} - ${'@nx/web'} - `('should skip update if Web plugin is installed', ({ webPlugin }) => { - addProjectConfiguration(tree, 'proj', { - root: 'proj', - name: 'proj', - }); - updateJson(tree, 'package.json', (json) => { - json.devDependencies[webPlugin] = '16.0.0'; - return json; - }); - writeJson(tree, 'proj/.babelrc', { - presets: [['@nx/web/babel', {}]], - }); - - update(tree); - - expect(readJson(tree, 'proj/.babelrc')).toEqual({ - presets: [['@nx/web/babel', {}]], - }); - }); - - it.each` - jsPlugin | originalPreset - ${'@nrwl/js'} | ${'@nrwl/web/babel'} - ${'@nrwl/js'} | ${'@nx/web/babel'} - ${'@nx/js'} | ${'@nrwl/web/babel'} - ${'@nx/js'} | ${'@nx/web/babel'} - `( - 'should rename @nrwl/web/babel to @nx/js/babel when JS plugin is installed', - ({ jsPlugin, originalPreset }) => { - addProjectConfiguration(tree, 'proj1', { - root: 'proj1', - name: 'proj1', - }); - addProjectConfiguration(tree, 'proj2', { - root: 'proj2', - name: 'proj2', - }); - updateJson(tree, 'package.json', (json) => { - json.devDependencies[jsPlugin] = '16.0.0'; - return json; - }); - writeJson(tree, 'proj1/.babelrc', { - presets: [[originalPreset, {}]], - }); - writeJson(tree, 'proj2/.babelrc', { - presets: [originalPreset], - }); - - update(tree); - - expect(readJson(tree, 'proj1/.babelrc')).toEqual({ - presets: [['@nx/js/babel', {}]], - }); - expect(readJson(tree, 'proj2/.babelrc')).toEqual({ - presets: ['@nx/js/babel'], - }); - } - ); - - it('should remove the invalid preset if neither Web nor JS plugins are present', () => { - addProjectConfiguration(tree, 'proj', { - root: 'proj', - name: 'proj', - }); - writeJson(tree, 'proj/.babelrc', { - presets: [ - '@babel/preset-env', - ['@nx/web/babel', {}], - '@babel/preset-typescript', - ], - }); - - update(tree); - - expect(readJson(tree, 'proj/.babelrc')).toEqual({ - presets: ['@babel/preset-env', '@babel/preset-typescript'], - }); - }); -}); diff --git a/packages/workspace/src/migrations/update-16-0-0/fix-invalid-babelrc.ts b/packages/workspace/src/migrations/update-16-0-0/fix-invalid-babelrc.ts deleted file mode 100644 index f7f4cbc1f735d3..00000000000000 --- a/packages/workspace/src/migrations/update-16-0-0/fix-invalid-babelrc.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { - getProjects, - joinPathFragments, - readJson, - Tree, - writeJson, -} from '@nx/devkit'; - -export default function update(tree: Tree) { - const projects = getProjects(tree); - const packageJson = readJson(tree, 'package.json'); - - // In case user installed as prod dep. - const deps = { ...packageJson.dependencies, ...packageJson.devDependencies }; - - // If web package is installed, skip update. - if (deps['@nrwl/web'] || deps['@nx/web']) { - return; - } - - projects.forEach((config, name) => { - const babelRcPath = joinPathFragments(config.root, '.babelrc'); - if (!tree.exists(babelRcPath)) return; - - const babelRc = readJson(tree, babelRcPath); - const nrwlWebBabelPresetIdx = babelRc.presets?.findIndex((p) => - // Babel preset could be specified as a string or a tuple with options. - // Account for rescope migration running before or after this one. - Array.isArray(p) - ? p[0] === '@nrwl/web/babel' || p[0] === '@nx/web/babel' - : p === '@nrwl/web/babel' || p === '@nx/web/babel' - ); - - if (nrwlWebBabelPresetIdx === undefined || nrwlWebBabelPresetIdx === -1) { - return; - } - - if (deps['@nrwl/js'] || deps['@nx/js']) { - // If JS plugin is installed, then rename to @nx/js/babel. - const found = babelRc.presets[nrwlWebBabelPresetIdx]; - babelRc.presets[nrwlWebBabelPresetIdx] = Array.isArray(found) - ? ['@nx/js/babel', found[1]] - : '@nx/js/babel'; - } else { - // Otherwise, remove from config. - babelRc.presets.splice(nrwlWebBabelPresetIdx, 1); - } - - writeJson(tree, babelRcPath, babelRc); - }); -} diff --git a/packages/workspace/src/migrations/update-16-0-0/move-workspace-generators-to-local-plugin.spec.ts b/packages/workspace/src/migrations/update-16-0-0/move-workspace-generators-to-local-plugin.spec.ts deleted file mode 100644 index 1685f655103fea..00000000000000 --- a/packages/workspace/src/migrations/update-16-0-0/move-workspace-generators-to-local-plugin.spec.ts +++ /dev/null @@ -1,208 +0,0 @@ -import 'nx/src/internal-testing-utils/mock-project-graph'; - -import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import { - Tree, - readProjectConfiguration, - readJson, - joinPathFragments, - GeneratorsJson, - ProjectConfiguration, - stripIndents, -} from '@nx/devkit'; - -import generator from './move-workspace-generators-to-local-plugin'; - -describe('move-workspace-generators-to-local-plugin', () => { - let tree: Tree; - - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - }); - - it('should find single workspace generator successfully', async () => { - await workspaceGeneratorGenerator(tree, { - name: 'my-generator', - }); - await generator(tree); - const config = readProjectConfiguration(tree, 'workspace-plugin'); - expect(config.root).toEqual('tools/workspace-plugin'); - - assertValidGenerator(tree, config, 'my-generator'); - }); - - it('should convert multiple workspace generators successfully', async () => { - const generators = [...new Array(10)].map((x) => uniq('generator')); - for (const name of generators) { - await workspaceGeneratorGenerator(tree, { - name, - }); - } - - await generator(tree); - - const config = readProjectConfiguration(tree, 'workspace-plugin'); - expect(config.root).toEqual('tools/workspace-plugin'); - - for (const generator of generators) { - assertValidGenerator(tree, config, generator); - } - }); - - it('should be idempotent', async () => { - const generators = [...new Array(10)].map((x) => uniq('generator')); - for (const name of generators) { - await workspaceGeneratorGenerator(tree, { - name, - }); - } - - await generator(tree); - - const generatorsJson = readJson( - tree, - 'tools/workspace-plugin/generators.json' - ); - - await generator(tree); - expect(readJson(tree, 'tools/workspace-plugin/generators.json')).toEqual( - generatorsJson - ); - - const config = readProjectConfiguration(tree, 'workspace-plugin'); - - for (const generator of generators) { - assertValidGenerator(tree, config, generator); - } - }); - - it('should merge new generators into existing plugin', async () => { - const generators = [...new Array(10)].map((x) => uniq('generator')); - for (const name of generators) { - await workspaceGeneratorGenerator(tree, { - name, - }); - } - - await generator(tree); - - const moreGenerators = [...new Array(5)].map((x) => uniq('generator')); - for (const name of moreGenerators) { - await workspaceGeneratorGenerator(tree, { - name, - }); - } - - await generator(tree); - - const config = readProjectConfiguration(tree, 'workspace-plugin'); - - for (const generator of generators.concat(moreGenerators)) { - assertValidGenerator(tree, config, generator); - } - }); - - it('should update imports that point to a parent directory', async () => { - await workspaceGeneratorGenerator(tree, { - name: 'my-generator', - }); - tree.write('tools/utils/index.ts', 'export default function someUtil() {}'); - tree.write( - 'tools/generators/my-generator/index.ts', - 'import { someUtil } from "../../utils";' - ); - tree.write( - 'tools/generators/my-generator/lib/index.ts', - 'import { someUtil } from "../../../utils";' - ); - await generator(tree); - - const config = readProjectConfiguration(tree, 'workspace-plugin'); - const generatorImplPath = joinPathFragments( - config.root, - 'src/generators/my-generator/index.ts' - ); - const generatorImpl = tree.read(generatorImplPath).toString('utf-8'); - expect(generatorImpl).toContain( - `import { someUtil } from '../../../../utils';` - ); - const generatorLibImplPath = joinPathFragments( - config.root, - 'src/generators/my-generator/lib/index.ts' - ); - const generatorLibImpl = tree.read(generatorLibImplPath).toString('utf-8'); - expect(generatorLibImpl).toContain( - `import { someUtil } from '../../../../../utils';` - ); - }); -}); - -function assertValidGenerator( - tree: Tree, - config: ProjectConfiguration, - generator: string -) { - const generatorsJson = readJson( - tree, - joinPathFragments(config.root, 'generators.json') - ); - expect(generatorsJson.generators).toHaveProperty(generator); - const generatorImplPath = joinPathFragments( - config.root, - generatorsJson.generators[generator].implementation, - 'index.ts' - ); - expect(tree.exists(generatorImplPath)).toBeTruthy(); - const generatorSchemaPath = joinPathFragments( - config.root, - generatorsJson.generators[generator].schema - ); - expect(tree.exists(generatorSchemaPath)).toBeTruthy(); -} - -function uniq(prefix: string) { - return `${prefix}${Math.floor(Math.random() * 10000000)}`; -} - -async function workspaceGeneratorGenerator( - host: Tree, - schema: { name: string } -) { - const outputDirectory = joinPathFragments('tools/generators', schema.name); - - host.write( - joinPathFragments(outputDirectory, 'index.ts'), - stripIndents`import { Tree, formatFiles, installPackagesTask } from '@nx/devkit'; - import { libraryGenerator } from '@nx/workspace/generators'; - - export default async function(tree: Tree, schema: any) { - await libraryGenerator(tree, {name: schema.name}); - await formatFiles(tree); - return () => { - installPackagesTask(tree) - } - }` - ); - - host.write( - joinPathFragments(outputDirectory, 'schema.json'), - stripIndents`{ - "$schema": "https://json-schema.org/schema", - "cli": "nx", - "$id": "<%= name %>", - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Library name", - "$default": { - "$source": "argv", - "index": 0 - } - } - }, - "required": ["name"] - } - ` - ); -} diff --git a/packages/workspace/src/migrations/update-16-0-0/move-workspace-generators-to-local-plugin.ts b/packages/workspace/src/migrations/update-16-0-0/move-workspace-generators-to-local-plugin.ts deleted file mode 100644 index e2f2625d740cc8..00000000000000 --- a/packages/workspace/src/migrations/update-16-0-0/move-workspace-generators-to-local-plugin.ts +++ /dev/null @@ -1,270 +0,0 @@ -import { - addDependenciesToPackageJson, - ensurePackage, - formatFiles, - getProjects, - getWorkspaceLayout, - joinPathFragments, - output, - ProjectConfiguration, - readJson, - readProjectConfiguration, - Tree, - updateJson, -} from '@nx/devkit'; -// nx-ignore-next-line -import * as path from 'path'; -import { - GeneratorsJson, - GeneratorsJsonEntry, -} from 'nx/src/config/misc-interfaces'; -import { moveGenerator } from '../../generators/move/move'; -import { nxVersion } from '../../utils/versions'; -import { PackageJson } from 'nx/src/utils/package-json'; -import { posix } from 'path'; -import { getNpmScope } from '../../utilities/get-import-path'; - -const PROJECT_NAME = 'workspace-plugin'; -const DESTINATION = `tools/${PROJECT_NAME}`; - -export default async function (tree: Tree) { - if (!tree.exists('tools/generators')) { - return; - } - const tasks = []; - if (hasWorkspaceGenerators(tree)) { - tasks.push(...(await moveWorkspaceGeneratorsToLocalPlugin(tree))); - } - removeToolsGeneratorsIfEmpty(tree); - await formatFiles(tree); - return () => { - for (const task of tasks) { - task(); - } - }; -} - -async function moveWorkspaceGeneratorsToLocalPlugin(tree: Tree) { - const tasks = []; - let project = getProjects(tree).get(PROJECT_NAME); - if (!project) { - await createNewPlugin(tree); - tasks.push( - addDependenciesToPackageJson( - tree, - {}, - { - '@nx/plugin': nxVersion, - } - ) - ); - project = readProjectConfiguration(tree, PROJECT_NAME); - } - updateExistingPlugin(tree, project); - return tasks; -} - -function hasWorkspaceGenerators(tree: Tree) { - const children = tree.children('tools/generators'); - return ( - children.length > 0 && - !(children.length === 1 && children[0] === '.gitkeep') - ); -} - -function removeToolsGeneratorsIfEmpty(tree: Tree) { - if (!hasWorkspaceGenerators(tree)) { - tree.delete('tools/generators'); - } -} - -// Inspired by packages/nx/src/command-line/workspace-generators.ts -function collectAndMoveGenerators(tree: Tree, destinationProjectRoot: string) { - const generators: Record = {}; - const generatorsDir = 'tools/generators'; - const destinationDir = joinPathFragments( - destinationProjectRoot, - 'src', - 'generators' - ); - for (const c of tree.children('tools/generators')) { - const childDir = path.join(generatorsDir, c); - const schemaPath = joinPathFragments(childDir, 'schema.json'); - if (tree.exists(schemaPath)) { - const schema = readJson(tree, schemaPath); - generators[c] = { - implementation: `./src/generators/${c}`, - schema: `./src/generators/${joinPathFragments(c, 'schema.json')}`, - description: schema.description ?? `Generator ${c}`, - }; - moveFilesInDirectory( - tree, - childDir, - joinPathFragments(destinationDir, c) - ); - } - } - return generators; -} - -function moveFilesInDirectory(tree: Tree, source: string, destination: string) { - const relative = posix.relative(source, posix.dirname(destination)); - if (!relative.startsWith('../')) { - // If the destination is in the same directory or a subdirectory of the source - // we can just move the files. If it is not, we need to update the relative imports. - return; - } - let offsetLevel = 0; - const pathParts = relative.split('/'); - for (const part of pathParts) { - if (part === '..') { - offsetLevel++; - } else { - break; - } - } - for (const c of tree.children(source)) { - if (!tree.isFile(c)) { - moveFilesInDirectory( - tree, - joinPathFragments(source, c), - joinPathFragments(destination, c) - ); - } - tree.rename( - joinPathFragments(source, c), - joinPathFragments(destination, c) - ); - // If its a TS file we can update relative imports with find + replace - // This could be done with AST, but since we are only looking at relative - // imports its easy to do via string replace. We replace any strings starting - // with a relative path outside of their own directory. - if (c.endsWith('.ts')) { - let content = tree.read(joinPathFragments(destination, c)).toString(); - // +2 is a bit of a magic number here - represents extra directory levels in a normal - // plugin structure compared to the workspace-generator layout - const extraDirectoriesInPluginStructure = 2; - content = content.replace( - new RegExp(`'` + `\.\.\/`.repeat(offsetLevel), 'g'), - "'" + '../'.repeat(offsetLevel + extraDirectoriesInPluginStructure) - ); - content = content.replace( - new RegExp(`"` + `\.\.\/`.repeat(offsetLevel), 'g'), - '"' + '../'.repeat(offsetLevel + extraDirectoriesInPluginStructure) - ); - // We write it back in the same spot, since it is moved as if it was a regular file after this - tree.write(joinPathFragments(source, c), content); - } - tree.rename( - joinPathFragments(source, c), - joinPathFragments(destination, c) - ); - } -} - -async function createNewPlugin(tree: Tree) { - ensurePackage('@nx/plugin', nxVersion); - const { pluginGenerator } = - // nx-ignore-next-line - require('@nx/plugin/src/generators/plugin/plugin'); - - // nx-ignore-next-line - const { Linter } = ensurePackage('@nx/eslint', nxVersion); - - const npmScope = getNpmScope(tree); - const importPath = npmScope ? `@${npmScope}/${PROJECT_NAME}` : PROJECT_NAME; - - await pluginGenerator(tree, { - minimal: true, - directory: PROJECT_NAME, - importPath: importPath, - skipTsConfig: false, - compiler: 'tsc', - linter: Linter.EsLint, - skipFormat: true, - skipLintChecks: false, - unitTestRunner: 'jest', - e2eTestRunner: 'none', - publishable: false, - }); - await getCreateGeneratorsJson()( - tree, - readProjectConfiguration(tree, PROJECT_NAME).root, - PROJECT_NAME - ); - await moveGeneratedPlugin(tree, DESTINATION, importPath); -} - -function moveGeneratedPlugin( - tree: Tree, - destination: string, - importPath: string -) { - const config = readProjectConfiguration(tree, PROJECT_NAME); - if (config.root !== DESTINATION) { - return moveGenerator(tree, { - destination, - projectName: PROJECT_NAME, - newProjectName: PROJECT_NAME, - updateImportPath: true, - importPath: importPath, - }); - } -} - -function updateExistingPlugin(tree: Tree, project: ProjectConfiguration) { - const packageJson = readJson( - tree, - joinPathFragments(project.root, 'package.json') - ); - const defaultGeneratorsPath = joinPathFragments( - project.root, - 'generators.json' - ); - let generatorsJsonPath = - packageJson.generators || - packageJson.schematics || - tree.exists(defaultGeneratorsPath) - ? defaultGeneratorsPath - : null; - if (!generatorsJsonPath) { - getCreateGeneratorsJson()( - tree, - readProjectConfiguration(tree, PROJECT_NAME).root, - PROJECT_NAME - ); - generatorsJsonPath = defaultGeneratorsPath; - } - updateJson(tree, generatorsJsonPath, (json) => { - const generators = collectAndMoveGenerators(tree, project.root); - json.generators ??= {}; - for (const generator in generators) { - if (json.generators[generator]) { - output.warn({ - title: `Generator ${generator} already exists in ${project.name}`, - bodyLines: [ - 'Since you have a generator with the same name in your plugin, the generator from workspace-generators has been discarded.', - ], - }); - } else { - json.generators[generator] = generators[generator]; - } - } - return json; - }); -} - -function getCreateGeneratorsJson(): ( - host: Tree, - projectRoot: string, - projectName: string, - skipLintChecks?: boolean, - skipFormat?: boolean -) => Promise { - // We cant use `as typeof import('@nx/plugin/src/generators/generator/generator');` here - // because it will cause a typescript error at build time. - const { createGeneratorsJson } = - // nx-ignore-next-line - require('@nx/plugin/src/generators/generator/generator'); - return createGeneratorsJson; -}