From bf206e578e642003ef03e68dc87126d07d694072 Mon Sep 17 00:00:00 2001 From: Jason Jean Date: Mon, 15 Apr 2024 16:45:08 -0400 Subject: [PATCH] feat(misc): non conflicting init/add flow (#22791) --- .../migration/adding-to-existing-project.md | 157 +++--- docs/shared/migration/adding-to-monorepo.md | 188 ++++--- e2e/detox/src/detox-legacy.test.ts | 17 +- e2e/expo/src/expo-legacy.test.ts | 19 +- .../src/react-native-legacy.test.ts | 18 +- packages/angular/plugins/component-testing.ts | 2 +- .../add-linting/add-linting.spec.ts | 2 + .../application/application.spec.ts | 4 + .../component-cypress-spec.spec.ts | 2 + .../component-story/component-story.spec.ts | 2 + .../component-test/component-test.spec.ts | 2 + .../cypress-component-configuration.spec.ts | 12 +- .../federate-module/federate-module.spec.ts | 2 + .../angular/src/generators/host/host.spec.ts | 2 + .../library-secondary-entry-point.spec.ts | 2 + .../src/generators/library/library.spec.ts | 2 + .../angular/src/generators/move/move.spec.ts | 2 + .../ng-add/migrate-from-angular-cli.spec.ts | 4 +- .../migrators/projects/app.migrator.spec.ts | 2 + .../migrators/projects/e2e.migrator.spec.ts | 2 + .../ngrx-feature-store.spec.ts | 2 + .../ngrx-root-store/ngrx-root-store.spec.ts | 2 + .../angular/src/generators/ngrx/ngrx.spec.ts | 2 + .../src/generators/remote/remote.spec.ts | 2 + .../scam-to-standalone.spec.ts | 2 + .../generators/setup-ssr/setup-ssr.spec.ts | 2 + .../generators/stories/stories-app.spec.ts | 2 + .../generators/stories/stories-lib.spec.ts | 2 + .../generators/web-worker/web-worker.spec.ts | 2 + .../rename-webpack-server.spec.ts | 2 + .../remove-browserlist-config.spec.ts | 2 + .../remove-browserlist-config.ts | 2 + .../update-typescript-target.spec.ts | 2 + .../update-workspace-config.spec.ts | 2 + .../component-configuration.spec.ts | 2 + .../configuration/configuration.spec.ts | 2 + .../generators/configuration/configuration.ts | 4 +- .../cypress-project/cypress-project.spec.ts | 2 + .../cypress/src/generators/init/init.spec.ts | 2 + packages/cypress/src/generators/init/init.ts | 65 +-- .../migrate-to-cypress-11.spec.ts | 2 + .../update-15-1-0/cypress-11.spec.ts | 4 +- .../update-16-2-0/update-cy-tsconfig.spec.ts | 2 + .../application/application.spec.ts | 2 + .../detox/src/generators/init/init.spec.ts | 2 + packages/detox/src/generators/init/init.ts | 49 +- packages/devkit/src/utils/add-plugin.spec.ts | 470 ++++++++++++++++++ ...pdate-package-scripts.ts => add-plugin.ts} | 288 +++++++---- .../src/utils/update-package-scripts.spec.ts | 394 --------------- .../convert-to-flat-config/generator.spec.ts | 2 + .../eslint/src/generators/init/init.spec.ts | 2 + packages/eslint/src/generators/init/init.ts | 72 +-- .../lint-project/lint-project.spec.ts | 2 + .../workspace-rule/workspace-rule.spec.ts | 2 + .../workspace-rules-project.spec.ts | 3 +- .../application/application.spec.ts | 2 + .../generators/component/component.spec.ts | 2 + .../expo/src/generators/init/init.spec.ts | 4 +- packages/expo/src/generators/init/init.ts | 60 +-- .../src/generators/library/library.spec.ts | 2 + packages/expo/src/utils/add-linting.spec.ts | 2 + packages/gradle/src/generators/init/init.ts | 6 - .../configuration/configuration.spec.ts | 2 + .../jest/src/generators/init/init.spec.ts | 2 + packages/jest/src/generators/init/init.ts | 39 +- .../convert-to-swc/convert-to-swc.spec.ts | 2 + .../js/src/generators/library/library.spec.ts | 2 + .../generators/setup-build/generator.spec.ts | 2 + .../setup-verdaccio/generator.spec.ts | 2 + .../update-15-8-0/rename-swcrc-config.spec.ts | 2 + packages/next/plugins/component-testing.ts | 2 +- .../next/src/generators/init/init.spec.ts | 13 +- packages/next/src/generators/init/init.ts | 28 +- .../src/generators/init/lib/add-plugin.ts | 28 -- .../application/application.spec.ts | 33 ++ .../src/generators/application/application.ts | 11 +- .../nuxt/src/generators/init/init.spec.ts | 6 +- packages/nuxt/src/generators/init/init.ts | 22 +- .../configuration.spec.ts | 2 + .../init/implementation/add-nx-to-monorepo.ts | 5 +- .../init/implementation/add-nx-to-npm-repo.ts | 5 +- .../command-line/init/implementation/utils.ts | 12 +- packages/nx/src/command-line/init/init-v2.ts | 73 ++- packages/nx/src/devkit-internals.ts | 3 + .../mock-project-graph.ts | 9 + packages/nx/src/project-graph/error-types.ts | 63 ++- packages/nx/src/project-graph/file-utils.ts | 1 + .../nx/src/project-graph/project-graph.ts | 11 +- .../utils/project-configuration-utils.spec.ts | 6 +- .../utils/project-configuration-utils.ts | 53 +- .../utils/retrieve-workspace-files.ts | 31 +- packages/nx/src/utils/nx-plugin.deprecated.ts | 1 - .../src/generators/init/init.spec.ts | 14 +- .../playwright/src/generators/init/init.ts | 38 +- .../create-package/create-package.spec.ts | 2 + .../src/generators/e2e-project/e2e.spec.ts | 2 + .../src/generators/executor/executor.spec.ts | 2 + .../generators/generator/generator.spec.ts | 2 + .../generators/lint-checks/generator.spec.ts | 2 + .../generators/migration/migration.spec.ts | 2 + .../src/generators/plugin/plugin.spec.ts | 2 + .../src/generators/preset/generator.spec.ts | 2 + .../specify-output-capture.spec.ts | 2 + .../update-configs-jest-29.spec.ts | 5 +- .../update-tests-jest-29.spec.ts | 6 +- .../update-16-0-0/cli-in-schema-json.spec.ts | 2 + .../application/application.spec.ts | 2 + .../generators/component/component.spec.ts | 2 + .../src/generators/init/init.spec.ts | 2 + .../react-native/src/generators/init/init.ts | 93 ++-- .../src/generators/library/library.spec.ts | 2 + .../src/utils/add-linting.spec.ts | 2 + .../react/plugins/component-testing/index.ts | 2 +- .../application/application.legacy.spec.ts | 2 + .../application/application.spec.ts | 3 +- .../component-cypress-spec.spec.ts | 2 + .../component-story/component-story.spec.ts | 2 + .../component-test/component-test.spec.ts | 2 + .../generators/component/component.spec.ts | 2 + .../cypress-component-configuration.spec.ts | 18 +- .../federate-module/federate-module.spec.ts | 2 + .../react/src/generators/hook/hook.spec.ts | 4 +- .../src/generators/library/library.spec.ts | 2 + .../react/src/generators/redux/redux.spec.ts | 2 + .../src/generators/remote/remote.spec.ts | 3 +- .../generators/stories/stories.app.spec.ts | 2 + .../generators/stories/stories.lib.spec.ts | 2 + .../generators/stories/stories.nextjs.spec.ts | 2 + .../configuration.spec.ts | 2 +- .../src/generators/action/action.impl.spec.ts | 2 + .../application/application.impl.spec.ts | 2 + ...press-component-configuration.impl.spec.ts | 2 + .../remix/src/generators/init/init.spec.ts | 2 + packages/remix/src/generators/init/init.ts | 56 +-- .../generators/library/library.impl.spec.ts | 2 + .../src/generators/loader/loader.impl.spec.ts | 2 + .../src/generators/meta/lib/v2.impl.spec.ts | 2 + .../src/generators/meta/meta.impl.spec.ts | 2 + .../resource-route.impl.spec.ts | 2 + .../src/generators/route/route.impl.spec.ts | 2 + .../setup-tailwind.impl.spec.ts | 2 + .../src/generators/setup/setup.impl.spec.ts | 2 + .../storybook-configuration.impl.spec.ts | 2 + .../src/generators/style/style.impl.spec.ts | 2 + .../configuration/configuration.spec.ts | 2 + .../rollup/src/generators/init/init.spec.ts | 16 +- packages/rollup/src/generators/init/init.ts | 44 +- .../src/generators/init/init.spec.ts | 18 +- .../storybook/src/generators/init/init.ts | 40 +- .../add-addon-essentials-to-all.spec.ts | 2 + packages/storybook/src/utils/utilities.ts | 26 - .../configuration/configuration.spec.ts | 2 + .../vite/src/generators/init/init.spec.ts | 15 +- packages/vite/src/generators/init/init.ts | 33 +- .../vite/src/generators/init/lib/utils.ts | 27 - packages/vite/src/generators/init/schema.d.ts | 1 + .../vite/src/generators/vitest/vitest.spec.ts | 2 + packages/vue/src/generators/init/init.spec.ts | 14 +- .../application/application.legacy.spec.ts | 2 + .../application/application.spec.ts | 2 + .../configuration/configuration.spec.ts | 2 + .../webpack/src/generators/init/init.spec.ts | 2 + packages/webpack/src/generators/init/init.ts | 66 +-- .../convert-to-monorepo.spec.ts | 2 + .../move/lib/check-destination.spec.ts | 2 + .../move/lib/move-project-files.spec.ts | 2 + .../move/lib/update-cypress-config.spec.ts | 2 + .../move/lib/update-eslint-config.spec.ts | 2 + .../move/lib/update-imports.spec.ts | 2 + .../move/lib/update-jest-config.spec.ts | 2 + .../move/lib/update-package-json.spec.ts | 2 + .../lib/update-project-root-files.spec.ts | 2 + .../generators/move/lib/update-readme.spec.ts | 2 + .../move/lib/update-storybook-config.spec.ts | 2 + .../src/generators/move/move.spec.ts | 2 + .../src/generators/preset/preset.spec.ts | 2 + .../remove/lib/remove-project.spec.ts | 2 + .../remove/lib/update-jest-config.spec.ts | 2 + .../run-commands/run-commands.spec.ts | 2 + ...rkspace-generators-to-local-plugin.spec.ts | 2 + 180 files changed, 1815 insertions(+), 1252 deletions(-) create mode 100644 packages/devkit/src/utils/add-plugin.spec.ts rename packages/devkit/src/utils/{update-package-scripts.ts => add-plugin.ts} (50%) delete mode 100644 packages/devkit/src/utils/update-package-scripts.spec.ts delete mode 100644 packages/next/src/generators/init/lib/add-plugin.ts create mode 100644 packages/nx/src/internal-testing-utils/mock-project-graph.ts diff --git a/docs/shared/migration/adding-to-existing-project.md b/docs/shared/migration/adding-to-existing-project.md index 698e5773d19a3..260e2182f5d51 100644 --- a/docs/shared/migration/adding-to-existing-project.md +++ b/docs/shared/migration/adding-to-existing-project.md @@ -1,6 +1,7 @@ # Adding Nx to your Existing Project -Nx can be added to any type of project, not just monorepos. The main benefit is to get caching abilities for the package scripts. Each project usually has a set of scripts in the `package.json`: +Nx can be added to any type of project, not just monorepos. The main benefit is to get caching abilities for the package +scripts. Each project usually has a set of scripts in the `package.json`: ```json {% fileName="package.json" %} { @@ -16,7 +17,8 @@ Nx can be added to any type of project, not just monorepos. The main benefit is You can make these scripts faster by leveraging Nx's caching capabilities. For example: - You change some spec files: in that case the `build` task can be cached and doesn't have to re-run. -- You update your docs, changing a couple of markdown files: then there's no need to re-run builds, tests, linting on your CI. All you might want to do is trigger the Docusaurus build. +- You update your docs, changing a couple of markdown files: then there's no need to re-run builds, tests, linting on + your CI. All you might want to do is trigger the Docusaurus build. ## Install Nx on a Non-Monorepo Project @@ -26,7 +28,55 @@ Run the following command: npx nx@latest init ``` -This will set up Nx for you - updating the `package.json` file and creating a new `nx.json` file with Nx configuration based on your answers during the set up process. The set up process will suggest installing Nx plugins that might be useful based on your existing repository. The example below is using the `@nx/eslint` and `@nx/next` plugins to run ESLint and Next.js tasks with Nx: +Running this command will ask you a few questions about your workspace and then set up Nx for you accordingly. The setup +process detects tools which are used in your workspace and suggests installing Nx plugins to integrate the tools you use +with Nx. Running those tools through Nx will have caching enabled when possible, providing you with a faster alternative +for running those tools. You can start with a few to see how it works and then add more with +the [`nx add`](/nx-api/nx/documents/add) command later. You can also decide to add them all and get the full experience +right +away because adding plugins will not break your existing workflow. + +The first thing you may notice is that Nx updates your `package.json` scripts during the setup process. Nx Plugins setup +Nx commands which run the underlying tool with caching enabled. When a `package.json` script runs a command which can be +run through Nx, Nx will replace that script in the `package.json` scripts with an Nx command that has +caching automatically enabled. Anywhere those `package.json` scripts are used, including your CI, will become faster +when possible. Let's go through an example where the `@nx/next/plugin` and `@nx/eslint/plugin` plugins are added to a +workspace with the +following `package.json`. + +```diff {% fileName="package.json" %} +{ + "name": "my-workspace", + ... + "scripts": { +- "build": "next build && echo 'Build complete'", ++ "build": "nx next:build && echo 'Build complete'", +- "lint": "eslint ./src", ++ "lint": "nx eslint:lint", + "test": "node ./run-tests.js" + }, ++ "nx": {} +} +``` + +The `@nx/next/plugin` plugin adds a `next:build` target which runs `next build` and sets up caching correctly. In other +words, running `nx next:build` is the same as running `next build` with the added benefit of it being cacheable. Hence, +Nx replaces `next build` in the `package.json` `build` script to add caching to anywhere running `npm run build`. +Similarly, `@nx/eslint/plugin` sets up the `nx eslint:lint` command to run `eslint ./src` with caching enabled. +The `test` script was not recognized by any Nx plugin, so it was left as is. After Nx has been setup, +running `npm run build` or `npm run lint` multiple times, will be instant when possible. + +You can also run any npm scripts directly through Nx with `nx build` or `nx lint` which will run the `npm run build` +and `npm run lint` scripts respectively. In the later portion of the setup flow, Nx will ask if you would like some of +those npm scripts to be cacheable. By making those cacheable, running `nx build` rather than `npm run build` will add +another layer of cacheability. However, `nx build` must be run instead of `npm run build` to take advantage of the +cache. + +## Inferred Tasks + +You may have noticed that `@nx/next` provides `dev` and `start` tasks in addition to the `next:build` task. Those tasks +were created by the `@nx/next/plugin` plugin from your existing Next.js configuration. You can see the configuration for +the Nx Plugins in `nx.json`: ```json {% fileName="nx.json" %} { @@ -34,13 +84,13 @@ This will set up Nx for you - updating the `package.json` file and creating a ne { "plugin": "@nx/eslint/plugin", "options": { - "targetName": "lint" + "targetName": "eslint:lint" } }, { "plugin": "@nx/next/plugin", "options": { - "buildTargetName": "build", + "buildTargetName": "next:build", "devTargetName": "dev", "startTargetName": "start" } @@ -49,33 +99,11 @@ This will set up Nx for you - updating the `package.json` file and creating a ne } ``` -When Nx updates your `package.json` scripts, it looks for scripts that can be replaced with an Nx command that has caching automatically enabled. The `package.json` defined above would be updated to look like this: - -```json {% fileName="package.json" %} -{ - "name": "my-workspace", - ... - "scripts": { - "build": "nx build", - "lint": "nx lint", - "test": "node ./run-tests.js" - }, - ... - "nx": { - "includedScripts": [] - } -} -``` - -The `@nx/next` plugin can run `next build` for you and set up caching correctly, so it replaces `next build` with `nx build`. Similarly, `@nx/eslint` can set up caching for `eslint ./src`. When you run `npm run build` or `npm run lint` multiple times, you'll see that caching is enabled. You can also call Nx directly from the terminal with `nx build` or `nx lint`. - -The `test` script was not recognized by any Nx plugin, so it was left as is. - -The `includedScripts` array allows you to specify `package.json` scripts that can be run with the `nx build` syntax. - -## Inferred Tasks +Each plugin can accept options to customize the projects which they create. You can see more information about +configuring the plugins on the [`@nx/next/plugin`](/nx-api/next) and [`@nx/eslint/plugin`](/nx-api/eslint) plugin pages. -You may have noticed that `@nx/next` provides `dev` and `start` tasks in addition to the `build` task. Those tasks were created by the `@nx/next` plugin from your existing Next.js configuration. To view all available tasks, open the Project Details view with Nx Console or use the terminal to launch the project details in a browser window. +To view all available tasks, open the Project Details view with Nx Console or use the terminal to launch the project +details in a browser window. ```shell nx show project my-workspace --web @@ -90,7 +118,7 @@ nx show project my-workspace --web "data": { "root": ".", "targets": { - "lint": { + "eslint:lint": { "cache": true, "options": { "cwd": ".", @@ -107,7 +135,7 @@ nx show project my-workspace --web "executor": "nx:run-commands", "configurations": {} }, - "build": { + "next:build": { "options": { "cwd": ".", "command": "next build" @@ -146,7 +174,6 @@ nx show project my-workspace --web "sourceRoot": ".", "name": "my-workspace", "projectType": "library", - "includedScripts": [], "implicitDependencies": [], "tags": [] } @@ -154,20 +181,20 @@ nx show project my-workspace --web "sourceMap": { "root": ["package.json", "nx/core/package-json-workspaces"], "targets": ["package.json", "nx/core/package-json-workspaces"], - "targets.lint": ["package.json", "@nx/eslint/plugin"], - "targets.lint.command": ["package.json", "@nx/eslint/plugin"], - "targets.lint.cache": ["package.json", "@nx/eslint/plugin"], - "targets.lint.options": ["package.json", "@nx/eslint/plugin"], - "targets.lint.inputs": ["package.json", "@nx/eslint/plugin"], - "targets.lint.options.cwd": ["package.json", "@nx/eslint/plugin"], - "targets.build": ["next.config.js", "@nx/next/plugin"], - "targets.build.command": ["next.config.js", "@nx/next/plugin"], - "targets.build.options": ["next.config.js", "@nx/next/plugin"], - "targets.build.dependsOn": ["next.config.js", "@nx/next/plugin"], - "targets.build.cache": ["next.config.js", "@nx/next/plugin"], - "targets.build.inputs": ["next.config.js", "@nx/next/plugin"], - "targets.build.outputs": ["next.config.js", "@nx/next/plugin"], - "targets.build.options.cwd": ["next.config.js", "@nx/next/plugin"], + "targets.eslint:lint": [".eslintrc.json", "@nx/eslint/plugin"], + "targets.eslint:lint.command": [".eslintrc.json", "@nx/eslint/plugin"], + "targets.eslint:lint.cache": [".eslintrc.json", "@nx/eslint/plugin"], + "targets.eslint:lint.options": [".eslintrc.json", "@nx/eslint/plugin"], + "targets.eslint:lint.inputs": [".eslintrc.json", "@nx/eslint/plugin"], + "targets.eslint:lint.options.cwd": [".eslintrc.json", "@nx/eslint/plugin"], + "targets.next:build": ["next.config.js", "@nx/next/plugin"], + "targets.next:build.command": ["next.config.js", "@nx/next/plugin"], + "targets.next:build.options": ["next.config.js", "@nx/next/plugin"], + "targets.next:build.dependsOn": ["next.config.js", "@nx/next/plugin"], + "targets.next:build.cache": ["next.config.js", "@nx/next/plugin"], + "targets.next:build.inputs": ["next.config.js", "@nx/next/plugin"], + "targets.next:build.outputs": ["next.config.js", "@nx/next/plugin"], + "targets.next:build.options.cwd": ["next.config.js", "@nx/next/plugin"], "targets.dev": ["next.config.js", "@nx/next/plugin"], "targets.dev.command": ["next.config.js", "@nx/next/plugin"], "targets.dev.options": ["next.config.js", "@nx/next/plugin"], @@ -180,7 +207,6 @@ nx show project my-workspace --web "sourceRoot": ["package.json", "nx/core/package-json-workspaces"], "name": ["package.json", "nx/core/package-json-workspaces"], "projectType": ["package.json", "nx/core/package-json-workspaces"], - "includedScripts": ["package.json", "nx/core/package-json-workspaces"], "targets.nx-release-publish": [ "package.json", "nx/core/package-json-workspaces" @@ -203,34 +229,38 @@ nx show project my-workspace --web {% /project-details %} -The project detail view lists all available tasks, the configuration values for those tasks and where those configuration values are being set. +The project detail view lists all available tasks, the configuration values for those tasks and where those +configuration values are being set. ## Configure an Existing Script to Run with Nx If you want to run one of your existing scripts with Nx, you need to tell Nx about it. 1. Preface the script with `nx exec -- ` to have `npm run test` invoke the command with Nx. -2. Add the script to `includedScripts`. -3. Define caching settings. +2. Define caching settings. -The `nx exec` command allows you to keep using `npm test` or `npm run test` (or other package manager's alternatives) as you're accustomed to. But still get the benefits of making those operations cacheable. Configuring the `test` script from the example above to run with Nx would look something like this: +The `nx exec` command allows you to keep using `npm test` or `npm run test` (or other package manager's alternatives) as +you're accustomed to. But still get the benefits of making those operations cacheable. Configuring the `test` script +from the example above to run with Nx would look something like this: ```json {% fileName="package.json" %} { "name": "my-workspace", ... "scripts": { - "build": "nx build", - "lint": "nx lint", + "build": "nx next:build", + "lint": "nx eslint:lint", "test": "nx exec -- node ./run-tests.js" }, ... "nx": { - "includedScripts": ["test"], "targets": { "test": { "cache": "true", - "inputs": ["default", "^default"], + "inputs": [ + "default", + "^default" + ], "outputs": [] } } @@ -238,17 +268,22 @@ The `nx exec` command allows you to keep using `npm test` or `npm run test` (or } ``` -Now if you run `npm run test` or `nx test` twice, the results will be retrieved from the cache. The `inputs` used in this example are as cautious as possible, so you can significantly improve the value of the cache by [customizing Nx Inputs](/recipes/running-tasks/configure-inputs) for each task. +Now if you run `npm run test` or `nx test` twice, the results will be retrieved from the cache. The `inputs` used in +this example are as cautious as possible, so you can significantly improve the value of the cache +by [customizing Nx Inputs](/recipes/running-tasks/configure-inputs) for each task. ## Learn More {% cards %} -{% card title="Customizing Inputs and Named Inputs" description="Learn more about how to fine-tune caching with custom inputs" type="documentation" url="/recipes/running-tasks/configure-inputs" /%} +{% card title="Customizing Inputs and Named Inputs" description="Learn more about how to fine-tune caching with custom +inputs" type="documentation" url="/recipes/running-tasks/configure-inputs" /%} -{% card title="Cache Task Results" description="Learn more about how caching works" type="documentation" url="/features/cache-task-results" /%} +{% card title="Cache Task Results" description="Learn more about how caching works" type="documentation" url=" +/features/cache-task-results" /%} -{% card title="Adding Nx to NPM/Yarn/PNPM Workspace" description="Learn more about how to add Nx to an existing monorepo" type="documentation" url="/recipes/adopting-nx/adding-to-monorepo" /%} +{% card title="Adding Nx to NPM/Yarn/PNPM Workspace" description="Learn more about how to add Nx to an existing +monorepo" type="documentation" url="/recipes/adopting-nx/adding-to-monorepo" /%} {% /cards %} diff --git a/docs/shared/migration/adding-to-monorepo.md b/docs/shared/migration/adding-to-monorepo.md index 1a06ddb4b9a5d..d49271b72df01 100644 --- a/docs/shared/migration/adding-to-monorepo.md +++ b/docs/shared/migration/adding-to-monorepo.md @@ -1,10 +1,13 @@ # Adding Nx to NPM/Yarn/PNPM Workspace {% callout type="note" title="Migrating from Lerna?" %} -Interested in migrating from [Lerna](https://github.com/lerna/lerna) in particular? In case you missed it, Lerna v6 is powering Nx underneath. As a result, Lerna gets all the modern features such as caching and task pipelines. Read more on [https://lerna.js.org/upgrade](https://lerna.js.org/upgrade). +Interested in migrating from [Lerna](https://github.com/lerna/lerna) in particular? In case you missed it, Lerna v6 is +powering Nx underneath. As a result, Lerna gets all the modern features such as caching and task pipelines. Read more +on [https://lerna.js.org/upgrade](https://lerna.js.org/upgrade). {% /callout %} -Nx has first-class support for [monorepos](/getting-started/tutorials/npm-workspaces-tutorial). As a result, if you have an existing NPM/Yarn or PNPM-based monorepo setup, you can easily add Nx to get +Nx has first-class support for [monorepos](/getting-started/tutorials/npm-workspaces-tutorial). As a result, if you have +an existing NPM/Yarn or PNPM-based monorepo setup, you can easily add Nx to get - fast [task scheduling](/features/run-tasks) - support for [task pipelines](/concepts/task-pipeline-configuration) @@ -12,7 +15,8 @@ Nx has first-class support for [monorepos](/getting-started/tutorials/npm-worksp - [remote caching with Nx Cloud](/ci/features/remote-cache) - [distributed task execution with Nx Cloud](/ci/features/distribute-task-execution) -This is a low-impact operation because all that needs to be done is to install the `nx` package at the root level and add an `nx.json` for configuring caching and task pipelines. +This is a low-impact operation because all that needs to be done is to install the `nx` package at the root level and +add an `nx.json` for configuring caching and task pipelines. {% youtube src="https://www.youtube.com/embed/ngdoUQBvAjo" @@ -27,7 +31,55 @@ Run the following command to automatically set up Nx: npx nx@latest init ``` -This will set up Nx for you - updating the `package.json` file and creating a new `nx.json` file with Nx configuration based on your answers during the set up process. The set up process will suggest installing Nx plugins that might be useful based on your existing repository. The example below is using the `@nx/eslint` and `@nx/next` plugins to run ESLint and Next.js tasks with Nx: +Running this command will ask you a few questions about your workspace and then set up Nx for you accordingly. The setup +process detects tools which are used in your workspace and suggests installing Nx plugins to integrate the tools you use +with Nx. Running those tools through Nx will have caching enabled when possible, providing you with a faster alternative +for running those tools. You can start with a few to see how it works and then add more with +the [`nx add`](/nx-api/nx/documents/add) command later. You can also decide to add them all and get the full experience +right +away because adding plugins will not break your existing workflow. + +The first thing you may notice is that Nx updates your `package.json` scripts during the setup process. Nx Plugins setup +Nx commands which run the underlying tool with caching enabled. When a `package.json` script runs a command which can be +run through Nx, Nx will replace that script in the `package.json` scripts with an Nx command that has +caching automatically enabled. Anywhere those `package.json` scripts are used, including your CI, will become faster +when possible. Let's go through an example where the `@nx/next/plugin` and `@nx/eslint/plugin` plugins are added to a +workspace with the +following `package.json`. + +```diff {% fileName="package.json" %} +{ + "name": "my-workspace", + ... + "scripts": { +- "build": "next build && echo 'Build complete'", ++ "build": "nx next:build && echo 'Build complete'", +- "lint": "eslint ./src", ++ "lint": "nx eslint:lint", + "test": "node ./run-tests.js" + }, + ... +} +``` + +The `@nx/next/plugin` plugin adds a `next:build` target which runs `next build` and sets up caching correctly. In other +words, running `nx next:build` is the same as running `next build` with the added benefit of it being cacheable. Hence, +Nx replaces `next build` in the `package.json` `build` script to add caching to anywhere running `npm run build`. +Similarly, `@nx/eslint/plugin` sets up the `nx eslint:lint` command to run `eslint ./src` with caching enabled. +The `test` script was not recognized by any Nx plugin, so it was left as is. After Nx has been setup, +running `npm run build` or `npm run lint` multiple times, will be instant when possible. + +You can also run any npm scripts directly through Nx with `nx build` or `nx lint` which will run the `npm run build` +and `npm run lint` scripts respectively. In the later portion of the setup flow, Nx will ask if you would like some of +those npm scripts to be cacheable. By making those cacheable, running `nx build` rather than `npm run build` will add +another layer of cacheability. However, `nx build` must be run instead of `npm run build` to take advantage of the +cache. + +## Inferred Tasks + +You may have noticed that `@nx/next` provides `dev` and `start` tasks in addition to the `next:build` task. Those tasks +were created by the `@nx/next/plugin` plugin from your existing Next.js configuration. You can see the configuration for +the Nx Plugins in `nx.json`: ```json {% fileName="nx.json" %} { @@ -35,13 +87,13 @@ This will set up Nx for you - updating the `package.json` file and creating a ne { "plugin": "@nx/eslint/plugin", "options": { - "targetName": "lint" + "targetName": "eslint:lint" } }, { "plugin": "@nx/next/plugin", "options": { - "buildTargetName": "build", + "buildTargetName": "next:build", "devTargetName": "dev", "startTargetName": "start" } @@ -50,48 +102,11 @@ This will set up Nx for you - updating the `package.json` file and creating a ne } ``` -When Nx updates your `package.json` scripts, it looks for scripts that can be replaced with an Nx command that has caching automatically enabled. Assuming you initially had a `package.json` file looking like the following: - -```json {% fileName="package.json" %} -{ - "name": "my-workspace", - ... - "scripts": { - "build": "next build", - "lint": "eslint ./src", - "test": "node ./run-tests.js" - }, - ... -} -``` - -After setting up Nx, the `package.json` file would be updated to look like this: - -```json {% fileName="package.json" %} -{ - "name": "my-workspace", - ... - "scripts": { - "build": "nx build", - "lint": "nx lint", - "test": "node ./run-tests.js" - }, - ... - "nx": { - "includedScripts": [] - } -} -``` - -The `@nx/next` plugin can run `next build` for you and set up caching correctly, so it replaces `next build` with `nx build`. Similarly, `@nx/eslint` can set up caching for `eslint ./src`. When you run `npm run build` or `npm run lint` multiple times, you'll see that caching is enabled. You can also call Nx directly from the terminal with `nx build` or `nx lint`. - -The `test` script was not recognized by any Nx plugin, so it was left as is. - -The `includedScripts` array allows you to specify `package.json` scripts that can be run with the `nx build` syntax. - -## Inferred Tasks +Each plugin can accept options to customize the projects which they create. You can see more information about +configuring the plugins on the [`@nx/next/plugin`](/nx-api/next) and [`@nx/eslint/plugin`](/nx-api/eslint) plugin pages. -You may have noticed that `@nx/next` provides `dev` and `start` tasks in addition to the `build` task. Those tasks were created by the `@nx/next` plugin from your existing Next.js configuration. To view all available tasks, open the Project Details view with Nx Console or use the terminal to launch the project details in a browser window. +To view all available tasks, open the Project Details view with Nx Console or use the terminal to launch the project +details in a browser window. ```shell nx show project my-workspace --web @@ -106,7 +121,7 @@ nx show project my-workspace --web "data": { "root": ".", "targets": { - "lint": { + "eslint:lint": { "cache": true, "options": { "cwd": ".", @@ -123,7 +138,7 @@ nx show project my-workspace --web "executor": "nx:run-commands", "configurations": {} }, - "build": { + "next:build": { "options": { "cwd": ".", "command": "next build" @@ -162,7 +177,6 @@ nx show project my-workspace --web "sourceRoot": ".", "name": "my-workspace", "projectType": "library", - "includedScripts": [], "implicitDependencies": [], "tags": [] } @@ -170,20 +184,20 @@ nx show project my-workspace --web "sourceMap": { "root": ["package.json", "nx/core/package-json-workspaces"], "targets": ["package.json", "nx/core/package-json-workspaces"], - "targets.lint": ["package.json", "@nx/eslint/plugin"], - "targets.lint.command": ["package.json", "@nx/eslint/plugin"], - "targets.lint.cache": ["package.json", "@nx/eslint/plugin"], - "targets.lint.options": ["package.json", "@nx/eslint/plugin"], - "targets.lint.inputs": ["package.json", "@nx/eslint/plugin"], - "targets.lint.options.cwd": ["package.json", "@nx/eslint/plugin"], - "targets.build": ["next.config.js", "@nx/next/plugin"], - "targets.build.command": ["next.config.js", "@nx/next/plugin"], - "targets.build.options": ["next.config.js", "@nx/next/plugin"], - "targets.build.dependsOn": ["next.config.js", "@nx/next/plugin"], - "targets.build.cache": ["next.config.js", "@nx/next/plugin"], - "targets.build.inputs": ["next.config.js", "@nx/next/plugin"], - "targets.build.outputs": ["next.config.js", "@nx/next/plugin"], - "targets.build.options.cwd": ["next.config.js", "@nx/next/plugin"], + "targets.eslint:lint": [".eslintrc.json", "@nx/eslint/plugin"], + "targets.eslint:lint.command": [".eslintrc.json", "@nx/eslint/plugin"], + "targets.eslint:lint.cache": [".eslintrc.json", "@nx/eslint/plugin"], + "targets.eslint:lint.options": [".eslintrc.json", "@nx/eslint/plugin"], + "targets.eslint:lint.inputs": [".eslintrc.json", "@nx/eslint/plugin"], + "targets.eslint:lint.options.cwd": [".eslintrc.json", "@nx/eslint/plugin"], + "targets.next:build": ["next.config.js", "@nx/next/plugin"], + "targets.next:build.command": ["next.config.js", "@nx/next/plugin"], + "targets.next:build.options": ["next.config.js", "@nx/next/plugin"], + "targets.next:build.dependsOn": ["next.config.js", "@nx/next/plugin"], + "targets.next:build.cache": ["next.config.js", "@nx/next/plugin"], + "targets.next:build.inputs": ["next.config.js", "@nx/next/plugin"], + "targets.next:build.outputs": ["next.config.js", "@nx/next/plugin"], + "targets.next:build.options.cwd": ["next.config.js", "@nx/next/plugin"], "targets.dev": ["next.config.js", "@nx/next/plugin"], "targets.dev.command": ["next.config.js", "@nx/next/plugin"], "targets.dev.options": ["next.config.js", "@nx/next/plugin"], @@ -196,7 +210,6 @@ nx show project my-workspace --web "sourceRoot": ["package.json", "nx/core/package-json-workspaces"], "name": ["package.json", "nx/core/package-json-workspaces"], "projectType": ["package.json", "nx/core/package-json-workspaces"], - "includedScripts": ["package.json", "nx/core/package-json-workspaces"], "targets.nx-release-publish": [ "package.json", "nx/core/package-json-workspaces" @@ -219,34 +232,38 @@ nx show project my-workspace --web {% /project-details %} -The project detail view lists all available tasks, the configuration values for those tasks and where those configuration values are being set. +The project detail view lists all available tasks, the configuration values for those tasks and where those +configuration values are being set. ## Configure an Existing Script to Run with Nx If you want to run one of your existing scripts with Nx, you need to tell Nx about it. 1. Preface the script with `nx exec -- ` to have `npm run test` invoke the command with Nx. -2. Add the script to `includedScripts`. -3. Define caching settings. +2. Define caching settings. -The `nx exec` command allows you to keep using `npm test` or `npm run test` (or other package manager's alternatives) as you're accustomed to. But still get the benefits of making those operations cacheable. Configuring the `test` script from the example above to run with Nx would look something like this: +The `nx exec` command allows you to keep using `npm test` or `npm run test` (or other package manager's alternatives) as +you're accustomed to. But still get the benefits of making those operations cacheable. Configuring the `test` script +from the example above to run with Nx would look something like this: ```json {% fileName="package.json" %} { "name": "my-workspace", ... "scripts": { - "build": "nx build", - "lint": "nx lint", + "build": "nx next:build", + "lint": "nx eslint:lint", "test": "nx exec -- node ./run-tests.js" }, ... "nx": { - "includedScripts": ["test"], "targets": { "test": { "cache": "true", - "inputs": ["default", "^default"], + "inputs": [ + "default", + "^default" + ], "outputs": [] } } @@ -254,11 +271,14 @@ The `nx exec` command allows you to keep using `npm test` or `npm run test` (or } ``` -Now if you run `npm run test` or `nx test` twice, the results will be retrieved from the cache. The `inputs` used in this example are as cautious as possible, so you can significantly improve the value of the cache by [customizing Nx Inputs](/recipes/running-tasks/configure-inputs) for each task. +Now if you run `npm run test` or `nx test` twice, the results will be retrieved from the cache. The `inputs` used in +this example are as cautious as possible, so you can significantly improve the value of the cache +by [customizing Nx Inputs](/recipes/running-tasks/configure-inputs) for each task. ## Incrementally Adopting Nx -All the features of Nx can be enabled independently of each other. Hence, Nx can easily be adopted incrementally by initially using Nx just for a subset of your scripts and then gradually adding more. +All the features of Nx can be enabled independently of each other. Hence, Nx can easily be adopted incrementally by +initially using Nx just for a subset of your scripts and then gradually adding more. For example, use Nx to run your builds: @@ -266,7 +286,8 @@ For example, use Nx to run your builds: npx nx run-many -t build ``` -But instead keep using NPM/Yarn/PNPM workspace commands for your tests and other scripts. Here's an example of using PNPM commands to run tests across packages +But instead keep using NPM/Yarn/PNPM workspace commands for your tests and other scripts. Here's an example of using +PNPM commands to run tests across packages ```shell pnpm run -r test @@ -278,14 +299,19 @@ This allows for incrementally adopting Nx in your existing workspace. {% cards %} -{% card title="Cache Task Results" description="Learn more about how caching works" type="documentation" url="/features/cache-task-results" /%} +{% card title="Cache Task Results" description="Learn more about how caching works" type="documentation" url=" +/features/cache-task-results" /%} -{% card title="Task Pipeline Configuration" description="Learn more about how to setup task dependencies" type="documentation" url="/concepts/task-pipeline-configuration" /%} +{% card title="Task Pipeline Configuration" description="Learn more about how to setup task dependencies" type=" +documentation" url="/concepts/task-pipeline-configuration" /%} -{% card title="Nx Ignore" description="Learn about how to ignore certain projects using .nxignore" type="documentation" url="/reference/nxignore" /%} +{% card title="Nx Ignore" description="Learn about how to ignore certain projects using .nxignore" type="documentation" +url="/reference/nxignore" /%} -{% card title="Nx and Turbo" description="Read about how Nx compares to Turborepo" url="/concepts/more-concepts/turbo-and-nx" /%} +{% card title="Nx and Turbo" description="Read about how Nx compares to Turborepo" url=" +/concepts/more-concepts/turbo-and-nx" /%} -{% card title="Integrated Repos vs Package-Based Repos" description="Learn about two styles of monorepos." url="/concepts/integrated-vs-package-based" /%} +{% card title="Integrated Repos vs Package-Based Repos" description="Learn about two styles of monorepos." url=" +/concepts/integrated-vs-package-based" /%} {% /cards %} diff --git a/e2e/detox/src/detox-legacy.test.ts b/e2e/detox/src/detox-legacy.test.ts index 5a8dd5bf88b86..405da62cfa565 100644 --- a/e2e/detox/src/detox-legacy.test.ts +++ b/e2e/detox/src/detox-legacy.test.ts @@ -11,17 +11,22 @@ import { describe('@nx/detox (legacy)', () => { const appName = uniq('myapp'); + let originalEnv: string; beforeAll(() => { + originalEnv = process.env.NX_ADD_PLUGINS; + process.env.NX_ADD_PLUGINS = 'false'; newProject(); }); - afterAll(() => cleanupProject()); + afterAll(() => { + process.env.NX_ADD_PLUGINS = originalEnv; + cleanupProject(); + }); it('should create files and run lint command for react-native apps', async () => { runCLI( - `generate @nx/react-native:app ${appName} --e2eTestRunner=detox --linter=eslint --install=false`, - { env: { NX_ADD_PLUGINS: 'false' } } + `generate @nx/react-native:app ${appName} --e2eTestRunner=detox --linter=eslint --install=false` ); checkFilesExist(`apps/${appName}-e2e/.detoxrc.json`); checkFilesExist(`apps/${appName}-e2e/tsconfig.json`); @@ -38,8 +43,7 @@ describe('@nx/detox (legacy)', () => { it('should create files and run lint command for expo apps', async () => { const expoAppName = uniq('myapp'); runCLI( - `generate @nx/expo:app ${expoAppName} --e2eTestRunner=detox --linter=eslint`, - { env: { NX_ADD_PLUGINS: 'false' } } + `generate @nx/expo:app ${expoAppName} --e2eTestRunner=detox --linter=eslint` ); checkFilesExist(`apps/${expoAppName}-e2e/.detoxrc.json`); checkFilesExist(`apps/${expoAppName}-e2e/tsconfig.json`); @@ -57,8 +61,7 @@ describe('@nx/detox (legacy)', () => { const appName = uniq('app1'); runCLI( - `generate @nx/react-native:app ${appName} --e2eTestRunner=detox --linter=eslint --install=false --project-name-and-root-format=as-provided --interactive=false`, - { env: { NX_ADD_PLUGINS: 'false' } } + `generate @nx/react-native:app ${appName} --e2eTestRunner=detox --linter=eslint --install=false --project-name-and-root-format=as-provided --interactive=false` ); // check files are generated without the layout directory ("apps/") and diff --git a/e2e/expo/src/expo-legacy.test.ts b/e2e/expo/src/expo-legacy.test.ts index 2ba7579f4d70f..b33e7d54c5876 100644 --- a/e2e/expo/src/expo-legacy.test.ts +++ b/e2e/expo/src/expo-legacy.test.ts @@ -23,10 +23,15 @@ describe('@nx/expo (legacy)', () => { let proj: string; let appName = uniq('my-app'); let libName = uniq('lib'); + let originalEnv: string; beforeAll(() => { proj = newProject({ packages: ['@nx/expo'] }); // we create empty preset above which skips creation of `production` named input + + originalEnv = process.env.NX_ADD_PLUGINS; + process.env.NX_ADD_PLUGINS = 'false'; + updateJson('nx.json', (nxJson) => { nxJson.namedInputs = { default: ['{projectRoot}/**/*', 'sharedGlobals'], @@ -36,14 +41,16 @@ describe('@nx/expo (legacy)', () => { return nxJson; }); runCLI( - `generate @nx/expo:application ${appName} --e2eTestRunner=cypress --no-interactive`, - { env: { NX_ADD_PLUGINS: 'false' } } + `generate @nx/expo:application ${appName} --e2eTestRunner=cypress --no-interactive` ); runCLI( `generate @nx/expo:library ${libName} --buildable --publishable --importPath=${proj}/${libName}` ); }); - afterAll(() => cleanupProject()); + afterAll(() => { + process.env.NX_ADD_PLUGINS = originalEnv; + cleanupProject(); + }); it('should test and lint', async () => { const componentName = uniq('Component'); @@ -193,8 +200,7 @@ describe('@nx/expo (legacy)', () => { const libName = uniq('@my-org/lib1'); runCLI( - `generate @nx/expo:application ${appName} --project-name-and-root-format=as-provided --no-interactive`, - { env: { NX_ADD_PLUGINS: 'false' } } + `generate @nx/expo:application ${appName} --project-name-and-root-format=as-provided --no-interactive` ); // check files are generated without the layout directory ("apps/") and @@ -268,8 +274,7 @@ describe('@nx/expo (legacy)', () => { it('should run e2e for playwright', async () => { const appName2 = uniq('my-app'); runCLI( - `generate @nx/expo:application ${appName2} --e2eTestRunner=playwright --no-interactive`, - { env: { NX_ADD_PLUGINS: 'false' } } + `generate @nx/expo:application ${appName2} --e2eTestRunner=playwright --no-interactive` ); if (runE2ETests()) { const results = runCLI(`e2e ${appName2}-e2e`, { verbose: true }); diff --git a/e2e/react-native/src/react-native-legacy.test.ts b/e2e/react-native/src/react-native-legacy.test.ts index eae99ada9b1d7..a4b81d2c4936a 100644 --- a/e2e/react-native/src/react-native-legacy.test.ts +++ b/e2e/react-native/src/react-native-legacy.test.ts @@ -23,8 +23,12 @@ describe('@nx/react-native (legacy)', () => { let proj: string; let appName = uniq('my-app'); let libName = uniq('lib'); + let originalEnv: string; beforeAll(() => { + originalEnv = process.env.NX_ADD_PLUGINS; + process.env.NX_ADD_PLUGINS = 'false'; + proj = newProject(); // we create empty preset above which skips creation of `production` named input updateJson('nx.json', (nxJson) => { @@ -36,14 +40,16 @@ describe('@nx/react-native (legacy)', () => { return nxJson; }); runCLI( - `generate @nx/react-native:application ${appName} --bunlder=webpack --e2eTestRunner=cypress --install=false --no-interactive`, - { env: { NX_ADD_PLUGINS: 'false' } } + `generate @nx/react-native:application ${appName} --bunlder=webpack --e2eTestRunner=cypress --install=false --no-interactive` ); runCLI( `generate @nx/react-native:library ${libName} --buildable --publishable --importPath=${proj}/${libName} --no-interactive` ); }); - afterAll(() => cleanupProject()); + afterAll(() => { + process.env.NX_ADD_PLUGINS = originalEnv; + cleanupProject(); + }); it('should build for web', async () => { const results = runCLI(`build ${appName}`); @@ -269,8 +275,7 @@ describe('@nx/react-native (legacy)', () => { const libName = uniq('@my-org/lib1'); runCLI( - `generate @nx/react-native:application ${appName} --project-name-and-root-format=as-provided --install=false --no-interactive`, - { env: { NX_ADD_PLUGINS: 'false' } } + `generate @nx/react-native:application ${appName} --project-name-and-root-format=as-provided --install=false --no-interactive` ); // check files are generated without the layout directory ("apps/") and @@ -306,8 +311,7 @@ describe('@nx/react-native (legacy)', () => { it('should run build with vite bundler and e2e with playwright', async () => { const appName2 = uniq('my-app'); runCLI( - `generate @nx/react-native:application ${appName2} --bundler=vite --e2eTestRunner=playwright --install=false --no-interactive`, - { env: { NX_ADD_PLUGINS: 'false' } } + `generate @nx/react-native:application ${appName2} --bundler=vite --e2eTestRunner=playwright --install=false --no-interactive` ); const buildResults = runCLI(`build ${appName2}`); expect(buildResults).toContain('Successfully ran target build'); diff --git a/packages/angular/plugins/component-testing.ts b/packages/angular/plugins/component-testing.ts index 0ddd3a126f38a..25c385d2b6a67 100644 --- a/packages/angular/plugins/component-testing.ts +++ b/packages/angular/plugins/component-testing.ts @@ -47,7 +47,7 @@ export function nxComponentTestingPreset( pathToConfig: string, options?: NxComponentTestingOptions ) { - if (global.NX_GRAPH_CREATION || global.NX_CYPRESS_INIT_GENERATOR_RUNNING) { + if (global.NX_GRAPH_CREATION) { // this is only used by plugins, so we don't need the component testing // options, cast to any to avoid type errors return nxBaseCypressPreset(pathToConfig, { diff --git a/packages/angular/src/generators/add-linting/add-linting.spec.ts b/packages/angular/src/generators/add-linting/add-linting.spec.ts index a2ad38741af00..140b17f1007a4 100644 --- a/packages/angular/src/generators/add-linting/add-linting.spec.ts +++ b/packages/angular/src/generators/add-linting/add-linting.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { ProjectConfiguration, Tree, diff --git a/packages/angular/src/generators/application/application.spec.ts b/packages/angular/src/generators/application/application.spec.ts index f9a00cb4a3ace..514129d1c5b6b 100644 --- a/packages/angular/src/generators/application/application.spec.ts +++ b/packages/angular/src/generators/application/application.spec.ts @@ -32,6 +32,10 @@ jest.mock('@nx/devkit', () => { return { ...original, ensurePackage: (pkg: string) => jest.requireActual(pkg), + createProjectGraphAsync: jest.fn().mockResolvedValue({ + nodes: {}, + dependencies: {}, + }), }; }); diff --git a/packages/angular/src/generators/component-cypress-spec/component-cypress-spec.spec.ts b/packages/angular/src/generators/component-cypress-spec/component-cypress-spec.spec.ts index 45c69d06daa1b..db2d419fb5762 100644 --- a/packages/angular/src/generators/component-cypress-spec/component-cypress-spec.spec.ts +++ b/packages/angular/src/generators/component-cypress-spec/component-cypress-spec.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { installedCypressVersion } from '@nx/cypress/src/utils/cypress-version'; import type { Tree } from '@nx/devkit'; import * as devkit from '@nx/devkit'; diff --git a/packages/angular/src/generators/component-story/component-story.spec.ts b/packages/angular/src/generators/component-story/component-story.spec.ts index d46a08fae05a2..a18c072b0cc0e 100644 --- a/packages/angular/src/generators/component-story/component-story.spec.ts +++ b/packages/angular/src/generators/component-story/component-story.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import type { Tree } from '@nx/devkit'; import * as devkit from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; diff --git a/packages/angular/src/generators/component-test/component-test.spec.ts b/packages/angular/src/generators/component-test/component-test.spec.ts index 0a56ee6248453..190dce7ee2758 100644 --- a/packages/angular/src/generators/component-test/component-test.spec.ts +++ b/packages/angular/src/generators/component-test/component-test.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { assertMinimumCypressVersion } from '@nx/cypress/src/utils/cypress-version'; import { Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; diff --git a/packages/angular/src/generators/cypress-component-configuration/cypress-component-configuration.spec.ts b/packages/angular/src/generators/cypress-component-configuration/cypress-component-configuration.spec.ts index 605fa1c11c67c..0a318c4b0c246 100644 --- a/packages/angular/src/generators/cypress-component-configuration/cypress-component-configuration.spec.ts +++ b/packages/angular/src/generators/cypress-component-configuration/cypress-component-configuration.spec.ts @@ -9,19 +9,21 @@ import { updateProjectConfiguration, } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import { componentGenerator } from '../component/component'; -import { librarySecondaryEntryPointGenerator } from '../library-secondary-entry-point/library-secondary-entry-point'; -import { generateTestApplication, generateTestLibrary } from '../utils/testing'; -import { cypressComponentConfiguration } from './cypress-component-configuration'; let projectGraph: ProjectGraph = { nodes: {}, dependencies: {} }; -jest.mock('@nx/cypress/src/utils/cypress-version'); jest.mock('@nx/devkit', () => ({ ...jest.requireActual('@nx/devkit'), createProjectGraphAsync: jest .fn() .mockImplementation(async () => projectGraph), })); + +import { componentGenerator } from '../component/component'; +import { librarySecondaryEntryPointGenerator } from '../library-secondary-entry-point/library-secondary-entry-point'; +import { generateTestApplication, generateTestLibrary } from '../utils/testing'; +import { cypressComponentConfiguration } from './cypress-component-configuration'; + +jest.mock('@nx/cypress/src/utils/cypress-version'); // nested code imports graph from the repo, which might have innacurate graph version jest.mock('nx/src/project-graph/project-graph', () => ({ ...jest.requireActual('nx/src/project-graph/project-graph'), diff --git a/packages/angular/src/generators/federate-module/federate-module.spec.ts b/packages/angular/src/generators/federate-module/federate-module.spec.ts index 94458d6beffaa..b0f1722046009 100644 --- a/packages/angular/src/generators/federate-module/federate-module.spec.ts +++ b/packages/angular/src/generators/federate-module/federate-module.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { getProjects } from '@nx/devkit'; import { Schema } from './schema'; import { Schema as remoteSchma } from '../remote/schema'; diff --git a/packages/angular/src/generators/host/host.spec.ts b/packages/angular/src/generators/host/host.spec.ts index 183b9c260d01c..18d8eb53f994c 100644 --- a/packages/angular/src/generators/host/host.spec.ts +++ b/packages/angular/src/generators/host/host.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { readJson, updateJson } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { diff --git a/packages/angular/src/generators/library-secondary-entry-point/library-secondary-entry-point.spec.ts b/packages/angular/src/generators/library-secondary-entry-point/library-secondary-entry-point.spec.ts index 987a46c3c0a9d..1c6f10309c0c2 100644 --- a/packages/angular/src/generators/library-secondary-entry-point/library-secondary-entry-point.spec.ts +++ b/packages/angular/src/generators/library-secondary-entry-point/library-secondary-entry-point.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import * as devkit from '@nx/devkit'; import { addProjectConfiguration, readJson, Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; diff --git a/packages/angular/src/generators/library/library.spec.ts b/packages/angular/src/generators/library/library.spec.ts index 19dd1eb31eca1..5dfa64c650a92 100644 --- a/packages/angular/src/generators/library/library.spec.ts +++ b/packages/angular/src/generators/library/library.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { getProjects, NxJsonConfiguration, diff --git a/packages/angular/src/generators/move/move.spec.ts b/packages/angular/src/generators/move/move.spec.ts index 34c978ae1f151..2cddb74e85082 100644 --- a/packages/angular/src/generators/move/move.spec.ts +++ b/packages/angular/src/generators/move/move.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import * as devkit from '@nx/devkit'; import { ProjectGraph, readJson, Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; diff --git a/packages/angular/src/generators/ng-add/migrate-from-angular-cli.spec.ts b/packages/angular/src/generators/ng-add/migrate-from-angular-cli.spec.ts index 008d41f2cc779..14d19e00f53b9 100644 --- a/packages/angular/src/generators/ng-add/migrate-from-angular-cli.spec.ts +++ b/packages/angular/src/generators/ng-add/migrate-from-angular-cli.spec.ts @@ -1,4 +1,6 @@ -import type { Tree } from '@nx/devkit'; +import 'nx/src/internal-testing-utils/mock-project-graph'; + +import { Tree } from '@nx/devkit'; import { readJson, readProjectConfiguration, diff --git a/packages/angular/src/generators/ng-add/migrators/projects/app.migrator.spec.ts b/packages/angular/src/generators/ng-add/migrators/projects/app.migrator.spec.ts index 75f9d4f52739b..9be7711bf1a66 100644 --- a/packages/angular/src/generators/ng-add/migrators/projects/app.migrator.spec.ts +++ b/packages/angular/src/generators/ng-add/migrators/projects/app.migrator.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import type { ProjectConfiguration, TargetConfiguration, diff --git a/packages/angular/src/generators/ng-add/migrators/projects/e2e.migrator.spec.ts b/packages/angular/src/generators/ng-add/migrators/projects/e2e.migrator.spec.ts index a136262d2e061..41573440e27c5 100644 --- a/packages/angular/src/generators/ng-add/migrators/projects/e2e.migrator.spec.ts +++ b/packages/angular/src/generators/ng-add/migrators/projects/e2e.migrator.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + // mock so we can test multiple versions jest.mock('@nx/cypress/src/utils/cypress-version'); // mock bc the nxE2EPreset uses fs for path normalization diff --git a/packages/angular/src/generators/ngrx-feature-store/ngrx-feature-store.spec.ts b/packages/angular/src/generators/ngrx-feature-store/ngrx-feature-store.spec.ts index e6769a768d551..df0332ea9fa92 100644 --- a/packages/angular/src/generators/ngrx-feature-store/ngrx-feature-store.spec.ts +++ b/packages/angular/src/generators/ngrx-feature-store/ngrx-feature-store.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import type { Tree } from '@nx/devkit'; import { readJson } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; diff --git a/packages/angular/src/generators/ngrx-root-store/ngrx-root-store.spec.ts b/packages/angular/src/generators/ngrx-root-store/ngrx-root-store.spec.ts index 2c65bcd3490d7..7148489abe09b 100644 --- a/packages/angular/src/generators/ngrx-root-store/ngrx-root-store.spec.ts +++ b/packages/angular/src/generators/ngrx-root-store/ngrx-root-store.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import type { Tree } from '@nx/devkit'; import { readJson } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; diff --git a/packages/angular/src/generators/ngrx/ngrx.spec.ts b/packages/angular/src/generators/ngrx/ngrx.spec.ts index b55f0335dcf03..72b2e3ea32d4c 100644 --- a/packages/angular/src/generators/ngrx/ngrx.spec.ts +++ b/packages/angular/src/generators/ngrx/ngrx.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import type { Tree } from '@nx/devkit'; import * as devkit from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; diff --git a/packages/angular/src/generators/remote/remote.spec.ts b/packages/angular/src/generators/remote/remote.spec.ts index a60faeb6501ab..8e2fbb78685ae 100644 --- a/packages/angular/src/generators/remote/remote.spec.ts +++ b/packages/angular/src/generators/remote/remote.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { E2eTestRunner } from '../../utils/test-runners'; import { getProjects, diff --git a/packages/angular/src/generators/scam-to-standalone/scam-to-standalone.spec.ts b/packages/angular/src/generators/scam-to-standalone/scam-to-standalone.spec.ts index a49a80b5fda89..87e89d3007395 100644 --- a/packages/angular/src/generators/scam-to-standalone/scam-to-standalone.spec.ts +++ b/packages/angular/src/generators/scam-to-standalone/scam-to-standalone.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import scamGenerator from '../scam/scam'; import { generateTestApplication } from '../utils/testing'; diff --git a/packages/angular/src/generators/setup-ssr/setup-ssr.spec.ts b/packages/angular/src/generators/setup-ssr/setup-ssr.spec.ts index a49a6433afb66..fb18673bf58f2 100644 --- a/packages/angular/src/generators/setup-ssr/setup-ssr.spec.ts +++ b/packages/angular/src/generators/setup-ssr/setup-ssr.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { NxJsonConfiguration, readJson, diff --git a/packages/angular/src/generators/stories/stories-app.spec.ts b/packages/angular/src/generators/stories/stories-app.spec.ts index fb924e816b2b6..7d67280605dba 100644 --- a/packages/angular/src/generators/stories/stories-app.spec.ts +++ b/packages/angular/src/generators/stories/stories-app.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { installedCypressVersion } from '@nx/cypress/src/utils/cypress-version'; import type { Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; diff --git a/packages/angular/src/generators/stories/stories-lib.spec.ts b/packages/angular/src/generators/stories/stories-lib.spec.ts index 77b6831003500..0d47aa130c2fd 100644 --- a/packages/angular/src/generators/stories/stories-lib.spec.ts +++ b/packages/angular/src/generators/stories/stories-lib.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { installedCypressVersion } from '@nx/cypress/src/utils/cypress-version'; import { Tree } from '@nx/devkit'; import { writeJson } from '@nx/devkit'; diff --git a/packages/angular/src/generators/web-worker/web-worker.spec.ts b/packages/angular/src/generators/web-worker/web-worker.spec.ts index b250f789f1ff0..fc298a45d93ab 100644 --- a/packages/angular/src/generators/web-worker/web-worker.spec.ts +++ b/packages/angular/src/generators/web-worker/web-worker.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import type { Tree } from '@nx/devkit'; import * as devkit from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; diff --git a/packages/angular/src/migrations/update-14-8-0/rename-webpack-server.spec.ts b/packages/angular/src/migrations/update-14-8-0/rename-webpack-server.spec.ts index afee0425060d4..707a28f9edb71 100644 --- a/packages/angular/src/migrations/update-14-8-0/rename-webpack-server.spec.ts +++ b/packages/angular/src/migrations/update-14-8-0/rename-webpack-server.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { readJson, updateJson } from '@nx/devkit'; import * as devkit from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; diff --git a/packages/angular/src/migrations/update-15-2-0/remove-browserlist-config.spec.ts b/packages/angular/src/migrations/update-15-2-0/remove-browserlist-config.spec.ts index a543dc79cb164..9be54c6387f12 100644 --- a/packages/angular/src/migrations/update-15-2-0/remove-browserlist-config.spec.ts +++ b/packages/angular/src/migrations/update-15-2-0/remove-browserlist-config.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import type { Tree } from '@nx/devkit'; import * as devkit from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; diff --git a/packages/angular/src/migrations/update-15-2-0/remove-browserlist-config.ts b/packages/angular/src/migrations/update-15-2-0/remove-browserlist-config.ts index f24952a52dcd5..94dabd5a94804 100644 --- a/packages/angular/src/migrations/update-15-2-0/remove-browserlist-config.ts +++ b/packages/angular/src/migrations/update-15-2-0/remove-browserlist-config.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import type { Tree } from '@nx/devkit'; import { logger, visitNotIgnoredFiles } from '@nx/devkit'; import { basename } from 'path'; diff --git a/packages/angular/src/migrations/update-15-2-0/update-typescript-target.spec.ts b/packages/angular/src/migrations/update-15-2-0/update-typescript-target.spec.ts index d41cf1c8cbff0..46b5d45687dfb 100644 --- a/packages/angular/src/migrations/update-15-2-0/update-typescript-target.spec.ts +++ b/packages/angular/src/migrations/update-15-2-0/update-typescript-target.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { readJson, readProjectConfiguration, diff --git a/packages/angular/src/migrations/update-15-2-0/update-workspace-config.spec.ts b/packages/angular/src/migrations/update-15-2-0/update-workspace-config.spec.ts index a2d8e4a51bfac..3c5967bd06bcf 100644 --- a/packages/angular/src/migrations/update-15-2-0/update-workspace-config.spec.ts +++ b/packages/angular/src/migrations/update-15-2-0/update-workspace-config.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import * as devkit from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { Builders } from '@schematics/angular/utility/workspace-models'; diff --git a/packages/cypress/src/generators/component-configuration/component-configuration.spec.ts b/packages/cypress/src/generators/component-configuration/component-configuration.spec.ts index 01267532c489b..cc24a75fcce2d 100644 --- a/packages/cypress/src/generators/component-configuration/component-configuration.spec.ts +++ b/packages/cypress/src/generators/component-configuration/component-configuration.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { addProjectConfiguration, ProjectConfiguration, diff --git a/packages/cypress/src/generators/configuration/configuration.spec.ts b/packages/cypress/src/generators/configuration/configuration.spec.ts index 703118ae0176b..449b1e22b30e7 100644 --- a/packages/cypress/src/generators/configuration/configuration.spec.ts +++ b/packages/cypress/src/generators/configuration/configuration.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { addProjectConfiguration, ProjectConfiguration, diff --git a/packages/cypress/src/generators/configuration/configuration.ts b/packages/cypress/src/generators/configuration/configuration.ts index 80049da8e52c9..8635ee5f9664c 100644 --- a/packages/cypress/src/generators/configuration/configuration.ts +++ b/packages/cypress/src/generators/configuration/configuration.ts @@ -70,6 +70,7 @@ export async function configurationGeneratorInternal( opts.addPlugin ??= process.env.NX_ADD_PLUGINS !== 'false'; const tasks: GeneratorCallback[] = []; + const projectGraph = await createProjectGraphAsync(); if (!installedCypressVersion()) { tasks.push(await jsInitGenerator(tree, { ...options, skipFormat: true })); tasks.push( @@ -79,10 +80,9 @@ export async function configurationGeneratorInternal( }) ); } else if (opts.addPlugin) { - addPlugin(tree); + await addPlugin(tree, projectGraph, false); } - const projectGraph = await createProjectGraphAsync(); const nxJson = readNxJson(tree); const hasPlugin = nxJson.plugins?.some((p) => typeof p === 'string' diff --git a/packages/cypress/src/generators/cypress-project/cypress-project.spec.ts b/packages/cypress/src/generators/cypress-project/cypress-project.spec.ts index 88c80119fa382..f9f811c11655f 100644 --- a/packages/cypress/src/generators/cypress-project/cypress-project.spec.ts +++ b/packages/cypress/src/generators/cypress-project/cypress-project.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { addProjectConfiguration, readJson, diff --git a/packages/cypress/src/generators/init/init.spec.ts b/packages/cypress/src/generators/init/init.spec.ts index 0b43f78e4aa66..d75397a3a3395 100644 --- a/packages/cypress/src/generators/init/init.spec.ts +++ b/packages/cypress/src/generators/init/init.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { NxJsonConfiguration, readJson, Tree, updateJson } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; diff --git a/packages/cypress/src/generators/init/init.ts b/packages/cypress/src/generators/init/init.ts index f4b0fafc864cc..f4d633d87049d 100644 --- a/packages/cypress/src/generators/init/init.ts +++ b/packages/cypress/src/generators/init/init.ts @@ -1,14 +1,19 @@ import { addDependenciesToPackageJson, + createProjectGraphAsync, formatFiles, GeneratorCallback, + ProjectGraph, readNxJson, removeDependenciesFromPackageJson, runTasksInSerial, Tree, updateNxJson, } from '@nx/devkit'; -import { updatePackageScripts } from '@nx/devkit/src/utils/update-package-scripts'; +import { + addPlugin as _addPlugin, + generateCombinations, +} from '@nx/devkit/src/utils/add-plugin'; import { createNodes } from '../../plugins/plugin'; import { cypressVersion, nxVersion } from '../../utils/versions'; import { Schema } from './schema'; @@ -55,30 +60,28 @@ function updateDependencies(tree: Tree, options: Schema) { return runTasksInSerial(...tasks); } -export function addPlugin(tree: Tree) { - const nxJson = readNxJson(tree); - nxJson.plugins ??= []; - - for (const plugin of nxJson.plugins) { - if ( - typeof plugin === 'string' - ? plugin === '@nx/cypress/plugin' - : plugin.plugin === '@nx/cypress/plugin' - ) { - return; - } - } - - nxJson.plugins.push({ - plugin: '@nx/cypress/plugin', - options: { - targetName: 'e2e', - componentTestingTargetName: 'component-test', - ciTargetName: 'e2e-ci', - openTargetName: 'open-cypress', - } as CypressPluginOptions, - }); - updateNxJson(tree, nxJson); +export function addPlugin( + tree: Tree, + graph: ProjectGraph, + updatePackageScripts: boolean +) { + return _addPlugin( + tree, + graph, + '@nx/cypress/plugin', + createNodes, + { + targetName: ['e2e', 'cypress:e2e', 'cypress-e2e'], + openTargetName: ['open-cypress', 'cypress-open'], + componentTestingTargetName: [ + 'component-test', + 'cypress:component-test', + 'cypress-component-test', + ], + ciTargetName: ['e2e-ci', 'cypress:e2e-ci', 'cypress-e2e-ci'], + }, + updatePackageScripts + ); } function updateProductionFileset(tree: Tree) { @@ -115,7 +118,11 @@ export async function cypressInitGeneratorInternal( nxJson.useInferencePlugins !== false; if (options.addPlugin) { - addPlugin(tree); + await addPlugin( + tree, + await createProjectGraphAsync(), + options.updatePackageScripts + ); } else { setupE2ETargetDefaults(tree); } @@ -125,12 +132,6 @@ export async function cypressInitGeneratorInternal( installTask = updateDependencies(tree, options); } - if (options.updatePackageScripts) { - global.NX_CYPRESS_INIT_GENERATOR_RUNNING = true; - await updatePackageScripts(tree, createNodes); - global.NX_CYPRESS_INIT_GENERATOR_RUNNING = false; - } - if (!options.skipFormat) { await formatFiles(tree); } diff --git a/packages/cypress/src/generators/migrate-to-cypress-11/migrate-to-cypress-11.spec.ts b/packages/cypress/src/generators/migrate-to-cypress-11/migrate-to-cypress-11.spec.ts index 096c504355b79..99a2a7c040f76 100644 --- a/packages/cypress/src/generators/migrate-to-cypress-11/migrate-to-cypress-11.spec.ts +++ b/packages/cypress/src/generators/migrate-to-cypress-11/migrate-to-cypress-11.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { addProjectConfiguration, joinPathFragments, diff --git a/packages/cypress/src/migrations/update-15-1-0/cypress-11.spec.ts b/packages/cypress/src/migrations/update-15-1-0/cypress-11.spec.ts index ee3659ff76084..ec83540f2f87c 100644 --- a/packages/cypress/src/migrations/update-15-1-0/cypress-11.spec.ts +++ b/packages/cypress/src/migrations/update-15-1-0/cypress-11.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { addProjectConfiguration, readProjectConfiguration, @@ -8,6 +10,7 @@ import { libraryGenerator } from '@nx/js'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import updateToCypress11 from './cypress-11'; import { installedCypressVersion } from '../../utils/cypress-version'; + jest.mock('../../utils/cypress-version'); import cypressComponentConfiguration from '../../generators/component-configuration/component-configuration'; @@ -21,7 +24,6 @@ describe('Cypress 11 Migration', () => { beforeEach(() => { tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); - jest.resetAllMocks(); }); it('should not update if cypress { 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 index 1184993efad7b..c5c36ad25f8d9 100644 --- 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 @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { Tree, readJson, diff --git a/packages/detox/src/generators/application/application.spec.ts b/packages/detox/src/generators/application/application.spec.ts index 7131940ee815d..b0e1ee0e5b9cd 100644 --- a/packages/detox/src/generators/application/application.spec.ts +++ b/packages/detox/src/generators/application/application.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { addProjectConfiguration, readJson, diff --git a/packages/detox/src/generators/init/init.spec.ts b/packages/detox/src/generators/init/init.spec.ts index cdf2c4a801faf..5b7f508f0b88c 100644 --- a/packages/detox/src/generators/init/init.spec.ts +++ b/packages/detox/src/generators/init/init.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { Tree, readJson } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { detoxInitGenerator } from './init'; diff --git a/packages/detox/src/generators/init/init.ts b/packages/detox/src/generators/init/init.ts index ac48480f3ce6e..8753d6ecf9836 100644 --- a/packages/detox/src/generators/init/init.ts +++ b/packages/detox/src/generators/init/init.ts @@ -1,14 +1,17 @@ import { addDependenciesToPackageJson, + createProjectGraphAsync, formatFiles, GeneratorCallback, readNxJson, removeDependenciesFromPackageJson, runTasksInSerial, Tree, - updateNxJson, } from '@nx/devkit'; -import { updatePackageScripts } from '@nx/devkit/src/utils/update-package-scripts'; +import { + addPlugin, + generateCombinations, +} from '@nx/devkit/src/utils/add-plugin'; import { createNodes, DetoxPluginOptions } from '../../plugins/plugin'; import { detoxVersion, nxVersion } from '../../utils/versions'; import { Schema } from './schema'; @@ -33,11 +36,18 @@ export async function detoxInitGeneratorInternal(host: Tree, schema: Schema) { } if (schema.addPlugin) { - addPlugin(host); - } - - if (schema.updatePackageScripts) { - await updatePackageScripts(host, createNodes); + await addPlugin( + host, + await createProjectGraphAsync(), + '@nx/detox/plugin', + createNodes, + { + buildTargetName: ['build', 'detox:build', 'detox-build'], + startTargetName: ['start', 'detox:start', 'detox-start'], + testTargetName: ['test', 'detox:test', 'detox-test'], + }, + schema.updatePackageScripts + ); } if (!schema.skipFormat) { @@ -64,29 +74,4 @@ function moveDependency(host: Tree) { return removeDependenciesFromPackageJson(host, ['@nx/detox'], []); } -function addPlugin(host: Tree) { - const nxJson = readNxJson(host); - nxJson.plugins ??= []; - - for (const plugin of nxJson.plugins) { - if ( - typeof plugin === 'string' - ? plugin === '@nx/detox/plugin' - : plugin.plugin === '@nx/detox/plugin' - ) { - return; - } - } - - nxJson.plugins.push({ - plugin: '@nx/detox/plugin', - options: { - buildTargetName: 'build', - startTargetName: 'start', - testTargetName: 'test', - } as DetoxPluginOptions, - }); - updateNxJson(host, nxJson); -} - export default detoxInitGenerator; diff --git a/packages/devkit/src/utils/add-plugin.spec.ts b/packages/devkit/src/utils/add-plugin.spec.ts new file mode 100644 index 0000000000000..10fad482fc358 --- /dev/null +++ b/packages/devkit/src/utils/add-plugin.spec.ts @@ -0,0 +1,470 @@ +import { createTreeWithEmptyWorkspace } from 'nx/src/generators/testing-utils/create-tree-with-empty-workspace'; +import type { Tree } from 'nx/src/generators/tree'; +import { readJson, writeJson } from 'nx/src/generators/utils/json'; +import type { PackageJson } from 'nx/src/utils/package-json'; +import { CreateNodes } from 'nx/src/project-graph/plugins'; +import { ProjectGraph } from 'nx/src/devkit-exports'; +import { TempFs } from 'nx/src/internal-testing-utils/temp-fs'; + +import { addPlugin, generateCombinations } from './add-plugin'; + +describe('addPlugin', () => { + let tree: Tree; + let createNodes: CreateNodes; + let graph: ProjectGraph; + let fs: TempFs; + + beforeEach(async () => { + tree = createTreeWithEmptyWorkspace(); + + fs = new TempFs('add-plugin'); + tree.root = fs.tempDir; + + graph = { + nodes: { + app1: { + name: 'app1', + type: 'app', + data: { + root: 'app1', + targets: {}, + }, + }, + }, + dependencies: { + app1: [], + }, + }; + createNodes = [ + '**/next.config.{js,cjs,mjs}', + (_, { targetName }) => ({ + projects: { + app1: { + name: 'app1', + targets: { + [targetName]: { command: 'next build' }, + }, + }, + }, + }), + ]; + + await fs.createFiles({ + 'app1/next.config.js': '', + }); + }); + + afterEach(() => { + fs.cleanup(); + }); + + describe('adding the plugin', () => { + it('should not conflicting with the existing graph', async () => { + graph.nodes.app1.data.targets.build = {}; + + await addPlugin( + tree, + graph, + '@nx/next/plugin', + createNodes, + + { + targetName: ['build', '_build'], + }, + true + ); + + expect(readJson(tree, 'nx.json').plugins).toContainEqual({ + plugin: '@nx/next/plugin', + options: { + targetName: '_build', + }, + }); + }); + }); + + it('should throw an error if no non-conflicting options are provided', async () => { + graph.nodes.app1.data.targets.build = {}; + + try { + await addPlugin( + tree, + graph, + '@nx/next/plugin', + createNodes, + + { + targetName: ['build'], + }, + true + ); + fail('Should have thrown an error'); + } catch (e) {} + }); + + describe('updating package scripts', () => { + test.each` + script + ${'next-remote-watch'} + ${'anext build'} + ${'next builda'} + `('should not replace "$script"', async ({ script }) => { + writeJson(tree, 'app1/package.json', { + name: 'app1', + scripts: { + build: script, + }, + }); + + await addPlugin( + tree, + graph, + '@nx/next/plugin', + createNodes, + + { + targetName: ['build'], + }, + true + ); + + const { scripts } = readJson(tree, 'app1/package.json'); + expect(scripts.build).toBe(script); + }); + + test.each` + script | expected + ${'next build'} | ${'nx build'} + ${'npx next build'} | ${'npx nx build'} + ${'next build --debug'} | ${'nx build --debug'} + ${'NODE_OPTIONS="--inspect" next build'} | ${'NODE_OPTIONS="--inspect" nx build'} + ${'NODE_OPTIONS="--inspect" npx next build --debug'} | ${'NODE_OPTIONS="--inspect" npx nx build --debug'} + ${'next build && echo "Done"'} | ${'nx build && echo "Done"'} + ${'echo "Building..." && next build'} | ${'echo "Building..." && nx build'} + ${'echo "Building..." && next build && echo "Done"'} | ${'echo "Building..." && nx build && echo "Done"'} + ${'echo "Building..." &&next build&& echo "Done"'} | ${'echo "Building..." &&nx build&& echo "Done"'} + ${'echo "Building..." && NODE_OPTIONS="--inspect" npx next build --debug && echo "Done"'} | ${'echo "Building..." && NODE_OPTIONS="--inspect" npx nx build --debug && echo "Done"'} + `( + 'should replace "$script" with "$expected"', + async ({ script, expected }) => { + writeJson(tree, 'app1/package.json', { + name: 'app1', + scripts: { + build: script, + }, + }); + + await addPlugin( + tree, + graph, + '@nx/next/plugin', + createNodes, + + { + targetName: ['build'], + }, + true + ); + + const { scripts } = readJson(tree, 'app1/package.json'); + expect(scripts.build).toBe(expected); + } + ); + + test.each` + script | expected + ${'cypress run --e2e --config-file cypress.config.ts'} | ${'nx e2e'} + ${'echo "Starting..." && cypress run --e2e --config-file cypress.config.ts && echo "Done"'} | ${'echo "Starting..." && nx e2e && echo "Done"'} + `( + 'should replace "$script" with "$expected"', + async ({ script, expected }) => { + await fs.createFile('app1/cypress.config.ts', ''); + writeJson(tree, 'app1/package.json', { + name: 'app1', + scripts: { + e2e: script, + }, + }); + + createNodes = [ + '**/cypress.config.{js,ts,mjs,mts,cjs,cts}', + () => ({ + projects: { + app1: { + name: 'app1', + targets: { + e2e: { + command: + 'cypress run --config-file cypress.config.ts --e2e', + }, + }, + }, + }, + }), + ]; + + await addPlugin( + tree, + graph, + '@nx/cypress/plugin', + createNodes, + + { + targetName: ['e2e'], + }, + true + ); + + const { scripts } = readJson(tree, 'app1/package.json'); + expect(scripts.e2e).toBe(expected); + } + ); + + it('should handle scripts with name different than the target name', async () => { + writeJson(tree, 'app1/package.json', { + name: 'app1', + scripts: { + 'build:dev': 'next build', + }, + }); + + await addPlugin( + tree, + graph, + '@nx/next/plugin', + createNodes, + + { + targetName: ['build'], + }, + true + ); + + const { scripts } = readJson(tree, 'app1/package.json'); + expect(scripts['build:dev']).toBe('nx build'); + }); + + it('should support replacing multiple scripts', async () => { + writeJson(tree, 'app1/package.json', { + name: 'app1', + scripts: { + dev: 'PORT=4000 next dev --experimental-https', + start: 'next build && PORT=4000 next start --experimental-https', + }, + }); + + createNodes = [ + '**/next.config.{js,cjs,mjs}', + () => ({ + projects: { + app1: { + name: 'app1', + targets: { + build: { command: 'next build' }, + dev: { command: 'next dev' }, + start: { command: 'next start' }, + }, + }, + }, + }), + ]; + + await addPlugin( + tree, + graph, + '@nx/next/plugin', + createNodes, + + { + targetName: ['build'], + }, + true + ); + + const { scripts } = readJson(tree, 'app1/package.json'); + expect(scripts.dev).toBe('PORT=4000 nx dev --experimental-https'); + expect(scripts.start).toBe( + 'nx build && PORT=4000 nx start --experimental-https' + ); + }); + + it('should support multiple occurrences of the same command within a script', async () => { + await fs.createFile('app1/tsconfig.json', ''); + writeJson(tree, 'app1/package.json', { + name: 'app1', + scripts: { + typecheck: 'tsc -p tsconfig.lib.json && tsc -p tsconfig.spec.json', + }, + }); + + createNodes = [ + '**/tsconfig.json', + () => ({ + projects: { + app1: { + name: 'app1', + targets: { + build: { command: 'tsc' }, + }, + }, + }, + }), + ]; + + await addPlugin( + tree, + graph, + '@nx/next/plugin', + createNodes, + + { + targetName: ['build'], + }, + true + ); + + const { scripts } = readJson(tree, 'app1/package.json'); + expect(scripts.typecheck).toBe( + 'nx build -p tsconfig.lib.json && nx build -p tsconfig.spec.json' + ); + }); + + it('should support multiple occurrences of the same command within a script with extra commands', async () => { + await fs.createFile('app1/tsconfig.json', ''); + writeJson(tree, 'app1/package.json', { + name: 'app1', + scripts: { + typecheck: + 'echo "Typechecking..." && tsc -p tsconfig.lib.json && tsc -p tsconfig.spec.json && echo "Done"', + }, + }); + + createNodes = [ + '**/tsconfig.json', + () => ({ + projects: { + app1: { + name: 'app1', + targets: { + build: { command: 'tsc' }, + }, + }, + }, + }), + ]; + + await addPlugin( + tree, + graph, + '@nx/next/plugin', + createNodes, + + { + targetName: ['build'], + }, + true + ); + + const { scripts } = readJson(tree, 'app1/package.json'); + expect(scripts.typecheck).toBe( + 'echo "Typechecking..." && nx build -p tsconfig.lib.json && nx build -p tsconfig.spec.json && echo "Done"' + ); + }); + }); +}); +describe('generateCombinations', () => { + it('should return all combinations for a 2x2 array of strings', () => { + const input = { + prop1: ['1', '2'], + prop2: ['a', 'b'], + }; + expect(generateCombinations(input).map((v) => JSON.stringify(v))) + .toMatchInlineSnapshot(` + [ + "{"prop1":"1","prop2":"a"}", + "{"prop1":"2","prop2":"a"}", + "{"prop1":"1","prop2":"b"}", + "{"prop1":"2","prop2":"b"}", + ] + `); + }); + + it('should handle arrays of 2x3 array of strings', () => { + const input = { + prop1: ['1', '2', '3'], + prop2: ['a', 'b'], + }; + expect(generateCombinations(input).map((v) => JSON.stringify(v))) + .toMatchInlineSnapshot(` + [ + "{"prop1":"1","prop2":"a"}", + "{"prop1":"2","prop2":"a"}", + "{"prop1":"3","prop2":"a"}", + "{"prop1":"1","prop2":"b"}", + "{"prop1":"2","prop2":"b"}", + "{"prop1":"3","prop2":"b"}", + ] + `); + }); + + it('should handle arrays of 3x2 array of strings', () => { + const input = { + prop1: ['1', '2'], + prop2: ['a', 'b'], + prop3: ['i', 'ii'], + }; + expect(generateCombinations(input).map((v) => JSON.stringify(v))) + .toMatchInlineSnapshot(` + [ + "{"prop1":"1","prop2":"a","prop3":"i"}", + "{"prop1":"2","prop2":"a","prop3":"i"}", + "{"prop1":"1","prop2":"b","prop3":"i"}", + "{"prop1":"2","prop2":"b","prop3":"i"}", + "{"prop1":"1","prop2":"a","prop3":"ii"}", + "{"prop1":"2","prop2":"a","prop3":"ii"}", + "{"prop1":"1","prop2":"b","prop3":"ii"}", + "{"prop1":"2","prop2":"b","prop3":"ii"}", + ] + `); + }); + + it('should be able to be used to generate possible combinations of plugin options', () => { + const possibleOptions = generateCombinations({ + buildTargetName: ['build', 'vite:build', 'vite-build'], + testTargetName: ['test', 'vite:test', 'vite-test'], + serveTargetName: ['serve', 'vite:serve', 'vite-serve'], + previewTargetName: ['preview', 'vite:preview', 'vite-preview'], + serveStaticTargetName: [ + 'serve-static', + 'vite:serve-static', + 'vite-serve-static', + ], + }); + + expect(possibleOptions.length).toEqual(3 ** 5); + + expect(possibleOptions[0]).toEqual({ + buildTargetName: 'build', + previewTargetName: 'preview', + testTargetName: 'test', + serveTargetName: 'serve', + serveStaticTargetName: 'serve-static', + }); + // The first defined option is the first to be changed + expect(possibleOptions[1]).toEqual({ + buildTargetName: 'vite:build', + previewTargetName: 'preview', + testTargetName: 'test', + serveTargetName: 'serve', + serveStaticTargetName: 'serve-static', + }); + + expect(possibleOptions[possibleOptions.length - 1]).toEqual({ + buildTargetName: 'vite-build', + previewTargetName: 'vite-preview', + testTargetName: 'vite-test', + serveTargetName: 'vite-serve', + serveStaticTargetName: 'vite-serve-static', + }); + }); +}); diff --git a/packages/devkit/src/utils/update-package-scripts.ts b/packages/devkit/src/utils/add-plugin.ts similarity index 50% rename from packages/devkit/src/utils/update-package-scripts.ts rename to packages/devkit/src/utils/add-plugin.ts index 46c4478e3a8fa..18e412db07790 100644 --- a/packages/devkit/src/utils/update-package-scripts.ts +++ b/packages/devkit/src/utils/add-plugin.ts @@ -1,16 +1,123 @@ -import type { - CreateNodes, - CreateNodesFunction, - CreateNodesResult, - NxJsonConfiguration, - Tree, +import { + type CreateNodes, + type ProjectConfiguration, + type ProjectGraph, + type Tree, } from 'nx/src/devkit-exports'; import type { PackageJson } from 'nx/src/utils/package-json'; -import { basename, dirname } from 'path'; import * as yargs from 'yargs-parser'; import { requireNx } from '../../nx'; -const { glob, readJson, readNxJson, workspaceRoot, writeJson } = requireNx(); +const { + readJson, + writeJson, + readNxJson, + updateNxJson, + retrieveProjectConfigurations, + LoadedNxPlugin, + ProjectConfigurationsError, +} = requireNx(); + +import type { ConfigurationResult } from 'nx/src/project-graph/utils/project-configuration-utils'; + +/** + * Iterates through various forms of plugin options to find the one which does not conflict with the current graph + + */ +export async function addPlugin( + tree: Tree, + graph: ProjectGraph, + pluginName: string, + createNodesTuple: CreateNodes, + options: Partial< + Record + >, + shouldUpdatePackageJsonScripts: boolean +): Promise { + const graphNodes = Object.values(graph.nodes); + const nxJson = readNxJson(tree); + + let pluginOptions: PluginOptions; + let projConfigs: ConfigurationResult; + const combinations = generateCombinations(options); + optionsLoop: for (const _pluginOptions of combinations) { + pluginOptions = _pluginOptions as PluginOptions; + + nxJson.plugins ??= []; + if ( + nxJson.plugins.some((p) => + typeof p === 'string' ? p === pluginName : p.plugin === pluginName + ) + ) { + // Plugin has already been added + return; + } + global.NX_GRAPH_CREATION = true; + try { + projConfigs = await retrieveProjectConfigurations( + [ + new LoadedNxPlugin( + { + name: pluginName, + createNodes: createNodesTuple, + }, + { + plugin: pluginName, + options: pluginOptions, + } + ), + ], + tree.root, + nxJson + ); + } catch (e) { + // Errors are okay for this because we're only running 1 plugin + if (e instanceof ProjectConfigurationsError) { + projConfigs = e.partialProjectConfigurationsResult; + } else { + throw e; + } + } + global.NX_GRAPH_CREATION = false; + + for (const projConfig of Object.values(projConfigs.projects)) { + const node = graphNodes.find( + (node) => node.data.root === projConfig.root + ); + + if (!node) { + continue; + } + + for (const targetName in projConfig.targets) { + if (node.data.targets[targetName]) { + // Conflicting Target Name, check the next one + pluginOptions = null; + continue optionsLoop; + } + } + } + + break; + } + + if (!pluginOptions) { + throw new Error( + 'Could not add the plugin in a way which does not conflict with existing targets. Please report this error at: https://github.com/nrwl/nx/issues/new/choose' + ); + } + + nxJson.plugins.push({ + plugin: pluginName, + options: pluginOptions, + }); + + updateNxJson(tree, nxJson); + + if (shouldUpdatePackageJsonScripts) { + updatePackageScripts(tree, projConfigs); + } +} type TargetCommand = { command: string; @@ -18,35 +125,20 @@ type TargetCommand = { configuration?: string; }; -export async function updatePackageScripts( +function updatePackageScripts( tree: Tree, - createNodesTuple: CreateNodes -): Promise { - const nxJson = readNxJson(tree); - - const [pattern, createNodes] = createNodesTuple; - const matchingFiles = glob(tree, [pattern]); - - for (const file of matchingFiles) { - const projectRoot = getProjectRootFromConfigFile(file); - await processProject( - tree, - projectRoot, - file, - createNodes, - nxJson, - matchingFiles - ); + projectConfigurations: ConfigurationResult +) { + for (const projectConfig of Object.values(projectConfigurations.projects)) { + const projectRoot = projectConfig.root; + processProject(tree, projectRoot, projectConfig); } } -async function processProject( +function processProject( tree: Tree, projectRoot: string, - projectConfigurationFile: string, - createNodesFunction: CreateNodesFunction, - nxJsonConfiguration: NxJsonConfiguration, - configFiles: string[] + projectConfiguration: ProjectConfiguration ) { const packageJsonPath = `${projectRoot}/package.json`; if (!tree.exists(packageJsonPath)) { @@ -57,17 +149,7 @@ async function processProject( return; } - const result = await createNodesFunction( - projectConfigurationFile, - {}, - { - nxJsonConfiguration, - workspaceRoot, - configFiles, - } - ); - - const targetCommands = getInferredTargetCommands(result); + const targetCommands = getInferredTargetCommands(projectConfiguration); if (!targetCommands.length) { return; } @@ -187,82 +269,86 @@ async function processProject( } } - if (process.env.NX_RUNNING_NX_INIT === 'true') { - // running `nx init` so we want to exclude everything by default - packageJson.nx ??= {}; - packageJson.nx.includedScripts = []; - } else if (replacedTargets.size) { - /** - * Running `nx add`. In this case we want to: - * - if `includedScripts` is already set: exclude scripts that match inferred targets that were used to replace a script - * - if `includedScripts` is not set: set `includedScripts` with all scripts except the ones that match an inferred target that was used to replace a script - */ - const includedScripts = - packageJson.nx?.includedScripts ?? Object.keys(packageJson.scripts); - const filteredScripts = includedScripts.filter( - (s) => !replacedTargets.has(s) - ); - if (filteredScripts.length !== includedScripts.length) { - packageJson.nx ??= {}; - packageJson.nx.includedScripts = filteredScripts; - } - } - writeJson(tree, packageJsonPath, packageJson); } -function getInferredTargetCommands(result: CreateNodesResult): TargetCommand[] { +function getInferredTargetCommands( + project: ProjectConfiguration +): TargetCommand[] { const targetCommands: TargetCommand[] = []; - for (const project of Object.values(result.projects ?? {})) { - for (const [targetName, target] of Object.entries(project.targets ?? {})) { - if (target.command) { - targetCommands.push({ command: target.command, target: targetName }); + for (const [targetName, target] of Object.entries(project.targets ?? {})) { + if (target.command) { + targetCommands.push({ command: target.command, target: targetName }); + } else if ( + target.executor === 'nx:run-commands' && + target.options?.command + ) { + targetCommands.push({ + command: target.options.command, + target: targetName, + }); + } + + if (!target.configurations) { + continue; + } + + for (const [configurationName, configuration] of Object.entries( + target.configurations + )) { + if (configuration.command) { + targetCommands.push({ + command: configuration.command, + target: targetName, + configuration: configurationName, + }); } else if ( target.executor === 'nx:run-commands' && - target.options?.command + configuration.options?.command ) { targetCommands.push({ - command: target.options.command, + command: configuration.options.command, target: targetName, + configuration: configurationName, }); } - - if (!target.configurations) { - continue; - } - - for (const [configurationName, configuration] of Object.entries( - target.configurations - )) { - if (configuration.command) { - targetCommands.push({ - command: configuration.command, - target: targetName, - configuration: configurationName, - }); - } else if ( - target.executor === 'nx:run-commands' && - configuration.options?.command - ) { - targetCommands.push({ - command: configuration.options.command, - target: targetName, - configuration: configurationName, - }); - } - } } } return targetCommands; } -function getProjectRootFromConfigFile(file: string): string { - let projectRoot = dirname(file); - if (basename(projectRoot) === '.storybook') { - projectRoot = dirname(projectRoot); - } +export function generateCombinations( + input: Record +): Record[] { + // This is reversed so that combinations have the first defined property updated first + const keys = Object.keys(input).reverse(); + return _generateCombinations(Object.values(input).reverse()).map( + (combination) => { + const result = {}; + combination.reverse().forEach((combo, i) => { + result[keys[keys.length - i - 1]] = combo; + }); + + return result; + } + ); +} - return projectRoot; +/** + * Generate all possible combinations of a 2-dimensional array. + * + * Useful for generating all possible combinations of options for a plugin + */ +function _generateCombinations(input: T[][]): T[][] { + if (input.length === 0) { + return [[]]; + } else { + const [first, ...rest] = input; + const partialCombinations = _generateCombinations(rest); + return first.flatMap((value) => + partialCombinations.map((combination) => [value, ...combination]) + ); + } } diff --git a/packages/devkit/src/utils/update-package-scripts.spec.ts b/packages/devkit/src/utils/update-package-scripts.spec.ts deleted file mode 100644 index 317cc5db24e90..0000000000000 --- a/packages/devkit/src/utils/update-package-scripts.spec.ts +++ /dev/null @@ -1,394 +0,0 @@ -import { createTreeWithEmptyWorkspace } from 'nx/src/generators/testing-utils/create-tree-with-empty-workspace'; -import type { Tree } from 'nx/src/generators/tree'; -import { readJson, writeJson } from 'nx/src/generators/utils/json'; -import type { PackageJson } from 'nx/src/utils/package-json'; -import { updatePackageScripts } from './update-package-scripts'; - -describe('updatePackageScripts', () => { - let tree: Tree; - - beforeEach(() => { - tree = createTreeWithEmptyWorkspace(); - }); - - test.each` - script - ${'next-remote-watch'} - ${'anext build'} - ${'next builda'} - `('should not replace "$script"', async ({ script }) => { - tree.write('app1/next.config.js', ''); - writeJson(tree, 'app1/package.json', { - name: 'app1', - scripts: { - build: script, - }, - }); - - await updatePackageScripts(tree, [ - '**/next.config.{js,cjs,mjs}', - () => ({ - projects: { - app1: { - targets: { - build: { command: 'next build' }, - }, - }, - }, - }), - ]); - - const { scripts } = readJson(tree, 'app1/package.json'); - expect(scripts.build).toBe(script); - }); - - test.each` - script | expected - ${'next build'} | ${'nx build'} - ${'npx next build'} | ${'npx nx build'} - ${'next build --debug'} | ${'nx build --debug'} - ${'NODE_OPTIONS="--inspect" next build'} | ${'NODE_OPTIONS="--inspect" nx build'} - ${'NODE_OPTIONS="--inspect" npx next build --debug'} | ${'NODE_OPTIONS="--inspect" npx nx build --debug'} - ${'next build && echo "Done"'} | ${'nx build && echo "Done"'} - ${'echo "Building..." && next build'} | ${'echo "Building..." && nx build'} - ${'echo "Building..." && next build && echo "Done"'} | ${'echo "Building..." && nx build && echo "Done"'} - ${'echo "Building..." &&next build&& echo "Done"'} | ${'echo "Building..." &&nx build&& echo "Done"'} - ${'echo "Building..." && NODE_OPTIONS="--inspect" npx next build --debug && echo "Done"'} | ${'echo "Building..." && NODE_OPTIONS="--inspect" npx nx build --debug && echo "Done"'} - `( - 'should replace "$script" with "$expected"', - async ({ script, expected }) => { - tree.write('app1/next.config.js', ''); - writeJson(tree, 'app1/package.json', { - name: 'app1', - scripts: { - build: script, - }, - }); - - await updatePackageScripts(tree, [ - '**/next.config.{js,cjs,mjs}', - () => ({ - projects: { - app1: { - targets: { - build: { command: 'next build' }, - }, - }, - }, - }), - ]); - - const { scripts } = readJson(tree, 'app1/package.json'); - expect(scripts.build).toBe(expected); - } - ); - - test.each` - script | expected - ${'cypress run --e2e --config-file cypress.config.ts'} | ${'nx e2e'} - ${'echo "Starting..." && cypress run --e2e --config-file cypress.config.ts && echo "Done"'} | ${'echo "Starting..." && nx e2e && echo "Done"'} - `( - 'should replace "$script" with "$expected"', - async ({ script, expected }) => { - tree.write('app1/cypress.config.ts', ''); - writeJson(tree, 'app1/package.json', { - name: 'app1', - scripts: { - e2e: script, - }, - }); - - await updatePackageScripts(tree, [ - '**/cypress.config.{js,ts,mjs,mts,cjs,cts}', - () => ({ - projects: { - app1: { - targets: { - e2e: { - command: 'cypress run --config-file cypress.config.ts --e2e', - }, - }, - }, - }, - }), - ]); - - const { scripts } = readJson(tree, 'app1/package.json'); - expect(scripts.e2e).toBe(expected); - } - ); - - it('should handle scripts with name different than the target name', async () => { - tree.write('app1/next.config.js', ''); - writeJson(tree, 'app1/package.json', { - name: 'app1', - scripts: { - 'build:dev': 'next build', - }, - }); - - await updatePackageScripts(tree, [ - '**/next.config.{js,cjs,mjs}', - () => ({ - projects: { - app1: { - targets: { - build: { - command: 'next build', - }, - }, - }, - }, - }), - ]); - - const { scripts } = readJson(tree, 'app1/package.json'); - expect(scripts['build:dev']).toBe('nx build'); - }); - - it('should support replacing multiple scripts', async () => { - tree.write('app1/next.config.js', ''); - writeJson(tree, 'app1/package.json', { - name: 'app1', - scripts: { - dev: 'PORT=4000 next dev --experimental-https', - start: 'next build && PORT=4000 next start --experimental-https', - }, - }); - - await updatePackageScripts(tree, [ - '**/next.config.{js,cjs,mjs}', - () => ({ - projects: { - app1: { - targets: { - build: { command: 'next build' }, - dev: { command: 'next dev' }, - start: { command: 'next start' }, - }, - }, - }, - }), - ]); - - const { scripts } = readJson(tree, 'app1/package.json'); - expect(scripts.dev).toBe('PORT=4000 nx dev --experimental-https'); - expect(scripts.start).toBe( - 'nx build && PORT=4000 nx start --experimental-https' - ); - }); - - it('should support multiple occurrences of the same command within a script', async () => { - tree.write('app1/tsconfig.json', ''); - writeJson(tree, 'app1/package.json', { - name: 'app1', - scripts: { - typecheck: 'tsc -p tsconfig.lib.json && tsc -p tsconfig.spec.json', - }, - }); - - await updatePackageScripts(tree, [ - '**/tsconfig.json', - () => ({ - projects: { - app1: { - targets: { - build: { command: 'tsc' }, - }, - }, - }, - }), - ]); - - const { scripts } = readJson(tree, 'app1/package.json'); - expect(scripts.typecheck).toBe( - 'nx build -p tsconfig.lib.json && nx build -p tsconfig.spec.json' - ); - }); - - it('should support multiple occurrences of the same command within a script with extra commands', async () => { - tree.write('app1/tsconfig.json', ''); - writeJson(tree, 'app1/package.json', { - name: 'app1', - scripts: { - typecheck: - 'echo "Typechecking..." && tsc -p tsconfig.lib.json && tsc -p tsconfig.spec.json && echo "Done"', - }, - }); - - await updatePackageScripts(tree, [ - '**/tsconfig.json', - () => ({ - projects: { - app1: { - targets: { - build: { command: 'tsc' }, - }, - }, - }, - }), - ]); - - const { scripts } = readJson(tree, 'app1/package.json'); - expect(scripts.typecheck).toBe( - 'echo "Typechecking..." && nx build -p tsconfig.lib.json && nx build -p tsconfig.spec.json && echo "Done"' - ); - }); - - it('should set "includedScripts" to an empty array when running "nx init"', async () => { - const originalEnvVarValue = process.env.NX_RUNNING_NX_INIT; - process.env.NX_RUNNING_NX_INIT = 'true'; - - tree.write('vite.config.ts', ''); - writeJson(tree, 'package.json', { - name: 'app1', - scripts: { - build: 'vite build', - serve: 'vite', - test: 'vitest', - coverage: 'vitest run --coverage', - foo: 'echo "foo"', - }, - }); - - await updatePackageScripts(tree, [ - '**/{vite,vitest}.config.{js,ts,mjs,mts,cjs,cts}', - () => ({ - projects: { - app1: { - targets: { - build: { command: 'vite build' }, - serve: { command: 'vite serve' }, - test: { command: 'vitest run' }, - }, - }, - }, - }), - ]); - - const packageJson = readJson(tree, 'package.json'); - expect(packageJson.scripts).toStrictEqual({ - build: 'nx build', - serve: 'vite', - test: 'vitest', - coverage: 'nx test --coverage', - foo: 'echo "foo"', - }); - expect(packageJson.nx.includedScripts).toStrictEqual([]); - - process.env.NX_RUNNING_NX_INIT = originalEnvVarValue; - }); - - it('should set "includedScripts" to all scripts except the ones matching inferred target names when "includedScripts" is not set', async () => { - tree.write('vite.config.ts', ''); - writeJson(tree, 'package.json', { - name: 'app1', - scripts: { - build: 'vite build', - serve: 'vite', - test: 'vitest', - coverage: 'vitest run --coverage', - foo: 'echo "foo"', - }, - }); - - await updatePackageScripts(tree, [ - '**/{vite,vitest}.config.{js,ts,mjs,mts,cjs,cts}', - () => ({ - projects: { - app1: { - targets: { - build: { command: 'vite build' }, - serve: { command: 'vite serve' }, - test: { command: 'vitest run' }, - }, - }, - }, - }), - ]); - - const packageJson = readJson(tree, 'package.json'); - expect(packageJson.scripts).toStrictEqual({ - build: 'nx build', - serve: 'vite', - test: 'vitest', - coverage: 'nx test --coverage', - foo: 'echo "foo"', - }); - // "build": excluded because a script (itself) was replaced with a target "build" - // "serve" not excluded even though it matches the name of an inferred target because no script was replaced with a target "serve" - // "test" excluded even though it was not replaced because another script was replaced with a target "test" - // "coverage" not excluded even though it was replaced because it does not match a target - // "foo" not excluded because it does not match a target - expect(packageJson.nx.includedScripts).toStrictEqual([ - 'serve', - 'coverage', - 'foo', - ]); - }); - - it('should not set "nx.includedScripts" when no script matched an inferred target', async () => { - tree.write('vite.config.ts', ''); - writeJson(tree, 'package.json', { - name: 'app1', - scripts: { - serve: 'vite', - coverage: 'vitest run --coverage', - foo: 'echo "foo"', - }, - }); - - await updatePackageScripts(tree, [ - '**/{vite,vitest}.config.{js,ts,mjs,mts,cjs,cts}', - () => ({ - projects: { - app1: { - targets: { - build: { command: 'vite build' }, - serve: { command: 'vite serve' }, - test: { command: 'vitest run' }, - }, - }, - }, - }), - ]); - - const packageJson = readJson(tree, 'package.json'); - expect(packageJson.scripts).toStrictEqual({ - serve: 'vite', - coverage: 'nx test --coverage', - foo: 'echo "foo"', - }); - expect(packageJson.nx).toBeUndefined(); - }); - - it('should exclude replaced package.json scripts from nx if they are initially included', async () => { - tree.write('next.config.js', ''); - writeJson(tree, 'package.json', { - name: 'app1', - scripts: { - build: 'next build', - foo: 'echo "foo"', - }, - nx: { - includedScripts: ['build', 'foo'], - }, - }); - - await updatePackageScripts(tree, [ - '**/next.config.{js,cjs,mjs}', - () => ({ - projects: { - app1: { - targets: { - build: { command: 'next build' }, - }, - }, - }, - }), - ]); - - const { nx } = readJson(tree, 'package.json'); - expect(nx.includedScripts).toStrictEqual(['foo']); - }); -}); diff --git a/packages/eslint/src/generators/convert-to-flat-config/generator.spec.ts b/packages/eslint/src/generators/convert-to-flat-config/generator.spec.ts index 62755d9254f81..17d3fa59747d5 100644 --- a/packages/eslint/src/generators/convert-to-flat-config/generator.spec.ts +++ b/packages/eslint/src/generators/convert-to-flat-config/generator.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { NxJsonConfiguration, diff --git a/packages/eslint/src/generators/init/init.spec.ts b/packages/eslint/src/generators/init/init.spec.ts index 552b65d8f363c..bcf161b287aef 100644 --- a/packages/eslint/src/generators/init/init.spec.ts +++ b/packages/eslint/src/generators/init/init.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { NxJsonConfiguration, readJson, Tree, updateJson } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { LinterInitOptions, lintInitGenerator } from './init'; diff --git a/packages/eslint/src/generators/init/init.ts b/packages/eslint/src/generators/init/init.ts index d6f91ed8c31cb..dfe622ea8cae5 100644 --- a/packages/eslint/src/generators/init/init.ts +++ b/packages/eslint/src/generators/init/init.ts @@ -1,15 +1,17 @@ -import type { GeneratorCallback, Tree } from '@nx/devkit'; import { addDependenciesToPackageJson, + createProjectGraphAsync, + GeneratorCallback, readNxJson, removeDependenciesFromPackageJson, runTasksInSerial, + Tree, updateNxJson, } from '@nx/devkit'; -import { updatePackageScripts } from '@nx/devkit/src/utils/update-package-scripts'; +import { addPlugin } from '@nx/devkit/src/utils/add-plugin'; import { eslintVersion, nxVersion } from '../../utils/versions'; import { findEslintFile } from '../utils/eslint-file'; -import { EslintPluginOptions, createNodes } from '../../plugins/plugin'; +import { createNodes } from '../../plugins/plugin'; import { hasEslintPlugin } from '../utils/plugin'; export interface LinterInitOptions { @@ -47,29 +49,6 @@ function addTargetDefaults(tree: Tree) { updateNxJson(tree, nxJson); } -function addPlugin(tree: Tree) { - const nxJson = readNxJson(tree); - nxJson.plugins ??= []; - - for (const plugin of nxJson.plugins) { - if ( - typeof plugin === 'string' - ? plugin === '@nx/eslint/plugin' - : plugin.plugin === '@nx/eslint/plugin' - ) { - return; - } - } - - nxJson.plugins.push({ - plugin: '@nx/eslint/plugin', - options: { - targetName: 'lint', - } as EslintPluginOptions, - }); - updateNxJson(tree, nxJson); -} - export async function initEsLint( tree: Tree, options: LinterInitOptions @@ -82,12 +61,28 @@ export async function initEsLint( const hasPlugin = hasEslintPlugin(tree); const rootEslintFile = findEslintFile(tree); - if (rootEslintFile && options.addPlugin && !hasPlugin) { - addPlugin(tree); + const graph = await createProjectGraphAsync(); - if (options.updatePackageScripts) { - await updatePackageScripts(tree, createNodes); - } + const lintTargetNames = [ + 'lint', + 'eslint:lint', + 'eslint-lint', + '_lint', + '_eslint:lint', + '_eslint-lint', + ]; + + if (rootEslintFile && options.addPlugin && !hasPlugin) { + await addPlugin( + tree, + graph, + '@nx/eslint/plugin', + createNodes, + { + targetName: lintTargetNames, + }, + options.updatePackageScripts + ); return () => {}; } @@ -99,7 +94,16 @@ export async function initEsLint( updateProductionFileset(tree); if (options.addPlugin) { - addPlugin(tree); + await addPlugin( + tree, + graph, + '@nx/eslint/plugin', + createNodes, + { + targetName: lintTargetNames, + }, + options.updatePackageScripts + ); } else { addTargetDefaults(tree); } @@ -121,10 +125,6 @@ export async function initEsLint( ); } - if (options.updatePackageScripts) { - await updatePackageScripts(tree, createNodes); - } - return runTasksInSerial(...tasks); } diff --git a/packages/eslint/src/generators/lint-project/lint-project.spec.ts b/packages/eslint/src/generators/lint-project/lint-project.spec.ts index 342ac38ef0dee..ba308961eb869 100644 --- a/packages/eslint/src/generators/lint-project/lint-project.spec.ts +++ b/packages/eslint/src/generators/lint-project/lint-project.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { addProjectConfiguration, readJson, diff --git a/packages/eslint/src/generators/workspace-rule/workspace-rule.spec.ts b/packages/eslint/src/generators/workspace-rule/workspace-rule.spec.ts index 1c9468d7ee9d4..c4a85162d677c 100644 --- a/packages/eslint/src/generators/workspace-rule/workspace-rule.spec.ts +++ b/packages/eslint/src/generators/workspace-rule/workspace-rule.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { lintWorkspaceRuleGenerator } from './workspace-rule'; diff --git a/packages/eslint/src/generators/workspace-rules-project/workspace-rules-project.spec.ts b/packages/eslint/src/generators/workspace-rules-project/workspace-rules-project.spec.ts index 6e60123c1fda0..0a0482e781e15 100644 --- a/packages/eslint/src/generators/workspace-rules-project/workspace-rules-project.spec.ts +++ b/packages/eslint/src/generators/workspace-rules-project/workspace-rules-project.spec.ts @@ -1,8 +1,9 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { addProjectConfiguration, NxJsonConfiguration, readJson, - readProjectConfiguration, Tree, updateJson, } from '@nx/devkit'; diff --git a/packages/expo/src/generators/application/application.spec.ts b/packages/expo/src/generators/application/application.spec.ts index cc502e65a5a38..3b3b574eb10d2 100644 --- a/packages/expo/src/generators/application/application.spec.ts +++ b/packages/expo/src/generators/application/application.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { getProjects, readJson, diff --git a/packages/expo/src/generators/component/component.spec.ts b/packages/expo/src/generators/component/component.spec.ts index 8c291a5e0d920..3f3f96c078d2e 100644 --- a/packages/expo/src/generators/component/component.spec.ts +++ b/packages/expo/src/generators/component/component.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { logger, Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { Linter } from '@nx/eslint'; diff --git a/packages/expo/src/generators/init/init.spec.ts b/packages/expo/src/generators/init/init.spec.ts index 2af0563d89a76..b40251d9a146d 100644 --- a/packages/expo/src/generators/init/init.spec.ts +++ b/packages/expo/src/generators/init/init.spec.ts @@ -1,4 +1,6 @@ -import { Tree, readJson, updateJson } from '@nx/devkit'; +import 'nx/src/internal-testing-utils/mock-project-graph'; + +import { readJson, Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { expoInitGenerator } from './init'; diff --git a/packages/expo/src/generators/init/init.ts b/packages/expo/src/generators/init/init.ts index f1a37634ce677..da4a087481624 100644 --- a/packages/expo/src/generators/init/init.ts +++ b/packages/expo/src/generators/init/init.ts @@ -1,15 +1,15 @@ import { addDependenciesToPackageJson, + createProjectGraphAsync, formatFiles, GeneratorCallback, readNxJson, removeDependenciesFromPackageJson, runTasksInSerial, Tree, - updateNxJson, } from '@nx/devkit'; -import { updatePackageScripts } from '@nx/devkit/src/utils/update-package-scripts'; -import { createNodes, ExpoPluginOptions } from '../../../plugins/plugin'; +import { addPlugin } from '@nx/devkit/src/utils/add-plugin'; +import { createNodes } from '../../../plugins/plugin'; import { expoCliVersion, expoVersion, @@ -18,7 +18,6 @@ import { reactNativeVersion, reactVersion, } from '../../utils/versions'; -import { hasExpoPlugin } from '../../utils/has-expo-plugin'; import { addGitIgnoreEntry } from './lib/add-git-ignore-entry'; import { Schema } from './schema'; @@ -37,7 +36,29 @@ export async function expoInitGeneratorInternal(host: Tree, schema: Schema) { addGitIgnoreEntry(host); if (schema.addPlugin) { - addPlugin(host); + await addPlugin( + host, + await createProjectGraphAsync(), + '@nx/expo/plugin', + createNodes, + { + startTargetName: ['start', 'expo:start', 'expo-start'], + buildTargetName: ['build', 'expo:build', 'expo-build'], + prebuildTargetName: ['prebuild', 'expo:prebuild', 'expo-prebuild'], + serveTargetName: ['serve', 'expo:serve', 'expo-serve'], + installTargetName: ['install', 'expo:install', 'expo-install'], + exportTargetName: ['export', 'expo:export', 'expo-export'], + submitTargetName: ['submit', 'expo:submit', 'expo-submit'], + runIosTargetName: ['run-ios', 'expo:run-ios', 'expo-run-ios'], + runAndroidTargetName: [ + 'run-android', + 'expo:run-android', + 'expo-run-android', + ], + }, + + schema.updatePackageScripts + ); } const tasks: GeneratorCallback[] = []; @@ -46,10 +67,6 @@ export async function expoInitGeneratorInternal(host: Tree, schema: Schema) { tasks.push(updateDependencies(host, schema)); } - if (schema.updatePackageScripts) { - await updatePackageScripts(host, createNodes); - } - if (!schema.skipFormat) { await formatFiles(host); } @@ -79,29 +96,4 @@ function moveDependency(host: Tree) { return removeDependenciesFromPackageJson(host, ['@nx/react-native'], []); } -function addPlugin(host: Tree) { - const nxJson = readNxJson(host); - - if (hasExpoPlugin(host)) { - return; - } - - nxJson.plugins ??= []; - nxJson.plugins.push({ - plugin: '@nx/expo/plugin', - options: { - startTargetName: 'start', - serveTargetName: 'serve', - runIosTargetName: 'run-ios', - runAndroidTargetName: 'run-android', - exportTargetName: 'export', - prebuildTargetName: 'prebuild', - installTargetName: 'install', - buildTargetName: 'build', - submitTargetName: 'submit', - } as ExpoPluginOptions, - }); - updateNxJson(host, nxJson); -} - export default expoInitGenerator; diff --git a/packages/expo/src/generators/library/library.spec.ts b/packages/expo/src/generators/library/library.spec.ts index 2f921ff0810c7..403e302856b66 100644 --- a/packages/expo/src/generators/library/library.spec.ts +++ b/packages/expo/src/generators/library/library.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { getProjects, readJson, diff --git a/packages/expo/src/utils/add-linting.spec.ts b/packages/expo/src/utils/add-linting.spec.ts index c97cb4f6d32f7..e6c8cac411c1e 100644 --- a/packages/expo/src/utils/add-linting.spec.ts +++ b/packages/expo/src/utils/add-linting.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { Linter } from '@nx/eslint'; diff --git a/packages/gradle/src/generators/init/init.ts b/packages/gradle/src/generators/init/init.ts index 2b0ab56cca6c2..e4d1c4d8f92d0 100644 --- a/packages/gradle/src/generators/init/init.ts +++ b/packages/gradle/src/generators/init/init.ts @@ -8,8 +8,6 @@ import { Tree, updateNxJson, } from '@nx/devkit'; -import { updatePackageScripts } from '@nx/devkit/src/utils/update-package-scripts'; -import { createNodes } from '../../plugin/nodes'; import { nxVersion } from '../../utils/versions'; import { InitGeneratorSchema } from './schema'; import { hasGradlePlugin } from '../../utils/has-gradle-plugin'; @@ -34,10 +32,6 @@ export async function initGenerator(tree: Tree, options: InitGeneratorSchema) { addPlugin(tree); addProjectReportToBuildGradle(tree); - if (options.updatePackageScripts && tree.exists('package.json')) { - await updatePackageScripts(tree, createNodes); - } - if (!options.skipFormat) { await formatFiles(tree); } diff --git a/packages/jest/src/generators/configuration/configuration.spec.ts b/packages/jest/src/generators/configuration/configuration.spec.ts index 42e89d53c4255..68691b9079705 100644 --- a/packages/jest/src/generators/configuration/configuration.spec.ts +++ b/packages/jest/src/generators/configuration/configuration.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { addProjectConfiguration, readJson, diff --git a/packages/jest/src/generators/init/init.spec.ts b/packages/jest/src/generators/init/init.spec.ts index eb59d466d95da..6841ce4218131 100644 --- a/packages/jest/src/generators/init/init.spec.ts +++ b/packages/jest/src/generators/init/init.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { type NxJsonConfiguration, readJson, diff --git a/packages/jest/src/generators/init/init.ts b/packages/jest/src/generators/init/init.ts index c0e72f02fcf7c..78c6fed32061d 100644 --- a/packages/jest/src/generators/init/init.ts +++ b/packages/jest/src/generators/init/init.ts @@ -7,33 +7,13 @@ import { updateNxJson, type GeneratorCallback, type Tree, + createProjectGraphAsync, } from '@nx/devkit'; -import { updatePackageScripts } from '@nx/devkit/src/utils/update-package-scripts'; import { createNodes } from '../../plugins/plugin'; import { jestVersion, nxVersion } from '../../utils/versions'; import { isPresetCjs } from '../../utils/config/is-preset-cjs'; import type { JestInitSchema } from './schema'; - -function addPlugin(tree: Tree) { - const nxJson = readNxJson(tree); - - nxJson.plugins ??= []; - if ( - !nxJson.plugins.some((p) => - typeof p === 'string' - ? p === '@nx/jest/plugin' - : p.plugin === '@nx/jest/plugin' - ) - ) { - nxJson.plugins.push({ - plugin: '@nx/jest/plugin', - options: { - targetName: 'test', - }, - }); - } - updateNxJson(tree, nxJson); -} +import { addPlugin } from '@nx/devkit/src/utils/add-plugin'; function updateProductionFileSet(tree: Tree, presetExt: 'cjs' | 'js') { const nxJson = readNxJson(tree); @@ -121,7 +101,16 @@ export async function jestInitGeneratorInternal( if (!tree.exists('jest.preset.js') && !tree.exists('jest.preset.cjs')) { updateProductionFileSet(tree, presetExt); if (options.addPlugin) { - addPlugin(tree); + await addPlugin( + tree, + await createProjectGraphAsync(), + '@nx/jest/plugin', + createNodes, + { + targetName: ['test', 'jest:test', 'jest-test'], + }, + options.updatePackageScripts + ); } else { addJestTargetDefaults(tree, presetExt); } @@ -133,10 +122,6 @@ export async function jestInitGeneratorInternal( tasks.push(updateDependencies(tree, options)); } - if (options.updatePackageScripts) { - await updatePackageScripts(tree, createNodes); - } - if (!options.skipFormat) { await formatFiles(tree); } diff --git a/packages/js/src/generators/convert-to-swc/convert-to-swc.spec.ts b/packages/js/src/generators/convert-to-swc/convert-to-swc.spec.ts index 74591dbe5c414..b424fb99f7d84 100644 --- a/packages/js/src/generators/convert-to-swc/convert-to-swc.spec.ts +++ b/packages/js/src/generators/convert-to-swc/convert-to-swc.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { readProjectConfiguration, Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { join } from 'path'; diff --git a/packages/js/src/generators/library/library.spec.ts b/packages/js/src/generators/library/library.spec.ts index 6e7e9bbed7770..423ee5b406379 100644 --- a/packages/js/src/generators/library/library.spec.ts +++ b/packages/js/src/generators/library/library.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { getPackageManagerCommand, getProjects, diff --git a/packages/js/src/generators/setup-build/generator.spec.ts b/packages/js/src/generators/setup-build/generator.spec.ts index 4c41d0368e05f..66655b65b7df8 100644 --- a/packages/js/src/generators/setup-build/generator.spec.ts +++ b/packages/js/src/generators/setup-build/generator.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { addProjectConfiguration, diff --git a/packages/js/src/generators/setup-verdaccio/generator.spec.ts b/packages/js/src/generators/setup-verdaccio/generator.spec.ts index 62663a75c6d85..022799b97a01d 100644 --- a/packages/js/src/generators/setup-verdaccio/generator.spec.ts +++ b/packages/js/src/generators/setup-verdaccio/generator.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { Tree, readJson, updateJson } from '@nx/devkit'; diff --git a/packages/js/src/migrations/update-15-8-0/rename-swcrc-config.spec.ts b/packages/js/src/migrations/update-15-8-0/rename-swcrc-config.spec.ts index 4285e43fcf8a8..c8fca2d0fce0b 100644 --- a/packages/js/src/migrations/update-15-8-0/rename-swcrc-config.spec.ts +++ b/packages/js/src/migrations/update-15-8-0/rename-swcrc-config.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { readProjectConfiguration, Tree, diff --git a/packages/next/plugins/component-testing.ts b/packages/next/plugins/component-testing.ts index 4974d33064b6f..f867c4dcc8873 100644 --- a/packages/next/plugins/component-testing.ts +++ b/packages/next/plugins/component-testing.ts @@ -29,7 +29,7 @@ export function nxComponentTestingPreset( pathToConfig: string, options?: NxComponentTestingOptions ) { - if (global.NX_GRAPH_CREATION || global.NX_CYPRESS_INIT_GENERATOR_RUNNING) { + if (global.NX_GRAPH_CREATION) { // this is only used by plugins, so we don't need the component testing // options, cast to any to avoid type errors return nxBaseCypressPreset(pathToConfig) as any; diff --git a/packages/next/src/generators/init/init.spec.ts b/packages/next/src/generators/init/init.spec.ts index 96071ccba5f59..a0b3497ed2420 100644 --- a/packages/next/src/generators/init/init.spec.ts +++ b/packages/next/src/generators/init/init.spec.ts @@ -1,12 +1,23 @@ import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import { readJson, NxJsonConfiguration, Tree } from '@nx/devkit'; +import { readJson, Tree, ProjectGraph } from '@nx/devkit'; import { nextInitGenerator } from './init'; +let projectGraph: ProjectGraph; +jest.mock('@nx/devkit', () => ({ + ...jest.requireActual('@nx/devkit'), + createProjectGraphAsync: jest.fn().mockImplementation(async () => { + return projectGraph; + }), +})); describe('init', () => { let tree: Tree; beforeEach(() => { + projectGraph = { + nodes: {}, + dependencies: {}, + }; tree = createTreeWithEmptyWorkspace(); }); diff --git a/packages/next/src/generators/init/init.ts b/packages/next/src/generators/init/init.ts index bb6351de2f51a..7608702ef4b0b 100644 --- a/packages/next/src/generators/init/init.ts +++ b/packages/next/src/generators/init/init.ts @@ -5,12 +5,12 @@ import { type GeneratorCallback, type Tree, readNxJson, + createProjectGraphAsync, } from '@nx/devkit'; -import { updatePackageScripts } from '@nx/devkit/src/utils/update-package-scripts'; +import { addPlugin } from '@nx/devkit/src/utils/add-plugin'; import { reactDomVersion, reactVersion } from '@nx/react/src/utils/versions'; import { addGitIgnoreEntry } from '../../utils/add-gitignore-entry'; import { nextVersion, nxVersion } from '../../utils/versions'; -import { addPlugin } from './lib/add-plugin'; import type { InitSchema } from './schema'; function updateDependencies(host: Tree, schema: InitSchema) { @@ -52,7 +52,24 @@ export async function nextInitGeneratorInternal( schema.addPlugin ??= addPluginDefault; if (schema.addPlugin) { - addPlugin(host); + const { createNodes } = await import('../../plugins/plugin'); + await addPlugin( + host, + await createProjectGraphAsync(), + '@nx/next/plugin', + createNodes, + { + startTargetName: ['start', 'next:start', 'next-start'], + buildTargetName: ['build', 'next:build', 'next-build'], + devTargetName: ['dev', 'next:dev', 'next-dev'], + serveStaticTargetName: [ + 'serve-static', + 'next:serve-static', + 'next-serve-static', + ], + }, + schema.updatePackageScripts + ); } addGitIgnoreEntry(host); @@ -62,11 +79,6 @@ export async function nextInitGeneratorInternal( installTask = updateDependencies(host, schema); } - if (schema.updatePackageScripts) { - const { createNodes } = await import('../../plugins/plugin'); - await updatePackageScripts(host, createNodes); - } - return installTask; } diff --git a/packages/next/src/generators/init/lib/add-plugin.ts b/packages/next/src/generators/init/lib/add-plugin.ts deleted file mode 100644 index 216d065ab4a91..0000000000000 --- a/packages/next/src/generators/init/lib/add-plugin.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Tree, readNxJson, updateNxJson } from '@nx/devkit'; - -export function addPlugin(tree: Tree) { - const nxJson = readNxJson(tree); - nxJson.plugins ??= []; - - for (const plugin of nxJson.plugins) { - if ( - typeof plugin === 'string' - ? plugin === '@nx/next/plugin' - : plugin.plugin === '@nx/next/plugin' - ) { - return; - } - } - - nxJson.plugins.push({ - plugin: '@nx/next/plugin', - options: { - buildTargetName: 'build', - devTargetName: 'dev', - startTargetName: 'start', - serveStaticTargetName: 'serve-static', - }, - }); - - updateNxJson(tree, nxJson); -} diff --git a/packages/nuxt/src/generators/application/application.spec.ts b/packages/nuxt/src/generators/application/application.spec.ts index c1db687c18f34..ef1210a1ffa4e 100644 --- a/packages/nuxt/src/generators/application/application.spec.ts +++ b/packages/nuxt/src/generators/application/application.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { Tree, readJson, readProjectConfiguration } from '@nx/devkit'; import { applicationGenerator } from './application'; @@ -57,6 +59,37 @@ describe('app', () => { expect(tree.read('my-app/project.json', 'utf-8')).toMatchSnapshot(); expect(tree.read('my-app/tsconfig.json', 'utf-8')).toMatchSnapshot(); }); + + it('should add the nuxt and vitest plugins', () => { + const nxJson = readJson(tree, 'nx.json'); + expect(nxJson.plugins).toMatchObject([ + { + plugin: '@nx/eslint/plugin', + options: { targetName: 'lint' }, + }, + { + plugin: '@nx/vite/plugin', + options: { testTargetName: 'test' }, + }, + { + plugin: '@nx/nuxt/plugin', + options: { buildTargetName: 'build', serveTargetName: 'serve' }, + }, + { + plugin: '@nx/cypress/plugin', + options: { targetName: 'e2e' }, + }, + ]); + expect( + nxJson.plugins.indexOf( + nxJson.plugins.find((p) => p.plugin === '@nx/nuxt/plugin') + ) + ).toBeGreaterThan( + nxJson.plugins.indexOf( + nxJson.plugins.find((p) => p.plugin === '@nx/vite/plugin') + ) + ); + }); }); describe('styles setup', () => { diff --git a/packages/nuxt/src/generators/application/application.ts b/packages/nuxt/src/generators/application/application.ts index 24d98a1d61271..4b16a335363be 100644 --- a/packages/nuxt/src/generators/application/application.ts +++ b/packages/nuxt/src/generators/application/application.ts @@ -40,11 +40,6 @@ export async function applicationGenerator(tree: Tree, schema: Schema) { skipFormat: true, }); tasks.push(jsInitTask); - const nuxtInitTask = await nuxtInitGenerator(tree, { - ...options, - skipFormat: true, - }); - tasks.push(nuxtInitTask); tasks.push(ensureDependencies(tree, options)); addProjectConfiguration(tree, options.name, { @@ -113,6 +108,12 @@ export async function applicationGenerator(tree: Tree, schema: Schema) { tasks.push(await addVitest(tree, options)); } + const nuxtInitTask = await nuxtInitGenerator(tree, { + ...options, + skipFormat: true, + }); + tasks.push(nuxtInitTask); + tasks.push(await addE2e(tree, options)); if (options.js) toJS(tree); diff --git a/packages/nuxt/src/generators/init/init.spec.ts b/packages/nuxt/src/generators/init/init.spec.ts index 051051613932f..b5885a2deecab 100644 --- a/packages/nuxt/src/generators/init/init.spec.ts +++ b/packages/nuxt/src/generators/init/init.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { readJson, readNxJson, Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { nuxtInitGenerator } from './init'; @@ -31,10 +33,6 @@ describe('init', () => { options: { buildTargetName: 'build', serveTargetName: 'serve' }, plugin: '@nx/nuxt/plugin', }, - { - options: { testTargetName: 'test' }, - plugin: '@nx/vite/plugin', - }, ]); }); }); diff --git a/packages/nuxt/src/generators/init/init.ts b/packages/nuxt/src/generators/init/init.ts index 30dc670fc87e3..819b22f609a5c 100644 --- a/packages/nuxt/src/generators/init/init.ts +++ b/packages/nuxt/src/generators/init/init.ts @@ -1,22 +1,28 @@ -import { GeneratorCallback, Tree } from '@nx/devkit'; -import { updatePackageScripts } from '@nx/devkit/src/utils/update-package-scripts'; +import { createProjectGraphAsync, GeneratorCallback, Tree } from '@nx/devkit'; +import { addPlugin } from '@nx/devkit/src/utils/add-plugin'; import { createNodes } from '../../plugins/plugin'; import { InitSchema } from './schema'; -import { addPlugin, updateDependencies } from './lib/utils'; +import { updateDependencies } from './lib/utils'; export async function nuxtInitGenerator(host: Tree, schema: InitSchema) { - addPlugin(host); + await addPlugin( + host, + await createProjectGraphAsync(), + '@nx/nuxt/plugin', + createNodes, + { + buildTargetName: ['build', 'nuxt:build', 'nuxt-build'], + serveTargetName: ['serve', 'nuxt:serve', 'nuxt-serve'], + }, + schema.updatePackageScripts + ); let installTask: GeneratorCallback = () => {}; if (!schema.skipPackageJson) { installTask = updateDependencies(host, schema); } - if (schema.updatePackageScripts) { - await updatePackageScripts(host, createNodes); - } - return installTask; } diff --git a/packages/nuxt/src/generators/storybook-configuration/configuration.spec.ts b/packages/nuxt/src/generators/storybook-configuration/configuration.spec.ts index 21a95f4ada5f2..c2954143b33c3 100644 --- a/packages/nuxt/src/generators/storybook-configuration/configuration.spec.ts +++ b/packages/nuxt/src/generators/storybook-configuration/configuration.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { logger, Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { Linter } from '@nx/eslint'; diff --git a/packages/nx/src/command-line/init/implementation/add-nx-to-monorepo.ts b/packages/nx/src/command-line/init/implementation/add-nx-to-monorepo.ts index 4e11f0ee06d1a..a767f5d1feb2d 100644 --- a/packages/nx/src/command-line/init/implementation/add-nx-to-monorepo.ts +++ b/packages/nx/src/command-line/init/implementation/add-nx-to-monorepo.ts @@ -96,10 +96,7 @@ export async function addNxToMonorepo(options: Options) { ); if (!options.legacy) { packageJsonFiles.forEach((packageJsonPath) => { - markPackageJsonAsNxProject( - join(repoRoot, packageJsonPath), - cacheableOperations - ); + markPackageJsonAsNxProject(join(repoRoot, packageJsonPath)); }); } diff --git a/packages/nx/src/command-line/init/implementation/add-nx-to-npm-repo.ts b/packages/nx/src/command-line/init/implementation/add-nx-to-npm-repo.ts index b8dbffde2f957..c8a3263ebe0a3 100644 --- a/packages/nx/src/command-line/init/implementation/add-nx-to-npm-repo.ts +++ b/packages/nx/src/command-line/init/implementation/add-nx-to-npm-repo.ts @@ -85,10 +85,7 @@ export async function addNxToNpmRepo(options: Options) { if (options.legacy) { markRootPackageJsonAsNxProjectLegacy(repoRoot, cacheableOperations, pmc); } else { - markPackageJsonAsNxProject( - join(repoRoot, 'package.json'), - cacheableOperations - ); + markPackageJsonAsNxProject(join(repoRoot, 'package.json')); } output.log({ title: '📦 Installing dependencies' }); diff --git a/packages/nx/src/command-line/init/implementation/utils.ts b/packages/nx/src/command-line/init/implementation/utils.ts index c8bfeb835b37c..ce133924bcb1d 100644 --- a/packages/nx/src/command-line/init/implementation/utils.ts +++ b/packages/nx/src/command-line/init/implementation/utils.ts @@ -194,21 +194,13 @@ export function markRootPackageJsonAsNxProjectLegacy( writeJsonFile(`package.json`, json); } -export function markPackageJsonAsNxProject( - packageJsonPath: string, - cacheableScripts: string[] -) { +export function markPackageJsonAsNxProject(packageJsonPath: string) { const json = readJsonFile(packageJsonPath); if (!json.scripts) { return; } - json.nx = { includedScripts: [] }; - for (let script of cacheableScripts) { - if (json.scripts[script]) { - json.nx.includedScripts.push(script); - } - } + json.nx = {}; writeJsonFile(packageJsonPath, json); } diff --git a/packages/nx/src/command-line/init/init-v2.ts b/packages/nx/src/command-line/init/init-v2.ts index 84878c119260a..62e11f83cbc34 100644 --- a/packages/nx/src/command-line/init/init-v2.ts +++ b/packages/nx/src/command-line/init/init-v2.ts @@ -74,34 +74,35 @@ export async function initHandler(options: InitArgs): Promise { const { plugins, updatePackageScripts } = await detectPlugins(); - if (!plugins.length) { - // If no plugins are detected/chosen, guide users to setup - // their targetDefaults correctly so their package scripts will work. - const packageJson: PackageJson = readJsonFile('package.json'); - if (isMonorepo(packageJson)) { - await addNxToMonorepo({ interactive: options.interactive }); - } else { - await addNxToNpmRepo({ interactive: options.interactive }); - } + const packageJson: PackageJson = readJsonFile('package.json'); + if (isMonorepo(packageJson)) { + await addNxToMonorepo({ + interactive: options.interactive, + nxCloud: false, + }); } else { - const useNxCloud = - options.nxCloud ?? - (options.interactive - ? await connectExistingRepoToNxCloudPrompt() - : false); + await addNxToNpmRepo({ + interactive: options.interactive, + nxCloud: false, + }); + } + const useNxCloud = + options.nxCloud ?? + (options.interactive ? await connectExistingRepoToNxCloudPrompt() : false); - const repoRoot = process.cwd(); - const pmc = getPackageManagerCommand(); + const repoRoot = process.cwd(); + const pmc = getPackageManagerCommand(); - createNxJsonFile(repoRoot, [], [], {}); - updateGitIgnore(repoRoot); + createNxJsonFile(repoRoot, [], [], {}); + updateGitIgnore(repoRoot); - addDepsToPackageJson(repoRoot, plugins); + addDepsToPackageJson(repoRoot, plugins); - output.log({ title: '📦 Installing Nx' }); + output.log({ title: '📦 Installing Nx' }); - runInstall(repoRoot, pmc); + runInstall(repoRoot, pmc); + if (plugins.length > 0) { output.log({ title: '🔨 Configuring plugins' }); for (const plugin of plugins) { execSync( @@ -114,24 +115,17 @@ export async function initHandler(options: InitArgs): Promise { } ); } + } - if (!updatePackageScripts) { - const rootPackageJsonPath = join(repoRoot, 'package.json'); - const json = readJsonFile(rootPackageJsonPath); - json.nx = { includedScripts: [] }; - writeJsonFile(rootPackageJsonPath, json); - } - - if (useNxCloud) { - output.log({ title: '🛠️ Setting up Nx Cloud' }); - execSync( - `${pmc.exec} nx g nx:connect-to-nx-cloud --installationSource=nx-init --quiet --hideFormatLogs --no-interactive`, - { - stdio: [0, 1, 2], - cwd: repoRoot, - } - ); - } + if (useNxCloud) { + output.log({ title: '🛠️ Setting up Nx Cloud' }); + execSync( + `${pmc.exec} nx g nx:connect-to-nx-cloud --installationSource=nx-init --quiet --hideFormatLogs --no-interactive`, + { + stdio: [0, 1, 2], + cwd: repoRoot, + } + ); } output.log({ @@ -220,9 +214,8 @@ async function detectPlugins(): Promise<{ { name: 'plugins', type: 'multiselect', - message: `Which plugins would you like to add?`, + message: `Which plugins would you like to add? Press to select and to submit.`, choices: plugins.map((p) => ({ name: p, value: p })), - initial: plugins.map((_, i) => i) as unknown as number, // casting to avoid type error due to bad d.ts file from enquirer }, ]).then((r) => r.plugins); diff --git a/packages/nx/src/devkit-internals.ts b/packages/nx/src/devkit-internals.ts index a24b33c98670a..7e50804f08874 100644 --- a/packages/nx/src/devkit-internals.ts +++ b/packages/nx/src/devkit-internals.ts @@ -20,4 +20,7 @@ export { createProjectRootMappingsFromProjectConfigurations, findProjectForPath, } from './project-graph/utils/find-project-for-path'; +export { retrieveProjectConfigurations } from './project-graph/utils/retrieve-workspace-files'; +export { LoadedNxPlugin } from './project-graph/plugins/internal-api'; +export * from './project-graph/error-types'; export { registerTsProject } from './plugins/js/utils/register'; diff --git a/packages/nx/src/internal-testing-utils/mock-project-graph.ts b/packages/nx/src/internal-testing-utils/mock-project-graph.ts new file mode 100644 index 0000000000000..59550e717f35b --- /dev/null +++ b/packages/nx/src/internal-testing-utils/mock-project-graph.ts @@ -0,0 +1,9 @@ +jest.doMock('@nx/devkit', () => ({ + ...jest.requireActual('@nx/devkit'), + createProjectGraphAsync: jest.fn().mockImplementation(async () => { + return { + nodes: {}, + dependencies: {}, + }; + }), +})); diff --git a/packages/nx/src/project-graph/error-types.ts b/packages/nx/src/project-graph/error-types.ts index 87ca50d23af91..92eb4fef9dc04 100644 --- a/packages/nx/src/project-graph/error-types.ts +++ b/packages/nx/src/project-graph/error-types.ts @@ -1,9 +1,70 @@ import { CreateNodesResultWithContext } from './plugins/internal-api'; import { ConfigurationResult } from './utils/project-configuration-utils'; +import { ProjectConfiguration } from '../config/workspace-json-project-json'; + +export class ProjectsWithConflictingNamesError extends Error { + constructor( + conflicts: Map, + public projects: Record + ) { + super( + [ + `The following projects are defined in multiple locations:`, + ...Array.from(conflicts.entries()).map(([project, roots]) => + [`- ${project}: `, ...roots.map((r) => ` - ${r}`)].join('\n') + ), + '', + "To fix this, set a unique name for each project in a project.json inside the project's root. If the project does not currently have a project.json, you can create one that contains only a name.", + ].join('\n') + ); + this.name = this.constructor.name; + } +} + +export function isProjectsWithConflictingNamesError( + e: unknown +): e is ProjectsWithConflictingNamesError { + return ( + e instanceof ProjectsWithConflictingNamesError || + (typeof e === 'object' && + 'name' in e && + e?.name === ProjectsWithConflictingNamesError.prototype.name) + ); +} + +export class ProjectsWithNoNameError extends Error { + constructor( + projectRoots: string[], + public projects: Record + ) { + super( + `The projects in the following directories have no name provided:\n - ${projectRoots.join( + '\n - ' + )}` + ); + this.name = this.constructor.name; + } +} + +export function isProjectsWithNoNameError( + e: unknown +): e is ProjectsWithNoNameError { + return ( + e instanceof ProjectsWithNoNameError || + (typeof e === 'object' && + 'name' in e && + e?.name === ProjectsWithNoNameError.prototype.name) + ); +} export class ProjectConfigurationsError extends Error { constructor( - public readonly errors: Array, + public readonly errors: Array< + | MergeNodesError + | CreateNodesError + | ProjectsWithNoNameError + | ProjectsWithConflictingNamesError + >, public readonly partialProjectConfigurationsResult: ConfigurationResult ) { super('Failed to create project configurations'); diff --git a/packages/nx/src/project-graph/file-utils.ts b/packages/nx/src/project-graph/file-utils.ts index 800654067c225..cffed56f53b35 100644 --- a/packages/nx/src/project-graph/file-utils.ts +++ b/packages/nx/src/project-graph/file-utils.ts @@ -173,6 +173,7 @@ export function readPackageJson(): any { return {}; // if package.json doesn't exist } } + // Original Exports export { FileData }; // TODO(17): Remove these exports diff --git a/packages/nx/src/project-graph/project-graph.ts b/packages/nx/src/project-graph/project-graph.ts index 05b8967a3cb4e..5fa8035661aed 100644 --- a/packages/nx/src/project-graph/project-graph.ts +++ b/packages/nx/src/project-graph/project-graph.ts @@ -34,6 +34,8 @@ import { CreateNodesError, MergeNodesError, ProjectConfigurationsError, + ProjectsWithNoNameError, + ProjectsWithConflictingNamesError, } from './error-types'; import { DaemonProjectGraphError } from '../daemon/daemon-project-graph-error'; import { loadNxPlugins, LoadedNxPlugin } from './plugins/internal-api'; @@ -179,7 +181,12 @@ export async function buildProjectGraphAndSourceMapsWithoutDaemon() { export class ProjectGraphError extends Error { readonly #errors: Array< - CreateNodesError | ProcessDependenciesError | ProcessProjectGraphError + | CreateNodesError + | MergeNodesError + | ProjectsWithNoNameError + | ProjectsWithConflictingNamesError + | ProcessDependenciesError + | ProcessProjectGraphError >; readonly #partialProjectGraph: ProjectGraph; readonly #partialSourceMaps: ConfigurationSourceMaps; @@ -188,6 +195,8 @@ export class ProjectGraphError extends Error { errors: Array< | CreateNodesError | MergeNodesError + | ProjectsWithNoNameError + | ProjectsWithConflictingNamesError | ProcessDependenciesError | ProcessProjectGraphError >, diff --git a/packages/nx/src/project-graph/utils/project-configuration-utils.spec.ts b/packages/nx/src/project-graph/utils/project-configuration-utils.spec.ts index 69ad981d3fac4..4c6380fb58cfe 100644 --- a/packages/nx/src/project-graph/utils/project-configuration-utils.spec.ts +++ b/packages/nx/src/project-graph/utils/project-configuration-utils.spec.ts @@ -1555,7 +1555,11 @@ describe('project-configuration-utils', () => { undefined, {}, ['libs/a/project.json', 'libs/b/project.json'], - [new LoadedNxPlugin(fakeTagPlugin, { plugin: fakeTagPlugin.name })] + [ + new LoadedNxPlugin(fakeTagPlugin, { + plugin: fakeTagPlugin.name, + }), + ] ); expect(projectConfigurations.projects).toEqual({ diff --git a/packages/nx/src/project-graph/utils/project-configuration-utils.ts b/packages/nx/src/project-graph/utils/project-configuration-utils.ts index 20448f4489936..13caded32c3c9 100644 --- a/packages/nx/src/project-graph/utils/project-configuration-utils.ts +++ b/packages/nx/src/project-graph/utils/project-configuration-utils.ts @@ -26,6 +26,10 @@ import { MergeNodesError, ProjectConfigurationsError, isAggregateCreateNodesError, + ProjectsWithNoNameError, + ProjectsWithConflictingNamesError, + isProjectsWithConflictingNamesError, + isProjectsWithNoNameError, } from '../error-types'; export type SourceInformation = [file: string, plugin: string]; @@ -321,7 +325,12 @@ export async function createProjectConfigurations( performance.mark('build-project-configs:start'); const results: Array>> = []; - const errors: Array = []; + const errors: Array< + | CreateNodesError + | MergeNodesError + | ProjectsWithNoNameError + | ProjectsWithConflictingNamesError + > = []; // We iterate over plugins first - this ensures that plugins specified first take precedence. for (const { @@ -425,7 +434,21 @@ export async function createProjectConfigurations( Object.assign(externalNodes, pluginExternalNodes); } - const projects = readProjectConfigurationsFromRootMap(projectRootMap); + let projects: Record; + try { + projects = readProjectConfigurationsFromRootMap(projectRootMap); + } catch (e) { + if ( + isProjectsWithNoNameError(e) || + isProjectsWithConflictingNamesError(e) + ) { + projects = e.projects; + errors.push(e); + } else { + throw e; + } + } + const rootMap = createRootMap(projectRootMap); performance.mark('createNodes:merge - end'); @@ -467,7 +490,8 @@ export function readProjectConfigurationsFromRootMap( // If there are projects that have the same name, that is an error. // This object tracks name -> (all roots of projects with that name) // to provide better error messaging. - const errors: Map = new Map(); + const conflicts = new Map(); + const projectRootsWithNoName: string[] = []; for (const [root, configuration] of projectRootMap.entries()) { // We're setting `// targets` as a comment `targets` is empty due to Project Crystal. @@ -478,31 +502,26 @@ export function readProjectConfigurationsFromRootMap( const { name } = readJsonFile(join(root, 'package.json')); configuration.name = name; } catch { - throw new Error(`Project at ${root} has no name provided.`); + projectRootsWithNoName.push(root); } } if (configuration.name in projects) { - let rootErrors = errors.get(configuration.name) ?? [ + let rootErrors = conflicts.get(configuration.name) ?? [ projects[configuration.name].root, ]; rootErrors.push(root); - errors.set(configuration.name, rootErrors); + conflicts.set(configuration.name, rootErrors); + projects[configuration.name] = configuration; } else { projects[configuration.name] = configuration; } } - if (errors.size > 0) { - throw new Error( - [ - `The following projects are defined in multiple locations:`, - ...Array.from(errors.entries()).map(([project, roots]) => - [`- ${project}: `, ...roots.map((r) => ` - ${r}`)].join('\n') - ), - '', - "To fix this, set a unique name for each project in a project.json inside the project's root. If the project does not currently have a project.json, you can create one that contains only a name.", - ].join('\n') - ); + if (conflicts.size > 0) { + throw new ProjectsWithConflictingNamesError(conflicts, projects); + } + if (projectRootsWithNoName.length > 0) { + throw new ProjectsWithNoNameError(projectRootsWithNoName, projects); } return projects; } diff --git a/packages/nx/src/project-graph/utils/retrieve-workspace-files.ts b/packages/nx/src/project-graph/utils/retrieve-workspace-files.ts index 1b54a2154c0b5..d61a11cef9a4b 100644 --- a/packages/nx/src/project-graph/utils/retrieve-workspace-files.ts +++ b/packages/nx/src/project-graph/utils/retrieve-workspace-files.ts @@ -6,8 +6,8 @@ import { } from '../../adapter/angular-json'; import { NxJsonConfiguration, readNxJson } from '../../config/nx-json'; import { - createProjectConfigurations, ConfigurationResult, + createProjectConfigurations, } from './project-configuration-utils'; import { LoadedNxPlugin, loadNxPlugins } from '../plugins/internal-api'; import { @@ -16,7 +16,6 @@ import { } from '../../utils/workspace-context'; import { buildAllWorkspaceFiles } from './build-all-workspace-files'; import { join } from 'path'; -import { NxPlugin } from '../plugins'; /** * Walks the workspace directory to create the `projectFileMap`, `ProjectConfigurations` and `allWorkspaceFiles` @@ -60,17 +59,21 @@ export async function retrieveWorkspaceFiles( /** * Walk through the workspace and return `ProjectConfigurations`. Only use this if the projectFileMap is not needed. */ -export async function retrieveProjectConfigurations( + +export function retrieveProjectConfigurations( plugins: LoadedNxPlugin[], workspaceRoot: string, nxJson: NxJsonConfiguration ): Promise { - const projects = await _retrieveProjectConfigurations( + const globPatterns = configurationGlobs(plugins); + const workspaceFiles = globWithWorkspaceContext(workspaceRoot, globPatterns); + + return createProjectConfigurations( workspaceRoot, nxJson, + workspaceFiles, plugins ); - return projects; } export async function retrieveProjectConfigurationsWithAngularProjects( @@ -95,27 +98,11 @@ export async function retrieveProjectConfigurationsWithAngularProjects( workspaceRoot ); - const res = _retrieveProjectConfigurations(workspaceRoot, nxJson, plugins); + const res = retrieveProjectConfigurations(plugins, workspaceRoot, nxJson); cleanup(); return res; } -function _retrieveProjectConfigurations( - workspaceRoot: string, - nxJson: NxJsonConfiguration, - plugins: LoadedNxPlugin[] -): Promise { - const globPatterns = configurationGlobs(plugins); - const workspaceFiles = globWithWorkspaceContext(workspaceRoot, globPatterns); - - return createProjectConfigurations( - workspaceRoot, - nxJson, - workspaceFiles, - plugins - ); -} - export function retrieveProjectConfigurationPaths( root: string, plugins: Array<{ createNodes?: readonly [string, ...unknown[]] } & unknown> diff --git a/packages/nx/src/utils/nx-plugin.deprecated.ts b/packages/nx/src/utils/nx-plugin.deprecated.ts index 6bd67d63ab923..f4bde883ad6d8 100644 --- a/packages/nx/src/utils/nx-plugin.deprecated.ts +++ b/packages/nx/src/utils/nx-plugin.deprecated.ts @@ -5,7 +5,6 @@ import ProjectJsonProjectsPlugin from '../plugins/project-json/build-nodes/proje import TargetDefaultsPlugin from '../plugins/target-defaults/target-defaults-plugin'; import * as PackageJsonWorkspacesPlugin from '../plugins/package-json-workspaces'; import { NxPluginV2 } from '../project-graph/plugins'; -import { LoadedNxPlugin } from '../project-graph/plugins/internal-api'; /** * @deprecated Add targets to the projects in a {@link CreateNodes} function instead. This will be removed in Nx 19 diff --git a/packages/playwright/src/generators/init/init.spec.ts b/packages/playwright/src/generators/init/init.spec.ts index f93ee184ab4ad..c4dea0c653753 100644 --- a/packages/playwright/src/generators/init/init.spec.ts +++ b/packages/playwright/src/generators/init/init.spec.ts @@ -1,12 +1,24 @@ -import { readNxJson, Tree, updateNxJson } from '@nx/devkit'; +import { ProjectGraph, readNxJson, Tree, updateNxJson } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { initGenerator } from './init'; +let projectGraph: ProjectGraph; +jest.mock('@nx/devkit', () => ({ + ...jest.requireActual('@nx/devkit'), + createProjectGraphAsync: jest.fn().mockImplementation(async () => { + return projectGraph; + }), +})); + describe('@nx/playwright:init', () => { let tree: Tree; beforeEach(() => { + projectGraph = { + nodes: {}, + dependencies: {}, + }; tree = createTreeWithEmptyWorkspace(); }); diff --git a/packages/playwright/src/generators/init/init.ts b/packages/playwright/src/generators/init/init.ts index ac008f8246db7..ae90ae3a95556 100644 --- a/packages/playwright/src/generators/init/init.ts +++ b/packages/playwright/src/generators/init/init.ts @@ -1,13 +1,13 @@ import { addDependenciesToPackageJson, + createProjectGraphAsync, formatFiles, GeneratorCallback, readNxJson, runTasksInSerial, Tree, - updateNxJson, } from '@nx/devkit'; -import { updatePackageScripts } from '@nx/devkit/src/utils/update-package-scripts'; +import { addPlugin } from '@nx/devkit/src/utils/add-plugin'; import { createNodes } from '../../plugins/plugin'; import { nxVersion, playwrightVersion } from '../../utils/versions'; import { InitGeneratorSchema } from './schema'; @@ -45,11 +45,14 @@ export async function initGeneratorInternal( } if (options.addPlugin) { - addPlugin(tree); - } - - if (options.updatePackageScripts) { - await updatePackageScripts(tree, createNodes); + await addPlugin( + tree, + await createProjectGraphAsync(), + '@nx/playwright/plugin', + createNodes, + { targetName: ['e2e', 'playwright:e2e', 'playwright-e2e'] }, + options.updatePackageScripts + ); } if (!options.skipFormat) { @@ -59,25 +62,4 @@ export async function initGeneratorInternal( return runTasksInSerial(...tasks); } -function addPlugin(tree: Tree) { - const nxJson = readNxJson(tree); - nxJson.plugins ??= []; - - if ( - !nxJson.plugins.some((p) => - typeof p === 'string' - ? p === '@nx/playwright/plugin' - : p.plugin === '@nx/playwright/plugin' - ) - ) { - nxJson.plugins.push({ - plugin: '@nx/playwright/plugin', - options: { - targetName: 'e2e', - }, - }); - updateNxJson(tree, nxJson); - } -} - export default initGenerator; diff --git a/packages/plugin/src/generators/create-package/create-package.spec.ts b/packages/plugin/src/generators/create-package/create-package.spec.ts index b76013fca5ff3..5c2a5875e29f1 100644 --- a/packages/plugin/src/generators/create-package/create-package.spec.ts +++ b/packages/plugin/src/generators/create-package/create-package.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { joinPathFragments, readJson, diff --git a/packages/plugin/src/generators/e2e-project/e2e.spec.ts b/packages/plugin/src/generators/e2e-project/e2e.spec.ts index 67df561e9728c..d5fb89da1dd02 100644 --- a/packages/plugin/src/generators/e2e-project/e2e.spec.ts +++ b/packages/plugin/src/generators/e2e-project/e2e.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { Tree, addProjectConfiguration, diff --git a/packages/plugin/src/generators/executor/executor.spec.ts b/packages/plugin/src/generators/executor/executor.spec.ts index 3215fef82ad50..e0f827c133f28 100644 --- a/packages/plugin/src/generators/executor/executor.spec.ts +++ b/packages/plugin/src/generators/executor/executor.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { Tree, readJson, readProjectConfiguration } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { executorGenerator } from './executor'; diff --git a/packages/plugin/src/generators/generator/generator.spec.ts b/packages/plugin/src/generators/generator/generator.spec.ts index b2543f6c377ee..d21d815eba33e 100644 --- a/packages/plugin/src/generators/generator/generator.spec.ts +++ b/packages/plugin/src/generators/generator/generator.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { GeneratorsJson, readJson, diff --git a/packages/plugin/src/generators/lint-checks/generator.spec.ts b/packages/plugin/src/generators/lint-checks/generator.spec.ts index 7485c4dd71287..21e04270c0886 100644 --- a/packages/plugin/src/generators/lint-checks/generator.spec.ts +++ b/packages/plugin/src/generators/lint-checks/generator.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { Tree, diff --git a/packages/plugin/src/generators/migration/migration.spec.ts b/packages/plugin/src/generators/migration/migration.spec.ts index 2e1d0ac3f4599..2e979aecab5e1 100644 --- a/packages/plugin/src/generators/migration/migration.spec.ts +++ b/packages/plugin/src/generators/migration/migration.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { readJson, readProjectConfiguration, Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { migrationGenerator } from './migration'; diff --git a/packages/plugin/src/generators/plugin/plugin.spec.ts b/packages/plugin/src/generators/plugin/plugin.spec.ts index ff7e6adae2405..6d86517677374 100644 --- a/packages/plugin/src/generators/plugin/plugin.spec.ts +++ b/packages/plugin/src/generators/plugin/plugin.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { getProjects, joinPathFragments, diff --git a/packages/plugin/src/generators/preset/generator.spec.ts b/packages/plugin/src/generators/preset/generator.spec.ts index 14dfc06ffbbba..9a486fddaabe1 100644 --- a/packages/plugin/src/generators/preset/generator.spec.ts +++ b/packages/plugin/src/generators/preset/generator.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { Tree, readProjectConfiguration, readJson } from '@nx/devkit'; diff --git a/packages/plugin/src/migrations/update-15-0-0/specify-output-capture.spec.ts b/packages/plugin/src/migrations/update-15-0-0/specify-output-capture.spec.ts index 1cfb2f9f0eeac..11c36067a09b3 100644 --- a/packages/plugin/src/migrations/update-15-0-0/specify-output-capture.spec.ts +++ b/packages/plugin/src/migrations/update-15-0-0/specify-output-capture.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { readJson, updateJson } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { Linter } from '@nx/eslint'; diff --git a/packages/plugin/src/migrations/update-15-9-0/update-configs-jest-29.spec.ts b/packages/plugin/src/migrations/update-15-9-0/update-configs-jest-29.spec.ts index 316dc9f29e29a..581d6dd424580 100644 --- a/packages/plugin/src/migrations/update-15-9-0/update-configs-jest-29.spec.ts +++ b/packages/plugin/src/migrations/update-15-9-0/update-configs-jest-29.spec.ts @@ -5,8 +5,6 @@ import { Tree, updateProjectConfiguration, } from '@nx/devkit'; -import { updateConfigsJest29 } from './jest-29-configs'; -import { libraryGenerator } from '@nx/js'; let projectGraph: ProjectGraph; jest.mock('@nx/devkit', () => ({ @@ -16,6 +14,9 @@ jest.mock('@nx/devkit', () => ({ }), })); +import { updateConfigsJest29 } from './jest-29-configs'; +import { libraryGenerator } from '@nx/js'; + describe('Nx Plugin Migration - jest 29 update configs', () => { let tree: Tree; diff --git a/packages/plugin/src/migrations/update-15-9-0/update-tests-jest-29.spec.ts b/packages/plugin/src/migrations/update-15-9-0/update-tests-jest-29.spec.ts index 7ee6cdf0bae2a..a8c1ed80fcfbc 100644 --- a/packages/plugin/src/migrations/update-15-9-0/update-tests-jest-29.spec.ts +++ b/packages/plugin/src/migrations/update-15-9-0/update-tests-jest-29.spec.ts @@ -5,8 +5,6 @@ import { updateProjectConfiguration, } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import { libraryGenerator } from '@nx/js'; -import { updateTestsJest29 } from './jest-29-tests'; let projectGraph: ProjectGraph; jest.mock('@nx/devkit', () => ({ @@ -15,6 +13,10 @@ jest.mock('@nx/devkit', () => ({ .fn() .mockImplementation(async () => projectGraph), })); + +import { libraryGenerator } from '@nx/js'; +import { updateTestsJest29 } from './jest-29-tests'; + describe('Nx Plugin Migration - jest 29 mocked usage in tests', () => { let tree: Tree; beforeEach(() => { 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 index 70aead7bdefe1..d338f688615fd 100644 --- 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 @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { ExecutorsJson, GeneratorsJson, diff --git a/packages/react-native/src/generators/application/application.spec.ts b/packages/react-native/src/generators/application/application.spec.ts index 14db3d844993e..ca2343713d156 100644 --- a/packages/react-native/src/generators/application/application.spec.ts +++ b/packages/react-native/src/generators/application/application.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { Tree, getProjects, diff --git a/packages/react-native/src/generators/component/component.spec.ts b/packages/react-native/src/generators/component/component.spec.ts index 809087900b04e..6b6a8ac376eae 100644 --- a/packages/react-native/src/generators/component/component.spec.ts +++ b/packages/react-native/src/generators/component/component.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { logger, Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { createApp, createLib } from '../../utils/testing-generators'; diff --git a/packages/react-native/src/generators/init/init.spec.ts b/packages/react-native/src/generators/init/init.spec.ts index 85ccf173c18c1..2e0939bc08788 100644 --- a/packages/react-native/src/generators/init/init.spec.ts +++ b/packages/react-native/src/generators/init/init.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { Tree, readJson } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { reactNativeInitGenerator } from './init'; diff --git a/packages/react-native/src/generators/init/init.ts b/packages/react-native/src/generators/init/init.ts index 5a1e5a21ff05e..be1331f55cf0e 100644 --- a/packages/react-native/src/generators/init/init.ts +++ b/packages/react-native/src/generators/init/init.ts @@ -1,15 +1,15 @@ import { addDependenciesToPackageJson, + createProjectGraphAsync, formatFiles, GeneratorCallback, readNxJson, removeDependenciesFromPackageJson, runTasksInSerial, Tree, - updateNxJson, } from '@nx/devkit'; -import { updatePackageScripts } from '@nx/devkit/src/utils/update-package-scripts'; -import { createNodes, ReactNativePluginOptions } from '../../../plugins/plugin'; +import { addPlugin } from '@nx/devkit/src/utils/add-plugin'; +import { createNodes } from '../../../plugins/plugin'; import { nxVersion, reactDomVersion, @@ -39,7 +39,57 @@ export async function reactNativeInitGeneratorInternal( schema.addPlugin ??= addPluginDefault; if (schema.addPlugin) { - addPlugin(host); + await addPlugin( + host, + await createProjectGraphAsync(), + '@nx/react-native/plugin', + createNodes, + { + startTargetName: ['start', 'react-native:start', 'react-native-start'], + upgradeTargetname: [ + 'update', + 'react-native:update', + 'react-native-update', + ], + bundleTargetName: [ + 'bundle', + 'react-native:bundle', + 'react-native-bundle', + ], + + podInstallTargetName: [ + 'pod-install', + 'react-native:pod-install', + 'react-native-pod-install', + ], + runIosTargetName: [ + 'run-ios', + 'react-native:run-ios', + 'react-native-run-ios', + ], + runAndroidTargetName: [ + 'run-android', + 'react-native:run-android', + 'react-native-run-android', + ], + buildIosTargetName: [ + 'build-ios', + 'react-native:build-ios', + 'react-native-build-ios', + ], + buildAndroidTargetName: [ + 'build-android', + 'react-native:build-android', + 'react-native-build-android', + ], + syncDepsTargetName: [ + 'sync-deps', + 'react-native:sync-deps', + 'react-native-sync-deps', + ], + }, + schema.updatePackageScripts + ); } const tasks: GeneratorCallback[] = []; @@ -48,10 +98,6 @@ export async function reactNativeInitGeneratorInternal( tasks.push(updateDependencies(host, schema)); } - if (schema.updatePackageScripts) { - await updatePackageScripts(host, createNodes); - } - if (!schema.skipFormat) { await formatFiles(host); } @@ -79,35 +125,4 @@ function moveDependency(host: Tree) { return removeDependenciesFromPackageJson(host, ['@nx/react-native'], []); } -function addPlugin(host: Tree) { - const nxJson = readNxJson(host); - nxJson.plugins ??= []; - - for (const plugin of nxJson.plugins) { - if ( - typeof plugin === 'string' - ? plugin === '@nx/react-native/plugin' - : plugin.plugin === '@nx/react-native/plugin' - ) { - return; - } - } - - nxJson.plugins.push({ - plugin: '@nx/react-native/plugin', - options: { - startTargetName: 'start', - podInstallTargetName: 'pod-install', - bundleTargetName: 'bundle', - runIosTargetName: 'run-ios', - runAndroidTargetName: 'run-android', - buildIosTargetName: 'build-ios', - buildAndroidTargetName: 'build-android', - syncDepsTargetName: 'sync-deps', - upgradeTargetname: 'upgrade', - } as ReactNativePluginOptions, - }); - updateNxJson(host, nxJson); -} - export default reactNativeInitGenerator; diff --git a/packages/react-native/src/generators/library/library.spec.ts b/packages/react-native/src/generators/library/library.spec.ts index 9ecd71d0ebc25..0c0d799ac26c3 100644 --- a/packages/react-native/src/generators/library/library.spec.ts +++ b/packages/react-native/src/generators/library/library.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { readJson, readProjectConfiguration, diff --git a/packages/react-native/src/utils/add-linting.spec.ts b/packages/react-native/src/utils/add-linting.spec.ts index dda057ead8d5c..388026a4a5674 100644 --- a/packages/react-native/src/utils/add-linting.spec.ts +++ b/packages/react-native/src/utils/add-linting.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { readProjectConfiguration, Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { Linter } from '@nx/eslint'; diff --git a/packages/react/plugins/component-testing/index.ts b/packages/react/plugins/component-testing/index.ts index ac7ad6f292cc8..d43afb00a22c3 100644 --- a/packages/react/plugins/component-testing/index.ts +++ b/packages/react/plugins/component-testing/index.ts @@ -66,7 +66,7 @@ export function nxComponentTestingPreset( testingType: 'component', }); - if (global.NX_GRAPH_CREATION || global.NX_CYPRESS_INIT_GENERATOR_RUNNING) { + if (global.NX_GRAPH_CREATION) { // this is only used by plugins, so we don't need the component testing // options, cast to any to avoid type errors return basePresetSettings as any; diff --git a/packages/react/src/generators/application/application.legacy.spec.ts b/packages/react/src/generators/application/application.legacy.spec.ts index 5db0430df73fa..7f3701f655b84 100644 --- a/packages/react/src/generators/application/application.legacy.spec.ts +++ b/packages/react/src/generators/application/application.legacy.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { installedCypressVersion } from '@nx/cypress/src/utils/cypress-version'; import { getProjects, readProjectConfiguration, Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; diff --git a/packages/react/src/generators/application/application.spec.ts b/packages/react/src/generators/application/application.spec.ts index fcae904d1b303..b834227e75145 100644 --- a/packages/react/src/generators/application/application.spec.ts +++ b/packages/react/src/generators/application/application.spec.ts @@ -1,9 +1,10 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { installedCypressVersion } from '@nx/cypress/src/utils/cypress-version'; import { getProjects, readJson, readNxJson, - readProjectConfiguration, Tree, updateNxJson, } from '@nx/devkit'; diff --git a/packages/react/src/generators/component-cypress-spec/component-cypress-spec.spec.ts b/packages/react/src/generators/component-cypress-spec/component-cypress-spec.spec.ts index 42bb2ac866ebe..6307d4bec5191 100644 --- a/packages/react/src/generators/component-cypress-spec/component-cypress-spec.spec.ts +++ b/packages/react/src/generators/component-cypress-spec/component-cypress-spec.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { Linter } from '@nx/eslint'; diff --git a/packages/react/src/generators/component-story/component-story.spec.ts b/packages/react/src/generators/component-story/component-story.spec.ts index 4102c79ba6b82..3945b70569da5 100644 --- a/packages/react/src/generators/component-story/component-story.spec.ts +++ b/packages/react/src/generators/component-story/component-story.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { getProjects, Tree, updateProjectConfiguration } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import libraryGenerator from '../library/library'; diff --git a/packages/react/src/generators/component-test/component-test.spec.ts b/packages/react/src/generators/component-test/component-test.spec.ts index 4b5fa164ec71c..b6b64387a8aa3 100644 --- a/packages/react/src/generators/component-test/component-test.spec.ts +++ b/packages/react/src/generators/component-test/component-test.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { assertMinimumCypressVersion } from '@nx/cypress/src/utils/cypress-version'; import { Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; diff --git a/packages/react/src/generators/component/component.spec.ts b/packages/react/src/generators/component/component.spec.ts index b5d278cc48399..72c77fabb2f16 100644 --- a/packages/react/src/generators/component/component.spec.ts +++ b/packages/react/src/generators/component/component.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { installedCypressVersion } from '@nx/cypress/src/utils/cypress-version'; import { logger, diff --git a/packages/react/src/generators/cypress-component-configuration/cypress-component-configuration.spec.ts b/packages/react/src/generators/cypress-component-configuration/cypress-component-configuration.spec.ts index 92900a3adc18c..ded692ebb0699 100644 --- a/packages/react/src/generators/cypress-component-configuration/cypress-component-configuration.spec.ts +++ b/packages/react/src/generators/cypress-component-configuration/cypress-component-configuration.spec.ts @@ -7,11 +7,6 @@ import { updateProjectConfiguration, } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; -import { Linter } from '@nx/eslint'; -import { applicationGenerator } from '../application/application'; -import { componentGenerator } from '../component/component'; -import { libraryGenerator } from '../library/library'; -import { cypressComponentConfigGenerator } from './cypress-component-configuration'; let projectGraph: ProjectGraph; jest.mock('@nx/devkit', () => ({ @@ -21,6 +16,13 @@ jest.mock('@nx/devkit', () => ({ .fn() .mockImplementation(async () => projectGraph), })); + +import { Linter } from '@nx/eslint'; +import { applicationGenerator } from '../application/application'; +import { componentGenerator } from '../component/component'; +import { libraryGenerator } from '../library/library'; +import { cypressComponentConfigGenerator } from './cypress-component-configuration'; + jest.mock('@nx/cypress/src/utils/cypress-version'); // nested code imports graph from the repo, which might have innacurate graph version jest.mock('nx/src/project-graph/project-graph', () => ({ @@ -470,9 +472,9 @@ describe('React:CypressComponentTestConfiguration', () => { buildTarget: 'my-app:build', }); }).resolves; - expect( - require('@nx/devkit').createProjectGraphAsync - ).not.toHaveBeenCalled(); + expect(require('@nx/devkit').createProjectGraphAsync).toHaveBeenCalledTimes( + 1 + ); }); it('should setup cypress config files correctly', async () => { diff --git a/packages/react/src/generators/federate-module/federate-module.spec.ts b/packages/react/src/generators/federate-module/federate-module.spec.ts index 878719272998e..237f2de9a1253 100644 --- a/packages/react/src/generators/federate-module/federate-module.spec.ts +++ b/packages/react/src/generators/federate-module/federate-module.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { Tree, getProjects } from '@nx/devkit'; import { Schema } from './schema'; import { Schema as remoteSchma } from '../remote/schema'; diff --git a/packages/react/src/generators/hook/hook.spec.ts b/packages/react/src/generators/hook/hook.spec.ts index e5a5c3a6b7bd2..af732193a4ef3 100644 --- a/packages/react/src/generators/hook/hook.spec.ts +++ b/packages/react/src/generators/hook/hook.spec.ts @@ -1,5 +1,7 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { createApp, createLib } from '../../utils/testing-generators'; -import { logger, readJson, Tree } from '@nx/devkit'; +import { logger, Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { hookGenerator } from './hook'; diff --git a/packages/react/src/generators/library/library.spec.ts b/packages/react/src/generators/library/library.spec.ts index 3f29de13dc1c0..80de7cf2311d1 100644 --- a/packages/react/src/generators/library/library.spec.ts +++ b/packages/react/src/generators/library/library.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { installedCypressVersion } from '@nx/cypress/src/utils/cypress-version'; import { getProjects, diff --git a/packages/react/src/generators/redux/redux.spec.ts b/packages/react/src/generators/redux/redux.spec.ts index e8afcbfe8be88..65593e8c507a8 100644 --- a/packages/react/src/generators/redux/redux.spec.ts +++ b/packages/react/src/generators/redux/redux.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { readJson, Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { Linter } from '@nx/eslint'; diff --git a/packages/react/src/generators/remote/remote.spec.ts b/packages/react/src/generators/remote/remote.spec.ts index 51da2f98cbf63..7352126fb77b3 100644 --- a/packages/react/src/generators/remote/remote.spec.ts +++ b/packages/react/src/generators/remote/remote.spec.ts @@ -1,4 +1,5 @@ -import * as devkit from '@nx/devkit'; +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { ProjectGraph, readJson, readNxJson } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { Linter } from '@nx/eslint'; diff --git a/packages/react/src/generators/stories/stories.app.spec.ts b/packages/react/src/generators/stories/stories.app.spec.ts index eff11ed002c5b..75026ad3e8a74 100644 --- a/packages/react/src/generators/stories/stories.app.spec.ts +++ b/packages/react/src/generators/stories/stories.app.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { installedCypressVersion } from '@nx/cypress/src/utils/cypress-version'; import { Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; diff --git a/packages/react/src/generators/stories/stories.lib.spec.ts b/packages/react/src/generators/stories/stories.lib.spec.ts index ad89c17b7d962..e48d10a7a87d8 100644 --- a/packages/react/src/generators/stories/stories.lib.spec.ts +++ b/packages/react/src/generators/stories/stories.lib.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { Tree } from '@nx/devkit'; import storiesGenerator from './stories'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; diff --git a/packages/react/src/generators/stories/stories.nextjs.spec.ts b/packages/react/src/generators/stories/stories.nextjs.spec.ts index c152e3e2ea32b..bc54fe60a6170 100644 --- a/packages/react/src/generators/stories/stories.nextjs.spec.ts +++ b/packages/react/src/generators/stories/stories.nextjs.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { Tree } from '@nx/devkit'; import storiesGenerator from './stories'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; diff --git a/packages/react/src/generators/storybook-configuration/configuration.spec.ts b/packages/react/src/generators/storybook-configuration/configuration.spec.ts index 60c31572d1a11..62778e98203b5 100644 --- a/packages/react/src/generators/storybook-configuration/configuration.spec.ts +++ b/packages/react/src/generators/storybook-configuration/configuration.spec.ts @@ -27,10 +27,10 @@ describe('react:storybook-configuration', () => { mockedInstalledCypressVersion.mockReturnValue(10); jest.spyOn(logger, 'warn').mockImplementation(() => {}); jest.spyOn(logger, 'debug').mockImplementation(() => {}); - jest.resetModules(); }); afterEach(() => { + jest.resetModules(); jest.restoreAllMocks(); }); diff --git a/packages/remix/src/generators/action/action.impl.spec.ts b/packages/remix/src/generators/action/action.impl.spec.ts index 86ec128650d77..f2b9fe9820635 100644 --- a/packages/remix/src/generators/action/action.impl.spec.ts +++ b/packages/remix/src/generators/action/action.impl.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + jest.mock('../../utils/remix-config'); import * as remixConfigUtils from '../../utils/remix-config'; diff --git a/packages/remix/src/generators/application/application.impl.spec.ts b/packages/remix/src/generators/application/application.impl.spec.ts index 2fd13383e41b9..1e9d681ac9db7 100644 --- a/packages/remix/src/generators/application/application.impl.spec.ts +++ b/packages/remix/src/generators/application/application.impl.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import type { Tree } from '@nx/devkit'; import { joinPathFragments, readJson } from '@nx/devkit'; import { ProjectNameAndRootFormat } from '@nx/devkit/src/generators/project-name-and-root-utils'; diff --git a/packages/remix/src/generators/cypress-component-configuration/cypress-component-configuration.impl.spec.ts b/packages/remix/src/generators/cypress-component-configuration/cypress-component-configuration.impl.spec.ts index 06898fbec1b07..0ecf702ea4da3 100644 --- a/packages/remix/src/generators/cypress-component-configuration/cypress-component-configuration.impl.spec.ts +++ b/packages/remix/src/generators/cypress-component-configuration/cypress-component-configuration.impl.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { joinPathFragments, readProjectConfiguration } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import libraryGenerator from '../library/library.impl'; diff --git a/packages/remix/src/generators/init/init.spec.ts b/packages/remix/src/generators/init/init.spec.ts index 48fc5639d9bf1..92b66265770de 100644 --- a/packages/remix/src/generators/init/init.spec.ts +++ b/packages/remix/src/generators/init/init.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { readJson } from '@nx/devkit'; import initGenerator from './init'; diff --git a/packages/remix/src/generators/init/init.ts b/packages/remix/src/generators/init/init.ts index 6f4d4e5ec1679..80e7214b18b66 100644 --- a/packages/remix/src/generators/init/init.ts +++ b/packages/remix/src/generators/init/init.ts @@ -3,42 +3,18 @@ import { formatFiles, GeneratorCallback, readNxJson, - updateNxJson, addDependenciesToPackageJson, runTasksInSerial, + createProjectGraphAsync, } from '@nx/devkit'; -import { updatePackageScripts } from '@nx/devkit/src/utils/update-package-scripts'; +import { + addPlugin, + generateCombinations, +} from '@nx/devkit/src/utils/add-plugin'; import { createNodes } from '../../plugins/plugin'; import { nxVersion, remixVersion } from '../../utils/versions'; import { type Schema } from './schema'; -function addPlugin(tree) { - const nxJson = readNxJson(tree); - nxJson.plugins ??= []; - - for (const plugin of nxJson.plugins) { - if ( - typeof plugin === 'string' - ? plugin === '@nx/remix/plugin' - : plugin.plugin === '@nx/remix/plugin' - ) { - return; - } - } - - nxJson.plugins.push({ - plugin: '@nx/remix/plugin', - options: { - buildTargetName: 'build', - devTargetName: 'dev', - startTargetName: 'start', - typecheckTargetName: 'typecheck', - }, - }); - - updateNxJson(tree, nxJson); -} - export function remixInitGenerator(tree: Tree, options: Schema) { return remixInitGeneratorInternal(tree, { addPlugin: false, ...options }); } @@ -68,11 +44,23 @@ export async function remixInitGeneratorInternal(tree: Tree, options: Schema) { nxJson.useInferencePlugins !== false; options.addPlugin ??= addPluginDefault; if (options.addPlugin) { - addPlugin(tree); - } - - if (options.updatePackageScripts) { - await updatePackageScripts(tree, createNodes); + await addPlugin( + tree, + await createProjectGraphAsync(), + '@nx/remix/plugin', + createNodes, + { + startTargetName: ['start', 'remix:start', 'remix-start'], + buildTargetName: ['build', 'remix:build', 'remix-build'], + devTargetName: ['dev', 'remix:dev', 'remix-dev'], + typecheckTargetName: [ + 'typecheck', + 'remix:typecheck', + 'remix-typecheck', + ], + }, + options.updatePackageScripts + ); } if (!options.skipFormat) { diff --git a/packages/remix/src/generators/library/library.impl.spec.ts b/packages/remix/src/generators/library/library.impl.spec.ts index 3b0078947a952..0b95e8565e248 100644 --- a/packages/remix/src/generators/library/library.impl.spec.ts +++ b/packages/remix/src/generators/library/library.impl.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { readJson, readProjectConfiguration } from '@nx/devkit'; import { type ProjectNameAndRootFormat } from '@nx/devkit/src/generators/project-name-and-root-utils'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; diff --git a/packages/remix/src/generators/loader/loader.impl.spec.ts b/packages/remix/src/generators/loader/loader.impl.spec.ts index 6b90cc13ac367..21411926883ae 100644 --- a/packages/remix/src/generators/loader/loader.impl.spec.ts +++ b/packages/remix/src/generators/loader/loader.impl.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + jest.mock('../../utils/remix-config'); import * as remixConfigUtils from '../../utils/remix-config'; diff --git a/packages/remix/src/generators/meta/lib/v2.impl.spec.ts b/packages/remix/src/generators/meta/lib/v2.impl.spec.ts index 71cae49ec1518..c3decba551657 100644 --- a/packages/remix/src/generators/meta/lib/v2.impl.spec.ts +++ b/packages/remix/src/generators/meta/lib/v2.impl.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + jest.mock('../../../utils/remix-config'); import * as remixConfigUtils from '../../../utils/remix-config'; diff --git a/packages/remix/src/generators/meta/meta.impl.spec.ts b/packages/remix/src/generators/meta/meta.impl.spec.ts index e32b2fd551610..e24d10f8019fa 100644 --- a/packages/remix/src/generators/meta/meta.impl.spec.ts +++ b/packages/remix/src/generators/meta/meta.impl.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + jest.mock('../../utils/remix-config'); import * as remixConfigUtils from '../../utils/remix-config'; diff --git a/packages/remix/src/generators/resource-route/resource-route.impl.spec.ts b/packages/remix/src/generators/resource-route/resource-route.impl.spec.ts index 033c3b92f1a94..86a58b457b045 100644 --- a/packages/remix/src/generators/resource-route/resource-route.impl.spec.ts +++ b/packages/remix/src/generators/resource-route/resource-route.impl.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + jest.mock('../../utils/remix-config'); import * as remixConfigUtils from '../../utils/remix-config'; diff --git a/packages/remix/src/generators/route/route.impl.spec.ts b/packages/remix/src/generators/route/route.impl.spec.ts index 506ca3b138526..d3f9cbb61c548 100644 --- a/packages/remix/src/generators/route/route.impl.spec.ts +++ b/packages/remix/src/generators/route/route.impl.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + jest.mock('../../utils/remix-config'); import * as remixConfigUtils from '../../utils/remix-config'; import { Tree } from '@nx/devkit'; diff --git a/packages/remix/src/generators/setup-tailwind/setup-tailwind.impl.spec.ts b/packages/remix/src/generators/setup-tailwind/setup-tailwind.impl.spec.ts index 3b842f3209249..00833faa9b247 100644 --- a/packages/remix/src/generators/setup-tailwind/setup-tailwind.impl.spec.ts +++ b/packages/remix/src/generators/setup-tailwind/setup-tailwind.impl.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { readJson } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import applicationGenerator from '../application/application.impl'; diff --git a/packages/remix/src/generators/setup/setup.impl.spec.ts b/packages/remix/src/generators/setup/setup.impl.spec.ts index f94c9c3c0937e..6fa8bb4a9c169 100644 --- a/packages/remix/src/generators/setup/setup.impl.spec.ts +++ b/packages/remix/src/generators/setup/setup.impl.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import setupGenerator from './setup.impl'; diff --git a/packages/remix/src/generators/storybook-configuration/storybook-configuration.impl.spec.ts b/packages/remix/src/generators/storybook-configuration/storybook-configuration.impl.spec.ts index 1f7b0e1e0f644..39266366d8aad 100644 --- a/packages/remix/src/generators/storybook-configuration/storybook-configuration.impl.spec.ts +++ b/packages/remix/src/generators/storybook-configuration/storybook-configuration.impl.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import libraryGenerator from '../library/library.impl'; import storybookConfigurationGenerator from './storybook-configuration.impl'; diff --git a/packages/remix/src/generators/style/style.impl.spec.ts b/packages/remix/src/generators/style/style.impl.spec.ts index 6aec4aceddecf..d3a5e74d0f58a 100644 --- a/packages/remix/src/generators/style/style.impl.spec.ts +++ b/packages/remix/src/generators/style/style.impl.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + jest.mock('../../utils/remix-config'); import * as remixConfigUtils from '../../utils/remix-config'; import { Tree } from '@nx/devkit'; diff --git a/packages/rollup/src/generators/configuration/configuration.spec.ts b/packages/rollup/src/generators/configuration/configuration.spec.ts index fc70c47b374da..4f04fc2ae070f 100644 --- a/packages/rollup/src/generators/configuration/configuration.spec.ts +++ b/packages/rollup/src/generators/configuration/configuration.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { addProjectConfiguration, readJson, diff --git a/packages/rollup/src/generators/init/init.spec.ts b/packages/rollup/src/generators/init/init.spec.ts index 70658c5df0333..c01555d6892f8 100644 --- a/packages/rollup/src/generators/init/init.spec.ts +++ b/packages/rollup/src/generators/init/init.spec.ts @@ -1,13 +1,27 @@ -import { Tree, readJson } from '@nx/devkit'; +import 'nx/src/internal-testing-utils/mock-project-graph'; + +import { Tree, readJson, ProjectGraph } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { nxVersion } from '../../utils/versions'; import { rollupInitGenerator } from './init'; +let projectGraph: ProjectGraph; +jest.mock('@nx/devkit', () => ({ + ...jest.requireActual('@nx/devkit'), + createProjectGraphAsync: jest.fn().mockImplementation(async () => { + return projectGraph; + }), +})); + describe('rollupInitGenerator', () => { let tree: Tree; beforeEach(async () => { + projectGraph = { + nodes: {}, + dependencies: {}, + }; tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); }); diff --git a/packages/rollup/src/generators/init/init.ts b/packages/rollup/src/generators/init/init.ts index dda52be7c5352..59be1a26d7e3a 100644 --- a/packages/rollup/src/generators/init/init.ts +++ b/packages/rollup/src/generators/init/init.ts @@ -1,40 +1,15 @@ import { addDependenciesToPackageJson, + createProjectGraphAsync, formatFiles, GeneratorCallback, Tree, - readNxJson, - updateNxJson, } from '@nx/devkit'; import { nxVersion } from '../../utils/versions'; import { Schema } from './schema'; -import { updatePackageScripts } from '@nx/devkit/src/utils/update-package-scripts'; +import { addPlugin } from '@nx/devkit/src/utils/add-plugin'; import { createNodes } from '../../plugins/plugin'; -function addPlugin(tree: Tree) { - const nxJson = readNxJson(tree); - nxJson.plugins ??= []; - - for (const plugin of nxJson.plugins) { - if ( - typeof plugin === 'string' - ? plugin === '@nx/rollup/plugin' - : plugin.plugin === '@nx/rollup/plugin' - ) { - return; - } - } - - nxJson.plugins.push({ - plugin: '@nx/rollup/plugin', - options: { - buildTargetName: 'build', - }, - }); - - updateNxJson(tree, nxJson); -} - export async function rollupInitGenerator(tree: Tree, schema: Schema) { let task: GeneratorCallback = () => {}; @@ -50,11 +25,16 @@ export async function rollupInitGenerator(tree: Tree, schema: Schema) { schema.addPlugin ??= process.env.NX_ADD_PLUGINS !== 'false'; if (schema.addPlugin) { - addPlugin(tree); - } - - if (schema.updatePackageScripts) { - await updatePackageScripts(tree, createNodes); + await addPlugin( + tree, + await createProjectGraphAsync(), + '@nx/rollup/plugin', + createNodes, + { + buildTargetName: ['build', 'rollup:build', 'rollup-build'], + }, + schema.updatePackageScripts + ); } if (!schema.skipFormat) { diff --git a/packages/storybook/src/generators/init/init.spec.ts b/packages/storybook/src/generators/init/init.spec.ts index 3ddf5198e3767..36338752e5e42 100644 --- a/packages/storybook/src/generators/init/init.spec.ts +++ b/packages/storybook/src/generators/init/init.spec.ts @@ -1,11 +1,27 @@ -import { readJson, type NxJsonConfiguration, type Tree } from '@nx/devkit'; +import { + readJson, + type NxJsonConfiguration, + type Tree, + ProjectGraph, +} from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { initGenerator } from './init'; +let projectGraph: ProjectGraph; +jest.mock('@nx/devkit', () => ({ + ...jest.requireActual('@nx/devkit'), + createProjectGraphAsync: jest.fn().mockImplementation(async () => { + return projectGraph; + }), +})); describe('@nx/storybook:init', () => { let tree: Tree; beforeEach(() => { + projectGraph = { + nodes: {}, + dependencies: {}, + }; tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); }); diff --git a/packages/storybook/src/generators/init/init.ts b/packages/storybook/src/generators/init/init.ts index 7bedbaead4e32..bc754beb73d24 100644 --- a/packages/storybook/src/generators/init/init.ts +++ b/packages/storybook/src/generators/init/init.ts @@ -1,5 +1,6 @@ import { addDependenciesToPackageJson, + createProjectGraphAsync, formatFiles, GeneratorCallback, installPackagesTask, @@ -9,11 +10,10 @@ import { updateJson, updateNxJson, } from '@nx/devkit'; -import { updatePackageScripts } from '@nx/devkit/src/utils/update-package-scripts'; +import { addPlugin } from '@nx/devkit/src/utils/add-plugin'; import { gte } from 'semver'; import { createNodes } from '../../plugins/plugin'; import { - addPlugin, getInstalledStorybookVersion, storybookMajorVersion, } from '../../utils/utilities'; @@ -102,7 +102,37 @@ export async function initGeneratorInternal(tree: Tree, schema: Schema) { schema.addPlugin ??= addPluginDefault; if (schema.addPlugin) { - addPlugin(tree); + await addPlugin( + tree, + await createProjectGraphAsync(), + '@nx/storybook/plugin', + createNodes, + { + serveStorybookTargetName: [ + 'storybook', + 'serve:storybook', + 'serve-storybook', + 'storybook:serve', + 'storybook-serve', + ], + buildStorybookTargetName: [ + 'build-storybook', + 'build:storybook', + 'storybook:build', + ], + testStorybookTargetName: [ + 'test-storybook', + 'test:storybook', + 'storybook:test', + ], + staticStorybookTargetName: [ + 'static-storybook', + 'static:storybook', + 'storybook:static', + ], + }, + schema.updatePackageScripts + ); updateGitignore(tree); } else { addCacheableOperation(tree); @@ -114,10 +144,6 @@ export async function initGeneratorInternal(tree: Tree, schema: Schema) { tasks.push(checkDependenciesInstalled(tree, schema)); } - if (schema.updatePackageScripts) { - await updatePackageScripts(tree, createNodes); - } - if (!schema.skipFormat) { await formatFiles(tree); } diff --git a/packages/storybook/src/migrations/update-15-7-0/add-addon-essentials-to-all.spec.ts b/packages/storybook/src/migrations/update-15-7-0/add-addon-essentials-to-all.spec.ts index 01e5b27e8e45d..130b5d5740280 100644 --- a/packages/storybook/src/migrations/update-15-7-0/add-addon-essentials-to-all.spec.ts +++ b/packages/storybook/src/migrations/update-15-7-0/add-addon-essentials-to-all.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { addProjectConfiguration, ProjectConfiguration, diff --git a/packages/storybook/src/utils/utilities.ts b/packages/storybook/src/utils/utilities.ts index e44bbfa0a9183..5ddb355b515e7 100644 --- a/packages/storybook/src/utils/utilities.ts +++ b/packages/storybook/src/utils/utilities.ts @@ -275,29 +275,3 @@ export function pleaseUpgrade(): string { https://nx.dev/nx-api/storybook/generators/migrate-7 `; } - -export function addPlugin(tree: Tree) { - const nxJson = readNxJson(tree); - nxJson.plugins ??= []; - - for (const plugin of nxJson.plugins) { - if ( - typeof plugin === 'string' - ? plugin === '@nx/storybook/plugin' - : plugin.plugin === '@nx/storybook/plugin' - ) { - return; - } - } - - nxJson.plugins.push({ - plugin: '@nx/storybook/plugin', - options: { - buildStorybookTargetName: 'build-storybook', - serveStorybookTargetName: 'storybook', - testStorybookTargetName: 'test-storybook', - staticStorybookTargetName: 'static-storybook', - }, - }); - updateNxJson(tree, nxJson); -} diff --git a/packages/vite/src/generators/configuration/configuration.spec.ts b/packages/vite/src/generators/configuration/configuration.spec.ts index 88ffc7e045a94..8a84712bd80b9 100644 --- a/packages/vite/src/generators/configuration/configuration.spec.ts +++ b/packages/vite/src/generators/configuration/configuration.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { addDependenciesToPackageJson, readJson, Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { nxVersion } from '../../utils/versions'; diff --git a/packages/vite/src/generators/init/init.spec.ts b/packages/vite/src/generators/init/init.spec.ts index c9c03855f2caf..66e70f9d6db7e 100644 --- a/packages/vite/src/generators/init/init.spec.ts +++ b/packages/vite/src/generators/init/init.spec.ts @@ -1,6 +1,7 @@ import { addDependenciesToPackageJson, NxJsonConfiguration, + ProjectGraph, readJson, readNxJson, Tree, @@ -9,13 +10,25 @@ import { import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { nxVersion } from '../../utils/versions'; +let projectGraph: ProjectGraph; +jest.mock('@nx/devkit', () => ({ + ...jest.requireActual('@nx/devkit'), + createProjectGraphAsync: jest.fn().mockImplementation(async () => { + return projectGraph; + }), +})); + import { initGenerator } from './init'; describe('@nx/vite:init', () => { let tree: Tree; beforeEach(() => { - tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); + tree = createTreeWithEmptyWorkspace(); + projectGraph = { + nodes: {}, + dependencies: {}, + }; }); describe('dependencies for package.json', () => { diff --git a/packages/vite/src/generators/init/init.ts b/packages/vite/src/generators/init/init.ts index bd5637531e98c..5d7fd3d60267a 100644 --- a/packages/vite/src/generators/init/init.ts +++ b/packages/vite/src/generators/init/init.ts @@ -1,4 +1,5 @@ import { + createProjectGraphAsync, formatFiles, GeneratorCallback, readNxJson, @@ -6,15 +7,11 @@ import { Tree, updateNxJson, } from '@nx/devkit'; -import { updatePackageScripts } from '@nx/devkit/src/utils/update-package-scripts'; +import { addPlugin } from '@nx/devkit/src/utils/add-plugin'; import { createNodes } from '../../plugins/plugin'; import { InitGeneratorSchema } from './schema'; -import { - addPlugin, - checkDependenciesInstalled, - moveToDevDependencies, -} from './lib/utils'; +import { checkDependenciesInstalled, moveToDevDependencies } from './lib/utils'; export function updateNxJsonSettings(tree: Tree) { const nxJson = readNxJson(tree); @@ -61,8 +58,26 @@ export async function initGeneratorInternal( process.env.NX_ADD_PLUGINS !== 'false' && nxJson.useInferencePlugins !== false; schema.addPlugin ??= addPluginDefault; + if (schema.addPlugin) { - addPlugin(tree); + await addPlugin( + tree, + await createProjectGraphAsync(), + '@nx/vite/plugin', + createNodes, + { + buildTargetName: ['build', 'vite:build', 'vite-build'], + testTargetName: ['test', 'vite:test', 'vite-test'], + serveTargetName: ['serve', 'vite:serve', 'vite-serve'], + previewTargetName: ['preview', 'vite:preview', 'vite-preview'], + serveStaticTargetName: [ + 'serve-static', + 'vite:serve-static', + 'vite-serve-static', + ], + }, + schema.updatePackageScripts + ); } updateNxJsonSettings(tree); @@ -73,10 +88,6 @@ export async function initGeneratorInternal( tasks.push(checkDependenciesInstalled(tree, schema)); } - if (schema.updatePackageScripts) { - await updatePackageScripts(tree, createNodes); - } - if (!schema.skipFormat) { await formatFiles(tree); } diff --git a/packages/vite/src/generators/init/lib/utils.ts b/packages/vite/src/generators/init/lib/utils.ts index 6594c1c7ad9b0..9df4fd31a137c 100644 --- a/packages/vite/src/generators/init/lib/utils.ts +++ b/packages/vite/src/generators/init/lib/utils.ts @@ -61,30 +61,3 @@ export function createVitestConfig(tree: Tree) { updateNxJson(tree, nxJson); } - -export function addPlugin(tree: Tree) { - const nxJson = readNxJson(tree); - nxJson.plugins ??= []; - - for (const plugin of nxJson.plugins) { - if ( - typeof plugin === 'string' - ? plugin === '@nx/vite/plugin' - : plugin.plugin === '@nx/vite/plugin' - ) { - return; - } - } - - nxJson.plugins.push({ - plugin: '@nx/vite/plugin', - options: { - buildTargetName: 'build', - previewTargetName: 'preview', - testTargetName: 'test', - serveTargetName: 'serve', - serveStaticTargetName: 'serve-static', - }, - }); - updateNxJson(tree, nxJson); -} diff --git a/packages/vite/src/generators/init/schema.d.ts b/packages/vite/src/generators/init/schema.d.ts index 302469d4fc089..970386bd652fe 100644 --- a/packages/vite/src/generators/init/schema.d.ts +++ b/packages/vite/src/generators/init/schema.d.ts @@ -4,4 +4,5 @@ export interface InitGeneratorSchema { keepExistingVersions?: boolean; updatePackageScripts?: boolean; addPlugin?: boolean; + vitestOnly?: boolean; } diff --git a/packages/vite/src/generators/vitest/vitest.spec.ts b/packages/vite/src/generators/vitest/vitest.spec.ts index 6320e7e6bba54..01e0ada232945 100644 --- a/packages/vite/src/generators/vitest/vitest.spec.ts +++ b/packages/vite/src/generators/vitest/vitest.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { Tree } from '@nx/devkit'; diff --git a/packages/vue/src/generators/init/init.spec.ts b/packages/vue/src/generators/init/init.spec.ts index 7f612c4d61952..16c773a17cf24 100644 --- a/packages/vue/src/generators/init/init.spec.ts +++ b/packages/vue/src/generators/init/init.spec.ts @@ -1,11 +1,23 @@ -import { readJson, Tree } from '@nx/devkit'; +import { ProjectGraph, readJson, Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { vueInitGenerator } from './init'; +let projectGraph: ProjectGraph; +jest.mock('@nx/devkit', () => ({ + ...jest.requireActual('@nx/devkit'), + createProjectGraphAsync: jest.fn().mockImplementation(async () => { + return projectGraph; + }), +})); + describe('init', () => { let tree: Tree; beforeEach(() => { + projectGraph = { + nodes: {}, + dependencies: {}, + }; tree = createTreeWithEmptyWorkspace(); }); diff --git a/packages/web/src/generators/application/application.legacy.spec.ts b/packages/web/src/generators/application/application.legacy.spec.ts index 0af23aa933cc7..05fc18a328f0d 100644 --- a/packages/web/src/generators/application/application.legacy.spec.ts +++ b/packages/web/src/generators/application/application.legacy.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { installedCypressVersion } from '@nx/cypress/src/utils/cypress-version'; import { getProjects, readProjectConfiguration, Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; diff --git a/packages/web/src/generators/application/application.spec.ts b/packages/web/src/generators/application/application.spec.ts index 08d171ca720a5..260a06841151d 100644 --- a/packages/web/src/generators/application/application.spec.ts +++ b/packages/web/src/generators/application/application.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { installedCypressVersion } from '@nx/cypress/src/utils/cypress-version'; import { readProjectConfiguration, Tree } from '@nx/devkit'; import { getProjects, readJson } from '@nx/devkit'; diff --git a/packages/webpack/src/generators/configuration/configuration.spec.ts b/packages/webpack/src/generators/configuration/configuration.spec.ts index 32ead187f0c1e..ff7e9a2adee13 100644 --- a/packages/webpack/src/generators/configuration/configuration.spec.ts +++ b/packages/webpack/src/generators/configuration/configuration.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { addProjectConfiguration, Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; diff --git a/packages/webpack/src/generators/init/init.spec.ts b/packages/webpack/src/generators/init/init.spec.ts index 114f329136fb6..5b76da0a742ed 100644 --- a/packages/webpack/src/generators/init/init.spec.ts +++ b/packages/webpack/src/generators/init/init.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { readJson, Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; diff --git a/packages/webpack/src/generators/init/init.ts b/packages/webpack/src/generators/init/init.ts index 361fe52f39b3d..b991bf0efe32c 100644 --- a/packages/webpack/src/generators/init/init.ts +++ b/packages/webpack/src/generators/init/init.ts @@ -1,13 +1,13 @@ import { addDependenciesToPackageJson, + createProjectGraphAsync, formatFiles, GeneratorCallback, readNxJson, Tree, - updateNxJson, } from '@nx/devkit'; -import { updatePackageScripts } from '@nx/devkit/src/utils/update-package-scripts'; -import { createNodes, WebpackPluginOptions } from '../../plugins/plugin'; +import { addPlugin } from '@nx/devkit/src/utils/add-plugin'; +import { createNodes } from '../../plugins/plugin'; import { nxVersion, webpackCliVersion } from '../../utils/versions'; import { Schema } from './schema'; @@ -23,7 +23,36 @@ export async function webpackInitGeneratorInternal(tree: Tree, schema: Schema) { schema.addPlugin ??= addPluginDefault; if (schema.addPlugin) { - addPlugin(tree); + await addPlugin( + tree, + await createProjectGraphAsync(), + '@nx/webpack/plugin', + createNodes, + { + buildTargetName: [ + 'build', + 'webpack:build', + 'build:webpack', + 'webpack-build', + 'build-webpack', + ], + serveTargetName: [ + 'serve', + 'webpack:serve', + 'serve:webpack', + 'webpack-serve', + 'serve-webpack', + ], + previewTargetName: [ + 'preview', + 'webpack:preview', + 'preview:webpack', + 'webpack-preview', + 'preview-webpack', + ], + }, + schema.updatePackageScripts + ); } let installTask: GeneratorCallback = () => {}; @@ -46,10 +75,6 @@ export async function webpackInitGeneratorInternal(tree: Tree, schema: Schema) { ); } - if (schema.updatePackageScripts) { - await updatePackageScripts(tree, createNodes); - } - if (!schema.skipFormat) { await formatFiles(tree); } @@ -57,29 +82,4 @@ export async function webpackInitGeneratorInternal(tree: Tree, schema: Schema) { return installTask; } -function addPlugin(tree: Tree) { - const nxJson = readNxJson(tree); - nxJson.plugins ??= []; - - for (const plugin of nxJson.plugins) { - if ( - typeof plugin === 'string' - ? plugin === '@nx/webpack/plugin' - : plugin.plugin === '@nx/webpack/plugin' - ) { - return; - } - } - - nxJson.plugins.push({ - plugin: '@nx/webpack/plugin', - options: { - buildTargetName: 'build', - serveTargetName: 'serve', - previewTargetName: 'preview', - } as WebpackPluginOptions, - }); - updateNxJson(tree, nxJson); -} - export default webpackInitGenerator; diff --git a/packages/workspace/src/generators/convert-to-monorepo/convert-to-monorepo.spec.ts b/packages/workspace/src/generators/convert-to-monorepo/convert-to-monorepo.spec.ts index 0f1f5107a1f54..86468fd95cd3b 100644 --- a/packages/workspace/src/generators/convert-to-monorepo/convert-to-monorepo.spec.ts +++ b/packages/workspace/src/generators/convert-to-monorepo/convert-to-monorepo.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { readJson, readProjectConfiguration, Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { monorepoGenerator } from './convert-to-monorepo'; diff --git a/packages/workspace/src/generators/move/lib/check-destination.spec.ts b/packages/workspace/src/generators/move/lib/check-destination.spec.ts index 83fc4c4635aec..2eb9e7991f422 100644 --- a/packages/workspace/src/generators/move/lib/check-destination.spec.ts +++ b/packages/workspace/src/generators/move/lib/check-destination.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { ProjectConfiguration, readProjectConfiguration, diff --git a/packages/workspace/src/generators/move/lib/move-project-files.spec.ts b/packages/workspace/src/generators/move/lib/move-project-files.spec.ts index cd5eaeafe4471..b07564401cbda 100644 --- a/packages/workspace/src/generators/move/lib/move-project-files.spec.ts +++ b/packages/workspace/src/generators/move/lib/move-project-files.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { ProjectConfiguration, readProjectConfiguration, diff --git a/packages/workspace/src/generators/move/lib/update-cypress-config.spec.ts b/packages/workspace/src/generators/move/lib/update-cypress-config.spec.ts index b11a2f7a19654..ddeda61777804 100644 --- a/packages/workspace/src/generators/move/lib/update-cypress-config.spec.ts +++ b/packages/workspace/src/generators/move/lib/update-cypress-config.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { ProjectConfiguration, readJson, diff --git a/packages/workspace/src/generators/move/lib/update-eslint-config.spec.ts b/packages/workspace/src/generators/move/lib/update-eslint-config.spec.ts index 62cb232e94fc1..52da633bdd480 100644 --- a/packages/workspace/src/generators/move/lib/update-eslint-config.spec.ts +++ b/packages/workspace/src/generators/move/lib/update-eslint-config.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { joinPathFragments, offsetFromRoot, diff --git a/packages/workspace/src/generators/move/lib/update-imports.spec.ts b/packages/workspace/src/generators/move/lib/update-imports.spec.ts index ef5291c5efd11..49139aa146ebe 100644 --- a/packages/workspace/src/generators/move/lib/update-imports.spec.ts +++ b/packages/workspace/src/generators/move/lib/update-imports.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { readJson, readProjectConfiguration, diff --git a/packages/workspace/src/generators/move/lib/update-jest-config.spec.ts b/packages/workspace/src/generators/move/lib/update-jest-config.spec.ts index ea04c6875ea6c..6a256a6218b51 100644 --- a/packages/workspace/src/generators/move/lib/update-jest-config.spec.ts +++ b/packages/workspace/src/generators/move/lib/update-jest-config.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { readProjectConfiguration, Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { NormalizedSchema } from '../schema'; diff --git a/packages/workspace/src/generators/move/lib/update-package-json.spec.ts b/packages/workspace/src/generators/move/lib/update-package-json.spec.ts index 633a4ad656acb..7792ed41b12c8 100644 --- a/packages/workspace/src/generators/move/lib/update-package-json.spec.ts +++ b/packages/workspace/src/generators/move/lib/update-package-json.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { readJson, Tree, writeJson } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { NormalizedSchema } from '../schema'; diff --git a/packages/workspace/src/generators/move/lib/update-project-root-files.spec.ts b/packages/workspace/src/generators/move/lib/update-project-root-files.spec.ts index 92a14d78b628e..5faaf8293c01f 100644 --- a/packages/workspace/src/generators/move/lib/update-project-root-files.spec.ts +++ b/packages/workspace/src/generators/move/lib/update-project-root-files.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { readProjectConfiguration, Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { NormalizedSchema } from '../schema'; diff --git a/packages/workspace/src/generators/move/lib/update-readme.spec.ts b/packages/workspace/src/generators/move/lib/update-readme.spec.ts index 7ed7e9051f2ca..2860373686fc4 100644 --- a/packages/workspace/src/generators/move/lib/update-readme.spec.ts +++ b/packages/workspace/src/generators/move/lib/update-readme.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { join } from 'path'; diff --git a/packages/workspace/src/generators/move/lib/update-storybook-config.spec.ts b/packages/workspace/src/generators/move/lib/update-storybook-config.spec.ts index 1f528670bd503..1f295d7ff62fa 100644 --- a/packages/workspace/src/generators/move/lib/update-storybook-config.spec.ts +++ b/packages/workspace/src/generators/move/lib/update-storybook-config.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { readProjectConfiguration, Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { NormalizedSchema } from '../schema'; diff --git a/packages/workspace/src/generators/move/move.spec.ts b/packages/workspace/src/generators/move/move.spec.ts index ef0a9074632b8..5e7c07ebd454b 100644 --- a/packages/workspace/src/generators/move/move.spec.ts +++ b/packages/workspace/src/generators/move/move.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { readJson, readProjectConfiguration, diff --git a/packages/workspace/src/generators/preset/preset.spec.ts b/packages/workspace/src/generators/preset/preset.spec.ts index 6696c8d199c58..b9f7e2dd8bd67 100644 --- a/packages/workspace/src/generators/preset/preset.spec.ts +++ b/packages/workspace/src/generators/preset/preset.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { readProjectConfiguration, Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { presetGenerator } from './preset'; diff --git a/packages/workspace/src/generators/remove/lib/remove-project.spec.ts b/packages/workspace/src/generators/remove/lib/remove-project.spec.ts index a4ecbe2042cf4..349040d637c5f 100644 --- a/packages/workspace/src/generators/remove/lib/remove-project.spec.ts +++ b/packages/workspace/src/generators/remove/lib/remove-project.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { readProjectConfiguration, Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { Schema } from '../schema'; diff --git a/packages/workspace/src/generators/remove/lib/update-jest-config.spec.ts b/packages/workspace/src/generators/remove/lib/update-jest-config.spec.ts index 24a658fbaacde..bc018577684fe 100644 --- a/packages/workspace/src/generators/remove/lib/update-jest-config.spec.ts +++ b/packages/workspace/src/generators/remove/lib/update-jest-config.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { readProjectConfiguration, Tree } from '@nx/devkit'; import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; diff --git a/packages/workspace/src/generators/run-commands/run-commands.spec.ts b/packages/workspace/src/generators/run-commands/run-commands.spec.ts index 845eb5df9a1dc..55d2879898d64 100644 --- a/packages/workspace/src/generators/run-commands/run-commands.spec.ts +++ b/packages/workspace/src/generators/run-commands/run-commands.spec.ts @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import runCommands from './run-commands'; import { readProjectConfiguration } from 'nx/src/generators/utils/project-configuration'; 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 index 257557f92472c..1685f655103fe 100644 --- 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 @@ -1,3 +1,5 @@ +import 'nx/src/internal-testing-utils/mock-project-graph'; + import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; import { Tree,