From b377c96d99848f356721695a426b09717b584c6e Mon Sep 17 00:00:00 2001 From: Emily Xiong Date: Wed, 23 Apr 2025 13:13:25 -0400 Subject: [PATCH] feat(java): add gradle kotlin plugin (#29464) - [x] change init to create `createNodes` instead - [x] unit tests - [x] test-ci - [x] test on windows - [x] help metadata - [x] external nodes TODO: - add publish executor? - publish to maven central? ## Current Behavior currently, it uses [project report plugin](https://docs.gradle.org/current/userguide/project_report_plugin.html). - pro: no need to maintain this plugin - con: this plugin gives limited information ## Expected Behavior change the project report plugin to @nxn/gradle/plugin-v1 now the @nx/gradle plugin will use project graph plugin (dev.nx.gradle.project-graph) created in this pr. this plugin will create json file that is exactly what nx project grpah expected. ## Related Issue(s) Fixes # --- e2e/gradle/.gitattributes => .gitattributes | 0 .github/workflows/ci.yml | 6 + .gitignore | 5 +- .nx/workflows/agents.yaml | 14 + .prettierignore | 1 + build.gradle.kts | 6 + docs/generated/manifests/nx-api.json | 10 + docs/generated/packages-metadata.json | 10 + .../add-include-subprojects-tasks.json | 2 +- .../migrations/change-plugin-to-v1.json | 14 + docs/shared/tutorials/gradle.md | 4 +- e2e/gradle/gradle/libs.versions.toml | 2 - e2e/gradle/gradle/wrapper/gradle-wrapper.jar | Bin 43453 -> 0 bytes e2e/gradle/src/gradle-import.test.ts | 90 +- e2e/gradle/src/gradle-plugin-v1.test.ts | 177 ++++ e2e/gradle/src/gradle.test.ts | 27 +- e2e/gradle/src/utils/create-gradle-project.ts | 57 +- gradle.properties | 8 + gradle/libs.versions.toml | 11 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 43705 bytes .../wrapper/gradle-wrapper.properties | 5 +- e2e/gradle/gradlew => gradlew | 8 +- e2e/gradle/gradlew.bat => gradlew.bat | 22 +- package.json | 1 + packages/gradle/.eslintrc.json | 7 +- packages/gradle/executors.json | 3 + packages/gradle/migrations.json | 6 + packages/gradle/package.json | 4 +- packages/gradle/plugin-v1.spec.ts | 131 +++ packages/gradle/plugin-v1.ts | 2 + packages/gradle/plugin.spec.ts | 71 +- packages/gradle/plugin.ts | 2 +- packages/gradle/project-graph/.gitignore | 3 + packages/gradle/project-graph/README.md | 56 ++ .../gradle/project-graph/build.gradle.kts | 120 +++ packages/gradle/project-graph/project.json | 43 + .../gradle/project-graph/publish-maven.ts | 133 +++ .../gradle/project-graph/settings.gradle.kts | 16 + .../nx/gradle/NxProjectGraphReportPlugin.kt | 94 ++ .../dev/nx/gradle/NxProjectReportTask.kt | 63 ++ .../kotlin/dev/nx/gradle/data/Dependency.kt | 6 + .../dev/nx/gradle/data/ExternalDepData.kt | 10 + .../kotlin/dev/nx/gradle/data/ExternalNode.kt | 11 + .../dev/nx/gradle/data/GradleNodeReport.kt | 11 + .../dev/nx/gradle/data/GradleTargets.kt | 17 + .../kotlin/dev/nx/gradle/data/NodeMetadata.kt | 9 + .../kotlin/dev/nx/gradle/data/ProjectNode.kt | 10 + .../dev/nx/gradle/utils/CiTargetsUtils.kt | 143 +++ .../dev/nx/gradle/utils/ProjectUtils.kt | 159 ++++ .../kotlin/dev/nx/gradle/utils/TaskUtils.kt | 348 +++++++ .../nx/gradle/utils/projectDependencyUtils.kt | 30 + .../nx/gradle/utils/AddTestCiTargetsTest.kt | 81 ++ .../gradle/utils/CreateNodeForProjectTest.kt | 54 ++ .../nx/gradle/utils/ProcessTaskUtilsTest.kt | 96 ++ .../__snapshots__/generator.spec.ts.snap | 16 +- .../circleci/.circleci/config.yml.template | 2 +- .../__workflowFileName__.yml.template | 6 +- .../gradle/src/generators/init/init.spec.ts | 2 - packages/gradle/src/generators/init/init.ts | 95 +- .../19-4-0/add-project-report-all.ts | 84 +- .../20-2-0/add-include-subprojects-tasks.md | 6 +- .../20-2-0/add-include-subprojects-tasks.ts | 2 +- .../migrations/21-0-0/change-plugin-to-v1.md | 26 + .../21-0-0/change-plugin-to-v1.spec.ts | 57 ++ .../migrations/21-0-0/change-plugin-to-v1.ts | 25 + packages/gradle/src/plugin-v1/dependencies.ts | 96 ++ packages/gradle/src/plugin-v1/nodes.spec.ts | 587 ++++++++++++ packages/gradle/src/plugin-v1/nodes.ts | 435 +++++++++ .../gradle-composite-dependencies.txt | 0 .../__mocks__/gradle-custom-dependencies.txt | 0 .../utils/__mocks__/gradle-dependencies.txt | 0 .../gradle-project-report-println.txt | 20 +- .../utils/__mocks__/gradle-project-report.txt | 14 +- ...radle-properties-report-child-projects.txt | 0 ...le-properties-report-no-child-projects.txt | 0 .../utils/get-gradle-report.spec.ts | 76 +- .../utils/get-gradle-report.ts | 46 +- .../utils/get-project-report-lines.ts | 13 +- .../plugin/__snapshots__/nodes.spec.ts.snap | 849 +++++++++++++++++ packages/gradle/src/plugin/dependencies.ts | 137 ++- packages/gradle/src/plugin/nodes.spec.ts | 555 +---------- packages/gradle/src/plugin/nodes.ts | 388 +------- .../utils/__mocks__/gradle_composite.json | 38 + .../utils/__mocks__/gradle_nx_list.json | 590 ++++++++++++ .../utils/__mocks__/gradle_tutorial.json | 344 +++++++ .../get-project-graph-from-gradle-plugin.ts | 203 ++++ .../plugin/utils/get-project-graph-lines.ts | 90 ++ .../src/plugin/utils/gradle-plugin-options.ts | 13 + packages/gradle/src/utils/exec-gradle.spec.ts | 20 +- packages/gradle/src/utils/exec-gradle.ts | 16 +- .../gradle/src/utils/split-config-files.ts | 2 + packages/gradle/src/utils/versions.ts | 3 + pnpm-lock.yaml | 876 ++++++------------ settings.gradle.kts | 18 + 94 files changed, 6123 insertions(+), 1846 deletions(-) rename e2e/gradle/.gitattributes => .gitattributes (100%) create mode 100644 build.gradle.kts create mode 100644 docs/generated/packages/gradle/migrations/change-plugin-to-v1.json delete mode 100644 e2e/gradle/gradle/libs.versions.toml delete mode 100644 e2e/gradle/gradle/wrapper/gradle-wrapper.jar create mode 100644 e2e/gradle/src/gradle-plugin-v1.test.ts create mode 100644 gradle.properties create mode 100644 gradle/libs.versions.toml create mode 100644 gradle/wrapper/gradle-wrapper.jar rename {e2e/gradle/gradle => gradle}/wrapper/gradle-wrapper.properties (74%) rename e2e/gradle/gradlew => gradlew (95%) rename e2e/gradle/gradlew.bat => gradlew.bat (91%) create mode 100644 packages/gradle/executors.json create mode 100644 packages/gradle/plugin-v1.spec.ts create mode 100644 packages/gradle/plugin-v1.ts create mode 100644 packages/gradle/project-graph/.gitignore create mode 100644 packages/gradle/project-graph/README.md create mode 100644 packages/gradle/project-graph/build.gradle.kts create mode 100644 packages/gradle/project-graph/project.json create mode 100644 packages/gradle/project-graph/publish-maven.ts create mode 100644 packages/gradle/project-graph/settings.gradle.kts create mode 100644 packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/NxProjectGraphReportPlugin.kt create mode 100644 packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/NxProjectReportTask.kt create mode 100644 packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/data/Dependency.kt create mode 100644 packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/data/ExternalDepData.kt create mode 100644 packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/data/ExternalNode.kt create mode 100644 packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/data/GradleNodeReport.kt create mode 100644 packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/data/GradleTargets.kt create mode 100644 packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/data/NodeMetadata.kt create mode 100644 packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/data/ProjectNode.kt create mode 100644 packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/utils/CiTargetsUtils.kt create mode 100644 packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/utils/ProjectUtils.kt create mode 100644 packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/utils/TaskUtils.kt create mode 100644 packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/utils/projectDependencyUtils.kt create mode 100644 packages/gradle/project-graph/src/test/kotlin/dev/nx/gradle/utils/AddTestCiTargetsTest.kt create mode 100644 packages/gradle/project-graph/src/test/kotlin/dev/nx/gradle/utils/CreateNodeForProjectTest.kt create mode 100644 packages/gradle/project-graph/src/test/kotlin/dev/nx/gradle/utils/ProcessTaskUtilsTest.kt create mode 100644 packages/gradle/src/migrations/21-0-0/change-plugin-to-v1.md create mode 100644 packages/gradle/src/migrations/21-0-0/change-plugin-to-v1.spec.ts create mode 100644 packages/gradle/src/migrations/21-0-0/change-plugin-to-v1.ts create mode 100644 packages/gradle/src/plugin-v1/dependencies.ts create mode 100644 packages/gradle/src/plugin-v1/nodes.spec.ts create mode 100644 packages/gradle/src/plugin-v1/nodes.ts rename packages/gradle/src/{ => plugin-v1}/utils/__mocks__/gradle-composite-dependencies.txt (100%) rename packages/gradle/src/{ => plugin-v1}/utils/__mocks__/gradle-custom-dependencies.txt (100%) rename packages/gradle/src/{ => plugin-v1}/utils/__mocks__/gradle-dependencies.txt (100%) rename packages/gradle/src/{ => plugin-v1}/utils/__mocks__/gradle-project-report-println.txt (57%) rename packages/gradle/src/{ => plugin-v1}/utils/__mocks__/gradle-project-report.txt (67%) rename packages/gradle/src/{ => plugin-v1}/utils/__mocks__/gradle-properties-report-child-projects.txt (100%) rename packages/gradle/src/{ => plugin-v1}/utils/__mocks__/gradle-properties-report-no-child-projects.txt (100%) rename packages/gradle/src/{ => plugin-v1}/utils/get-gradle-report.spec.ts (65%) rename packages/gradle/src/{ => plugin-v1}/utils/get-gradle-report.ts (93%) rename packages/gradle/src/{ => plugin-v1}/utils/get-project-report-lines.ts (87%) create mode 100644 packages/gradle/src/plugin/__snapshots__/nodes.spec.ts.snap create mode 100644 packages/gradle/src/plugin/utils/__mocks__/gradle_composite.json create mode 100644 packages/gradle/src/plugin/utils/__mocks__/gradle_nx_list.json create mode 100644 packages/gradle/src/plugin/utils/__mocks__/gradle_tutorial.json create mode 100644 packages/gradle/src/plugin/utils/get-project-graph-from-gradle-plugin.ts create mode 100644 packages/gradle/src/plugin/utils/get-project-graph-lines.ts create mode 100644 packages/gradle/src/plugin/utils/gradle-plugin-options.ts create mode 100644 settings.gradle.kts diff --git a/e2e/gradle/.gitattributes b/.gitattributes similarity index 100% rename from e2e/gradle/.gitattributes rename to .gitattributes diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 431ee92031..6147ff77a8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,6 +65,12 @@ jobs: - name: Install Rust uses: dtolnay/rust-toolchain@stable + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: 21 + - name: Check Documentation run: pnpm nx documentation timeout-minutes: 20 diff --git a/.gitignore b/.gitignore index 43b39b1cf3..afff128d8d 100644 --- a/.gitignore +++ b/.gitignore @@ -67,5 +67,8 @@ target vite.config.*.timestamp* +storybook-static -storybook-static \ No newline at end of file +# Ignore Gradle project-specific cache directory +.gradle +.kotlin diff --git a/.nx/workflows/agents.yaml b/.nx/workflows/agents.yaml index 9d5abe7b71..95c493579a 100644 --- a/.nx/workflows/agents.yaml +++ b/.nx/workflows/agents.yaml @@ -64,6 +64,13 @@ launch-templates: - name: Load Cargo Env script: echo "PATH=$HOME/.cargo/bin:$PATH" >> $NX_CLOUD_ENV + - name: Setup Java 21 + script: | + sudo apt update + sudo apt install -y openjdk-21-jdk + sudo update-alternatives --set java /usr/lib/jvm/java-21-openjdk-amd64/bin/java + java -version + linux-extra-large: resource-class: 'docker_linux_amd64/extra_large' image: 'ubuntu22.04-node20.11-v10' @@ -128,3 +135,10 @@ launch-templates: - name: Load Cargo Env script: echo "PATH=$HOME/.cargo/bin:$PATH" >> $NX_CLOUD_ENV + + - name: Setup Java 21 + script: | + sudo apt update + sudo apt install -y openjdk-21-jdk + sudo update-alternatives --set java /usr/lib/jvm/java-21-openjdk-amd64/bin/java + java -version diff --git a/.prettierignore b/.prettierignore index ddb7730ed7..0f3bb1a9f9 100644 --- a/.prettierignore +++ b/.prettierignore @@ -13,6 +13,7 @@ packages/express/src/schematics/**/files/**/*.json packages/nest/src/schematics/**/files/**/*.json packages/react/src/schematics/**/files/**/*.json packages/jest/src/schematics/**/files/**/*.json +packages/gradle/project-graph/build/**/*.* packages/nx/src/plugins/js/lock-file/__fixtures__/**/*.* packages/**/schematics/**/files/**/*.html packages/**/generators/**/files/**/*.html diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000000..dbb3f11d9a --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,6 @@ +plugins { + id("dev.nx.gradle.project-graph") version("0.0.2") + id("com.ncorti.ktfmt.gradle") version("+") +} + +group = "dev.nx" \ No newline at end of file diff --git a/docs/generated/manifests/nx-api.json b/docs/generated/manifests/nx-api.json index b168167bae..ea3355e8b9 100644 --- a/docs/generated/manifests/nx-api.json +++ b/docs/generated/manifests/nx-api.json @@ -2325,6 +2325,16 @@ } }, "migrations": { + "/nx-api/gradle/migrations/change-plugin-to-v1": { + "description": "Change @nx/gradle plugin to version 1", + "file": "generated/packages/gradle/migrations/change-plugin-to-v1.json", + "hidden": false, + "name": "change-plugin-to-v1", + "version": "21.0.0-beta.5", + "originalFilePath": "/packages/gradle", + "path": "/nx-api/gradle/migrations/change-plugin-to-v1", + "type": "migration" + }, "/nx-api/gradle/migrations/add-include-subprojects-tasks": { "description": "Add includeSubprojectsTasks to build.gradle file", "file": "generated/packages/gradle/migrations/add-include-subprojects-tasks.json", diff --git a/docs/generated/packages-metadata.json b/docs/generated/packages-metadata.json index 2dcfbde7cd..c6743548cd 100644 --- a/docs/generated/packages-metadata.json +++ b/docs/generated/packages-metadata.json @@ -2309,6 +2309,16 @@ } ], "migrations": [ + { + "description": "Change @nx/gradle plugin to version 1", + "file": "generated/packages/gradle/migrations/change-plugin-to-v1.json", + "hidden": false, + "name": "change-plugin-to-v1", + "version": "21.0.0-beta.5", + "originalFilePath": "/packages/gradle", + "path": "gradle/migrations/change-plugin-to-v1", + "type": "migration" + }, { "description": "Add includeSubprojectsTasks to build.gradle file", "file": "generated/packages/gradle/migrations/add-include-subprojects-tasks.json", diff --git a/docs/generated/packages/gradle/migrations/add-include-subprojects-tasks.json b/docs/generated/packages/gradle/migrations/add-include-subprojects-tasks.json index b9aef994f0..b9acf7cfe7 100644 --- a/docs/generated/packages/gradle/migrations/add-include-subprojects-tasks.json +++ b/docs/generated/packages/gradle/migrations/add-include-subprojects-tasks.json @@ -10,5 +10,5 @@ "path": "/packages/gradle", "schema": null, "type": "migration", - "examplesFile": "#### Add includeSubprojectsTasks to build.gradle File\n\nAdd includeSubprojectsTasks to build.gradle file\n\n#### Sample Code Changes\n\nUpdate import paths for `withModuleFederation` and `withModuleFederationForSSR`.\n\n{% tabs %}\n{% tab label=\"Before\" %}\n\n```json {% fileName=\"nx.json\" %}\n{\n \"plugins\": [\"@nx/gradle\"]\n}\n```\n\n{% /tab %}\n{% tab label=\"After\" %}\n\n```json {% highlightLines=[5] fileName=\"nx.json\" %}\n{\n \"plugins\": [\n {\n \"options\": {\n \"includeSubprojectsTasks\": true\n },\n \"plugin\": \"@nx/gradle\"\n }\n ]\n}\n```\n\n{% /tab %}\n{% /tabs %}\n" + "examplesFile": "#### Add includeSubprojectsTasks to @nx/gradle Plugin Options\n\nAdd includeSubprojectsTasks to @nx/gradle plugin options in nx.json file\n\n#### Sample Code Changes\n\n{% tabs %}\n{% tab label=\"Before\" %}\n\n```json {% fileName=\"nx.json\" %}\n{\n \"plugins\": [\"@nx/gradle\"]\n}\n```\n\n{% /tab %}\n{% tab label=\"After\" %}\n\n```json {% highlightLines=[5] fileName=\"nx.json\" %}\n{\n \"plugins\": [\n {\n \"options\": {\n \"includeSubprojectsTasks\": true\n },\n \"plugin\": \"@nx/gradle\"\n }\n ]\n}\n```\n\n{% /tab %}\n{% /tabs %}\n" } diff --git a/docs/generated/packages/gradle/migrations/change-plugin-to-v1.json b/docs/generated/packages/gradle/migrations/change-plugin-to-v1.json new file mode 100644 index 0000000000..c2fa18b222 --- /dev/null +++ b/docs/generated/packages/gradle/migrations/change-plugin-to-v1.json @@ -0,0 +1,14 @@ +{ + "name": "change-plugin-to-v1", + "version": "21.0.0-beta.5", + "cli": "nx", + "description": "Change @nx/gradle plugin to version 1", + "factory": "./src/migrations/21-0-0/change-plugin-to-v1", + "implementation": "/packages/gradle/src/migrations/21-0-0/change-plugin-to-v1.ts", + "aliases": [], + "hidden": false, + "path": "/packages/gradle", + "schema": null, + "type": "migration", + "examplesFile": "#### Change @nx/gradle plugin to @nx/gradle/plugin-v1\n\nChange @nx/gradle plugin to version 1 in nx.json\n\n#### Sample Code Changes\n\n{% tabs %}\n{% tab label=\"Before\" %}\n\n```json {% fileName=\"nx.json\" %}\n{\n \"plugins\": [\"@nx/gradle\"]\n}\n```\n\n{% /tab %}\n{% tab label=\"After\" %}\n\n```json {% highlightLines=[5] fileName=\"nx.json\" %}\n{\n \"plugins\": [\"@nx/gradle/plugin-v1\"]\n}\n```\n\n{% /tab %}\n{% /tabs %}\n" +} diff --git a/docs/shared/tutorials/gradle.md b/docs/shared/tutorials/gradle.md index db6c275aef..a94e0619f8 100644 --- a/docs/shared/tutorials/gradle.md +++ b/docs/shared/tutorials/gradle.md @@ -375,10 +375,10 @@ jobs: # Uncomment this line to enable task distribution # - run: npx nx-cloud start-ci-run --distribute-on="3 linux-medium-jvm" --stop-agents-after="build" - - name: Set up JDK 17 for x64 + - name: Set up JDK 21 for x64 uses: actions/setup-java@v4 with: - java-version: '17' + java-version: '21' distribution: 'temurin' architecture: x64 diff --git a/e2e/gradle/gradle/libs.versions.toml b/e2e/gradle/gradle/libs.versions.toml deleted file mode 100644 index 4ac3234a6a..0000000000 --- a/e2e/gradle/gradle/libs.versions.toml +++ /dev/null @@ -1,2 +0,0 @@ -# This file was generated by the Gradle 'init' task. -# https://docs.gradle.org/current/userguide/platforms.html#sub::toml-dependencies-format diff --git a/e2e/gradle/gradle/wrapper/gradle-wrapper.jar b/e2e/gradle/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index e6441136f3d4ba8a0da8d277868979cfbc8ad796..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43453 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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
NnX)EH+Nua)3Y(c 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 { - let proj: string; const tempImportE2ERoot = join(e2eCwd, 'nx-import'); beforeAll(() => { - proj = newProject({ + newProject({ packages: ['@nx/js'], }); @@ -66,30 +65,7 @@ describe('Nx Import Gradle', () => { 'gradleProjectKotlin', 'kotlin-' ); - // Add project.json files to the gradle project to avoid duplicate project names - createFileSync(join(tempGraldeProjectPath, 'project.json')); - writeFileSync( - join(tempGraldeProjectPath, 'project.json'), - `{"name": "${tempGradleProjectName}"}` - ); - - execSync(`git init`, { - cwd: tempGraldeProjectPath, - }); - execSync(`git add .`, { - cwd: tempGraldeProjectPath, - }); - execSync(`git commit -am "initial commit"`, { - cwd: tempGraldeProjectPath, - }); - - try { - execSync(`git checkout -b main`, { - cwd: tempGraldeProjectPath, - }); - } catch { - // This fails if git is already configured to have `main` branch, but that's OK - } + setupGradleProjectGit(tempGraldeProjectPath, tempGradleProjectName); const remote = tempGraldeProjectPath; const ref = 'main'; @@ -140,30 +116,7 @@ describe('Nx Import Gradle', () => { 'gradleProjectGroovy', 'groovy-' ); - // Add project.json files to the gradle project to avoid duplicate project names - createFileSync(join(tempGraldeProjectPath, 'project.json')); - writeFileSync( - join(tempGraldeProjectPath, 'project.json'), - `{"name": "${tempGradleProjectName}"}` - ); - - execSync(`git init`, { - cwd: tempGraldeProjectPath, - }); - execSync(`git add .`, { - cwd: tempGraldeProjectPath, - }); - execSync(`git commit -am "initial commit"`, { - cwd: tempGraldeProjectPath, - }); - - try { - execSync(`git checkout -b main`, { - cwd: tempGraldeProjectPath, - }); - } catch { - // This fails if git is already configured to have `main` branch, but that's OK - } + setupGradleProjectGit(tempGraldeProjectPath, tempGradleProjectName); const remote = tempGraldeProjectPath; const ref = 'main'; @@ -199,3 +152,40 @@ describe('Nx Import Gradle', () => { runCommand(`git commit -am 'import groovy project'`); }); }); + +function setupGradleProjectGit( + tempGraldeProjectPath: string, + tempGradleProjectName: string +) { + // Add project.json files to the gradle project to avoid duplicate project names + createFileSync(join(tempGraldeProjectPath, 'project.json')); + writeFileSync( + join(tempGraldeProjectPath, 'project.json'), + `{"name": "${tempGradleProjectName}"}` + ); + + execSync(`./gradlew --stop`, { + cwd: tempGraldeProjectPath, + }); + execSync(`./gradlew clean`, { + cwd: tempGraldeProjectPath, + }); + + execSync(`git init`, { + cwd: tempGraldeProjectPath, + }); + execSync(`git add .`, { + cwd: tempGraldeProjectPath, + }); + execSync(`git commit -am "initial commit"`, { + cwd: tempGraldeProjectPath, + }); + + try { + execSync(`git checkout -b main`, { + cwd: tempGraldeProjectPath, + }); + } catch { + // This fails if git is already configured to have `main` branch, but that's OK + } +} diff --git a/e2e/gradle/src/gradle-plugin-v1.test.ts b/e2e/gradle/src/gradle-plugin-v1.test.ts new file mode 100644 index 0000000000..e17a34074e --- /dev/null +++ b/e2e/gradle/src/gradle-plugin-v1.test.ts @@ -0,0 +1,177 @@ +import { + checkFilesExist, + cleanupProject, + createFile, + fileExists, + newProject, + readFile, + runCLI, + uniq, + updateFile, + updateJson, +} from '@nx/e2e/utils'; +import { basename, dirname, join } from 'path'; + +import { createGradleProject } from './utils/create-gradle-project'; + +describe('Gradle Plugin V1', () => { + describe.each([{ type: 'kotlin' }, { type: 'groovy' }])( + '$type', + ({ type }: { type: 'kotlin' | 'groovy' }) => { + let gradleProjectName = uniq('my-gradle-project'); + beforeAll(() => { + newProject(); + createGradleProject(gradleProjectName, type); + runCLI(`add @nx/gradle`); + updateJson('nx.json', (json) => { + json.plugins.find((p) => p.plugin === '@nx/gradle').plugin = + '@nx/gradle/plugin-v1'; + return json; + }); + addProjectReportToBuildGradle( + `settings.gradle${type === 'kotlin' ? '.kts' : ''}` + ); + }); + afterAll(() => cleanupProject()); + + it('should build', () => { + const projects = runCLI(`show projects`); + expect(projects).toContain('app'); + expect(projects).toContain('list'); + expect(projects).toContain('utilities'); + expect(projects).toContain(gradleProjectName); + + const buildOutput = runCLI('build app', { verbose: true }); + expect(buildOutput).toContain('nx run list:build'); + expect(buildOutput).toContain(':list:classes'); + expect(buildOutput).toContain('nx run utilities:build'); + expect(buildOutput).toContain(':utilities:classes'); + + checkFilesExist( + `app/build/libs/app.jar`, + `list/build/libs/list.jar`, + `utilities/build/libs/utilities.jar` + ); + }); + + it('should track dependencies for new app', () => { + if (type === 'groovy') { + createFile( + `app2/build.gradle`, + `plugins { + id 'buildlogic.groovy-application-conventions' +} + +dependencies { + implementation project(':app') +}` + ); + } else { + createFile( + `app2/build.gradle.kts`, + `plugins { + id("buildlogic.kotlin-application-conventions") +} + +dependencies { + implementation(project(":app")) +}` + ); + updateFile(`app/build.gradle.kts`, (content) => { + content += `\r\ntasks.register("task1"){ + println("REGISTER TASK1: This is executed during the configuration phase") + }`; + return content; + }); + } + updateFile( + `settings.gradle${type === 'kotlin' ? '.kts' : ''}`, + (content) => { + content += `\r\ninclude("app2")`; + return content; + } + ); + + let buildOutput = runCLI('build app2', { verbose: true }); + // app2 depends on app + expect(buildOutput).toContain('nx run app:build'); + expect(buildOutput).toContain(':app:classes'); + expect(buildOutput).toContain('nx run list:build'); + expect(buildOutput).toContain(':list:classes'); + expect(buildOutput).toContain('nx run utilities:build'); + expect(buildOutput).toContain(':utilities:classes'); + + checkFilesExist( + `app2/build/libs/app2.jar`, + `app/build/libs/app.jar`, + `list/build/libs/list.jar`, + `utilities/build/libs/utilities.jar` + ); + }); + + it('should run atomized test target', () => { + updateJson('nx.json', (json) => { + json.plugins.find((p) => p.plugin === '@nx/gradle/plugin-v1').options[ + 'ciTargetName' + ] = 'test-ci'; + return json; + }); + + expect(() => { + runCLI('run app:test-ci--MessageUtilsTest', { verbose: true }); + runCLI('run list:test-ci--LinkedListTest', { verbose: true }); + }).not.toThrow(); + }); + } + ); +}); + +function addProjectReportToBuildGradle(settingsGradleFile: string) { + const filename = basename(settingsGradleFile); + let gradleFilePath = 'build.gradle'; + if (filename.endsWith('.kts')) { + gradleFilePath = 'build.gradle.kts'; + } + gradleFilePath = join(dirname(settingsGradleFile), gradleFilePath); + let buildGradleContent = ''; + if (!fileExists(gradleFilePath)) { + createFile(gradleFilePath, buildGradleContent); // create a build.gradle file near settings.gradle file if it does not exist + } else { + buildGradleContent = readFile(gradleFilePath).toString(); + } + + buildGradleContent += `\n\rallprojects { + apply { + plugin("project-report") + } +}`; + + if (gradleFilePath.endsWith('.kts')) { + buildGradleContent += `\n\rtasks.register("projectReportAll") { + // All project reports of subprojects + allprojects.forEach { + dependsOn(it.tasks.get("projectReport")) + } + + // All projectReportAll of included builds + gradle.includedBuilds.forEach { + dependsOn(it.task(":projectReportAll")) + } +}`; + } else { + buildGradleContent += `\n\rtasks.register("projectReportAll") { + // All project reports of subprojects + allprojects.forEach { + dependsOn(it.tasks.getAt("projectReport")) + } + + // All projectReportAll of included builds + gradle.includedBuilds.forEach { + dependsOn(it.task(":projectReportAll")) + } + }`; + } + if (buildGradleContent) { + updateFile(gradleFilePath, buildGradleContent); + } +} diff --git a/e2e/gradle/src/gradle.test.ts b/e2e/gradle/src/gradle.test.ts index 856f77b43c..44814f3779 100644 --- a/e2e/gradle/src/gradle.test.ts +++ b/e2e/gradle/src/gradle.test.ts @@ -6,6 +6,7 @@ import { runCLI, uniq, updateFile, + updateJson, } from '@nx/e2e/utils'; import { createGradleProject } from './utils/create-gradle-project'; @@ -30,9 +31,9 @@ describe('Gradle', () => { expect(projects).toContain(gradleProjectName); const buildOutput = runCLI('build app', { verbose: true }); - expect(buildOutput).toContain('nx run list:build'); + expect(buildOutput).toContain('nx run list:'); expect(buildOutput).toContain(':list:classes'); - expect(buildOutput).toContain('nx run utilities:build'); + expect(buildOutput).toContain('nx run utilities:'); expect(buildOutput).toContain(':utilities:classes'); checkFilesExist( @@ -82,8 +83,28 @@ dependencies { let buildOutput = runCLI('build app2', { verbose: true }); // app2 depends on app - expect(buildOutput).toContain('nx run app:build'); + expect(buildOutput).toContain('nx run app:'); expect(buildOutput).toContain(':app:classes'); + expect(buildOutput).toContain('nx run list:'); + expect(buildOutput).toContain(':list:classes'); + expect(buildOutput).toContain('nx run utilities:'); + expect(buildOutput).toContain(':utilities:classes'); + + checkFilesExist(`app2/build/libs/app2.jar`); + }); + + it('should run atomized test target', () => { + updateJson('nx.json', (json) => { + json.plugins.find((p) => p.plugin === '@nx/gradle').options[ + 'ciTargetName' + ] = 'test-ci'; + return json; + }); + + expect(() => { + runCLI('run app:test-ci--MessageUtilsTest', { verbose: true }); + runCLI('run list:test-ci--LinkedListTest', { verbose: true }); + }).not.toThrow(); }); } ); diff --git a/e2e/gradle/src/utils/create-gradle-project.ts b/e2e/gradle/src/utils/create-gradle-project.ts index 1e4755082e..85292a04a1 100644 --- a/e2e/gradle/src/utils/create-gradle-project.ts +++ b/e2e/gradle/src/utils/create-gradle-project.ts @@ -5,6 +5,7 @@ import { tmpProjPath, } from '@nx/e2e/utils'; import { execSync } from 'child_process'; +import { readFileSync } from 'fs'; import { createFileSync, writeFileSync } from 'fs-extra'; import { join, resolve } from 'path'; @@ -15,14 +16,10 @@ export function createGradleProject( packageName: string = 'gradleProject', addProjectJsonNamePrefix: string = '' ) { - e2eConsoleLogger( - `Using java version: ${execSync('java -version')} ${execSync( - 'echo $JAVA_HOME' - )}` - ); + e2eConsoleLogger(`Using java version: ${execSync('java -version')}`); const gradleCommand = isWindows() - ? resolve(`${__dirname}/../../gradlew.bat`) - : resolve(`${__dirname}/../../gradlew`); + ? resolve(`${__dirname}/../../../../gradlew.bat`) + : resolve(`${__dirname}/../../../../gradlew`); e2eConsoleLogger( 'Using gradle version: ' + execSync(`${gradleCommand} --version`, { @@ -36,13 +33,26 @@ export function createGradleProject( ); e2eConsoleLogger( runCommand( - `${gradleCommand} init --type ${type}-application --dsl ${type} --project-name ${projectName} --package ${packageName} --no-incubating --split-project`, + `${gradleCommand} init --type ${type}-application --dsl ${type} --project-name ${projectName} --package ${packageName} --no-incubating --split-project --overwrite`, { cwd, } ) ); + try { + e2eConsoleLogger( + runCommand(`${gradleCommand} --stop`, { + cwd, + }) + ); + e2eConsoleLogger( + runCommand(`${gradleCommand} clean`, { + cwd, + }) + ); + } catch (e) {} + if (addProjectJsonNamePrefix) { createFileSync(join(cwd, 'app/project.json')); writeFileSync( @@ -60,4 +70,35 @@ export function createGradleProject( `{"name": "${addProjectJsonNamePrefix}utilities"}` ); } + + addLocalPluginManagement( + join(cwd, `settings.gradle${type === 'kotlin' ? '.kts' : ''}`) + ); + addLocalPluginManagement( + join(cwd, `buildSrc/settings.gradle${type === 'kotlin' ? '.kts' : ''}`) + ); + + e2eConsoleLogger( + execSync( + `${gradleCommand} :project-graph:publishToMavenLocal -x :project-graph:signNxProjectGraphPluginPluginMarkerMavenPublication -x :project-graph:signPluginMavenPublication -x :project-graph:publishNxProjectGraphPluginPluginMarkerMavenPublicationToMavenLocal -x :project-graph:publishPluginMavenPublicationToMavenLocal`, + { + cwd: `${__dirname}/../../../..`, + } + ).toString() + ); +} + +function addLocalPluginManagement(filePath: string) { + let content = readFileSync(filePath).toString(); + content = + `pluginManagement { + repositories { + mavenLocal() + gradlePluginPortal() + mavenCentral() + // Add other repositories if needed + } +} +` + content; + writeFileSync(filePath, content); } diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000000..494717139a --- /dev/null +++ b/gradle.properties @@ -0,0 +1,8 @@ +# This file was generated by the Gradle 'init' task. +# https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_configuration_properties + +org.gradle.parallel=true +org.gradle.caching=true +# disable the configuration cache for this project https://docs.gradle.org/current/userguide/configuration_cache.html#config_cache:requirements:disallowed_types +# nxProjectGraph is not supported by the configuration cache +org.gradle.configuration-cache=false \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000000..3b788e62d4 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,11 @@ +# This file was generated by the Gradle 'init' task. +# https://docs.gradle.org/current/userguide/platforms.html#sub::toml-dependencies-format + +[plugins] +jvm = { id = "org.jetbrains.kotlin.jvm", version = "1.9.20" } + +[versions] +kotlin-gradle-plugin = "2.0.21" + +[libraries] +kotlin-gradle-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin-gradle-plugin" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..9bbc975c742b298b441bfb90dbc124400a3751b9 GIT binary patch literal 43705 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 DHx0+F literal 0 HcmV?d00001 diff --git a/e2e/gradle/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties similarity index 74% rename from e2e/gradle/gradle/wrapper/gradle-wrapper.properties rename to gradle/wrapper/gradle-wrapper.properties index a0777a32ce..37f853b1c8 100644 --- a/e2e/gradle/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip -validateDistributionUrl=false +distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/e2e/gradle/gradlew b/gradlew similarity index 95% rename from e2e/gradle/gradlew rename to gradlew index 1aa94a4269..faf93008b7 100755 --- a/e2e/gradle/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -84,7 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -203,7 +205,7 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. diff --git a/e2e/gradle/gradlew.bat b/gradlew.bat similarity index 91% rename from e2e/gradle/gradlew.bat rename to gradlew.bat index 93e3f59f13..9d21a21834 100644 --- a/e2e/gradle/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -43,11 +45,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail diff --git a/package.json b/package.json index 732174f9ad..598f3e49e3 100644 --- a/package.json +++ b/package.json @@ -369,6 +369,7 @@ "core-js": "3.36.1", "enquirer": "~2.3.6", "fast-glob": "3.3.3", + "form-data": "^4.0.2", "framer-motion": "^11.3.0", "front-matter": "^4.0.2", "glob": "7.1.4", diff --git a/packages/gradle/.eslintrc.json b/packages/gradle/.eslintrc.json index 52b3d2c335..b6e9ee1523 100644 --- a/packages/gradle/.eslintrc.json +++ b/packages/gradle/.eslintrc.json @@ -27,7 +27,12 @@ } }, { - "files": ["./package.json"], + "files": [ + "./package.json", + "./generators.json", + "./executors.json", + "./migrations.json" + ], "parser": "jsonc-eslint-parser", "rules": { "@nx/nx-plugin-checks": "error" diff --git a/packages/gradle/executors.json b/packages/gradle/executors.json new file mode 100644 index 0000000000..3a64718e93 --- /dev/null +++ b/packages/gradle/executors.json @@ -0,0 +1,3 @@ +{ + "executors": {} +} diff --git a/packages/gradle/migrations.json b/packages/gradle/migrations.json index 1dc2c58227..5088bd5347 100644 --- a/packages/gradle/migrations.json +++ b/packages/gradle/migrations.json @@ -17,6 +17,12 @@ "cli": "nx", "description": "Add includeSubprojectsTasks to build.gradle file", "factory": "./src/migrations/20-2-0/add-include-subprojects-tasks" + }, + "change-plugin-to-v1": { + "version": "21.0.0-beta.5", + "cli": "nx", + "description": "Change @nx/gradle plugin to version 1", + "factory": "./src/migrations/21-0-0/change-plugin-to-v1" } }, "packageJsonUpdates": {} diff --git a/packages/gradle/package.json b/packages/gradle/package.json index 14f5ebf31c..3ea30bcc01 100644 --- a/packages/gradle/package.json +++ b/packages/gradle/package.json @@ -26,6 +26,7 @@ "generators": "./generators.json", "exports": { ".": "./index.js", + "./plugin-v1": "./plugin-v1.js", "./package.json": "./package.json", "./migrations.json": "./migrations.json", "./generators.json": "./generators.json" @@ -38,5 +39,6 @@ }, "publishConfig": { "access": "public" - } + }, + "executors": "./executors.json" } diff --git a/packages/gradle/plugin-v1.spec.ts b/packages/gradle/plugin-v1.spec.ts new file mode 100644 index 0000000000..c82b9123ea --- /dev/null +++ b/packages/gradle/plugin-v1.spec.ts @@ -0,0 +1,131 @@ +import { CreateNodesContext } from '@nx/devkit'; +import { TempFs } from '@nx/devkit/internal-testing-utils'; +import { createNodesV2 } from './plugin-v1'; +import { type GradleReport } from './src/plugin-v1/utils/get-gradle-report'; + +let gradleReport: GradleReport; +jest.mock('./src/plugin-v1/utils/get-gradle-report', () => { + return { + GRADLE_BUILD_FILES: new Set(['build.gradle', 'build.gradle.kts']), + populateGradleReport: jest.fn().mockImplementation(() => void 0), + getCurrentGradleReport: jest.fn().mockImplementation(() => gradleReport), + }; +}); + +describe('@nx/gradle/plugin-v1', () => { + let createNodesFunction = createNodesV2[1]; + let context: CreateNodesContext; + let tempFs: TempFs; + + beforeEach(async () => { + tempFs = new TempFs('gradle-plugin'); + gradleReport = { + gradleFileToGradleProjectMap: new Map([ + ['proj/build.gradle', 'proj'], + ]), + gradleProjectToDepsMap: new Map>(), + gradleFileToOutputDirsMap: new Map>([ + ['proj/build.gradle', new Map([['build', 'build']])], + ]), + gradleProjectToTasksMap: new Map>([ + ['proj', new Set(['test'])], + ]), + gradleProjectToTasksTypeMap: new Map>([ + ['proj', new Map([['test', 'Verification']])], + ]), + gradleProjectToProjectName: new Map([['proj', 'proj']]), + gradleProjectNameToProjectRootMap: new Map([ + ['proj', 'proj'], + ]), + gradleProjectToChildProjects: new Map(), + }; + context = { + nxJsonConfiguration: { + namedInputs: { + default: ['{projectRoot}/**/*'], + production: ['!{projectRoot}/**/*.spec.ts'], + }, + }, + workspaceRoot: tempFs.tempDir, + configFiles: [], + }; + tempFs.createFileSync('package.json', JSON.stringify({ name: 'repo' })); + tempFs.createFileSync( + 'my-app/project.json', + JSON.stringify({ name: 'my-app' }) + ); + }); + + afterEach(() => { + jest.resetModules(); + tempFs.cleanup(); + tempFs = null; + }); + + it('should create nodes', async () => { + tempFs.createFileSync('gradlew', ''); + + const nodes = await createNodesFunction( + ['gradlew', 'proj/build.gradle'], + undefined, + context + ); + + expect(nodes).toMatchInlineSnapshot(` + [ + [ + "proj/build.gradle", + { + "projects": { + "proj": { + "metadata": { + "targetGroups": { + "Verification": [ + "test", + ], + }, + "technologies": [ + "gradle", + ], + }, + "name": "proj", + "projectType": "application", + "targets": { + "test": { + "cache": true, + "command": "./gradlew proj:test", + "dependsOn": [ + "testClasses", + ], + "inputs": [ + "default", + "^production", + ], + "metadata": { + "help": { + "command": "./gradlew help --task proj:test", + "example": { + "options": { + "args": [ + "--rerun", + ], + }, + }, + }, + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": ".", + }, + }, + }, + }, + }, + }, + ], + ] + `); + }); +}); diff --git a/packages/gradle/plugin-v1.ts b/packages/gradle/plugin-v1.ts new file mode 100644 index 0000000000..35195059db --- /dev/null +++ b/packages/gradle/plugin-v1.ts @@ -0,0 +1,2 @@ +export { createDependencies } from './src/plugin-v1/dependencies'; +export { createNodes, createNodesV2 } from './src/plugin-v1/nodes'; diff --git a/packages/gradle/plugin.spec.ts b/packages/gradle/plugin.spec.ts index 4d9108e34f..5306d56eff 100644 --- a/packages/gradle/plugin.spec.ts +++ b/packages/gradle/plugin.spec.ts @@ -1,14 +1,17 @@ -import { CreateNodesContext } from '@nx/devkit'; +import { CreateNodesContext, readJsonFile } from '@nx/devkit'; import { TempFs } from '@nx/devkit/internal-testing-utils'; import { createNodesV2 } from './plugin'; -import { type GradleReport } from './src/utils/get-gradle-report'; +import { type ProjectGraphReport } from './src/plugin/utils/get-project-graph-from-gradle-plugin'; +import { join } from 'path'; -let gradleReport: GradleReport; -jest.mock('./src/utils/get-gradle-report', () => { +let gradleReport: ProjectGraphReport; +jest.mock('./src/plugin/utils/get-project-graph-from-gradle-plugin', () => { return { GRADLE_BUILD_FILES: new Set(['build.gradle', 'build.gradle.kts']), - populateGradleReport: jest.fn().mockImplementation(() => void 0), - getCurrentGradleReport: jest.fn().mockImplementation(() => gradleReport), + populateProjectGraph: jest.fn().mockImplementation(() => void 0), + getCurrentProjectGraphReport: jest + .fn() + .mockImplementation(() => gradleReport), }; }); @@ -19,26 +22,9 @@ describe('@nx/gradle/plugin', () => { beforeEach(async () => { tempFs = new TempFs('gradle-plugin'); - gradleReport = { - gradleFileToGradleProjectMap: new Map([ - ['proj/build.gradle', 'proj'], - ]), - buildFileToDepsMap: new Map>(), - gradleFileToOutputDirsMap: new Map>([ - ['proj/build.gradle', new Map([['build', 'build']])], - ]), - gradleProjectToTasksMap: new Map>([ - ['proj', new Set(['test'])], - ]), - gradleProjectToTasksTypeMap: new Map>([ - ['proj', new Map([['test', 'Verification']])], - ]), - gradleProjectToProjectName: new Map([['proj', 'proj']]), - gradleProjectNameToProjectRootMap: new Map([ - ['proj', 'proj'], - ]), - gradleProjectToChildProjects: new Map(), - }; + gradleReport = readJsonFile( + join(__dirname, 'src/plugin/utils/__mocks__/gradle_tutorial.json') + ); context = { nxJsonConfiguration: { namedInputs: { @@ -76,48 +62,33 @@ describe('@nx/gradle/plugin', () => { [ "proj/build.gradle", { + "externalNodes": {}, "projects": { "proj": { "metadata": { "targetGroups": { - "Verification": [ - "test", + "help": [ + "buildEnvironment", ], }, "technologies": [ "gradle", ], }, - "name": "proj", - "projectType": "application", + "name": "gradle-tutorial", + "root": "proj", "targets": { - "test": { + "buildEnvironment": { "cache": true, - "command": "./gradlew proj:test", - "dependsOn": [ - "testClasses", - ], - "inputs": [ - "default", - "^production", - ], + "command": "./gradlew :buildEnvironment", "metadata": { - "help": { - "command": "./gradlew help --task proj:test", - "example": { - "options": { - "args": [ - "--rerun", - ], - }, - }, - }, + "description": "Displays all buildscript dependencies declared in root project 'gradle-tutorial'.", "technologies": [ "gradle", ], }, "options": { - "cwd": ".", + "cwd": "proj", }, }, }, diff --git a/packages/gradle/plugin.ts b/packages/gradle/plugin.ts index c6345f3ebd..f1b3829f07 100644 --- a/packages/gradle/plugin.ts +++ b/packages/gradle/plugin.ts @@ -1,2 +1,2 @@ export { createDependencies } from './src/plugin/dependencies'; -export { createNodes, createNodesV2 } from './src/plugin/nodes'; +export { createNodesV2 } from './src/plugin/nodes'; diff --git a/packages/gradle/project-graph/.gitignore b/packages/gradle/project-graph/.gitignore new file mode 100644 index 0000000000..667ce03db0 --- /dev/null +++ b/packages/gradle/project-graph/.gitignore @@ -0,0 +1,3 @@ +# Ignore Gradle project-specific cache directory +bin +build \ No newline at end of file diff --git a/packages/gradle/project-graph/README.md b/packages/gradle/project-graph/README.md new file mode 100644 index 0000000000..2ffdde03fd --- /dev/null +++ b/packages/gradle/project-graph/README.md @@ -0,0 +1,56 @@ +# dev.nx.gradle.project-graph + +This gradle plugin contains + +## Installation + +Kotlin +build.gradle.kts + +``` +plugins { + id("dev.nx.gradle.project-graph") version("+") +} +``` + +Groovy +build.gradle + +``` +plugins { + id "dev.nx.gradle.project-graph" version "+" +} +``` + +## Usage + +```bash +./gradlew nxProjectGraph +``` + +In terminal, it should output something like: + +``` +> Task :nxProjectGraph +< your workspace >/build/nx/add-nx-to-gradle.json +``` + +To pass in a hash parameter: + +```bash +./gradlew nxProjectGraph -Phash=12345 +``` + +It generates a json file to be consumed by nx: + +```json +{ + "nodes": { + "app": { + "targets": {} + } + }, + "dependencies": [], + "externalNodes": {} +} +``` diff --git a/packages/gradle/project-graph/build.gradle.kts b/packages/gradle/project-graph/build.gradle.kts new file mode 100644 index 0000000000..7b81d2f463 --- /dev/null +++ b/packages/gradle/project-graph/build.gradle.kts @@ -0,0 +1,120 @@ +plugins { + `java-gradle-plugin` + `maven-publish` + signing + id("com.ncorti.ktfmt.gradle") version "+" + id("dev.nx.gradle.project-graph") version "0.0.2" + id("org.jetbrains.kotlin.jvm") version "2.1.10" + id("com.gradle.plugin-publish") version "1.2.1" +} + +group = "dev.nx.gradle" + +version = "0.0.2" + +repositories { mavenCentral() } + +dependencies { + implementation("com.google.code.gson:gson:2.10.1") + testImplementation(kotlin("test")) + testImplementation("org.mockito:mockito-core:5.8.0") + testImplementation("org.mockito.kotlin:mockito-kotlin:5.2.1") + testImplementation("org.junit.jupiter:junit-jupiter:5.10.1") +} + +java { + withSourcesJar() + withJavadocJar() +} + +gradlePlugin { + website = "https://nx.dev/" + vcsUrl = "https://github.com/nrwl/nx" + plugins { + create("nxProjectGraphPlugin") { + id = "dev.nx.gradle.project-graph" + implementationClass = "dev.nx.gradle.NxProjectGraphReportPlugin" + displayName = "The Nx Plugin for Gradle to generate Nx project graph" + description = "Generates a JSON file with nodes, dependencies, and external nodes for Nx" + tags = listOf("nx", "monorepo", "javascript", "typescript") + } + } +} + +afterEvaluate { + publishing { + publications.named("pluginMaven", MavenPublication::class) { + pom { + name.set("Nx Gradle Project Graph Plugin") + description.set( + "A plugin to generate a JSON file with nodes, dependencies, and external nodes for Nx") + url.set("https://github.com/nrwl/nx") + + licenses { license { name.set("MIT") } } + + developers { + developer { + id.set("nx") + name.set("Nx") + email.set("java-services@nrwl.io") + } + } + + scm { + connection.set("scm:git:git://github.com/nrwl/nx.git") + developerConnection.set("scm:git:ssh://github.com/nrwl/nx.git") + url.set("https://github.com/nrwl/nx") + } + } + } + + repositories { + maven { + name = "localStaging" + url = uri(layout.buildDirectory.dir("staging")) + } + } + } + publishing { + publications.named("nxProjectGraphPluginPluginMarkerMaven", MavenPublication::class) { + pom { + name.set("Nx Gradle Project Graph Plugin") + description.set( + "A plugin to generate a JSON file with nodes, dependencies, and external nodes for Nx") + url.set("https://github.com/nrwl/nx") + + licenses { license { name.set("MIT") } } + + developers { + developer { + id.set("nx") + name.set("Nx") + email.set("java-services@nrwl.io") + } + } + + scm { + connection.set("scm:git:git://github.com/nrwl/nx.git") + developerConnection.set("scm:git:ssh://github.com/nrwl/nx.git") + url.set("https://github.com/nrwl/nx") + } + + repositories { + maven { + name = "localStaging" + url = uri(layout.buildDirectory.dir("staging")) + } + } + } + } + } +} + +signing { + afterEvaluate { + sign(publishing.publications["pluginMaven"]) + sign(publishing.publications["nxProjectGraphPluginPluginMarkerMaven"]) + } +} + +tasks.test { useJUnitPlatform() } diff --git a/packages/gradle/project-graph/project.json b/packages/gradle/project-graph/project.json new file mode 100644 index 0000000000..0301757775 --- /dev/null +++ b/packages/gradle/project-graph/project.json @@ -0,0 +1,43 @@ +{ + "name": "gradle-project-graph", + "$schema": "node_modules/nx/schemas/project-schema.json", + "targets": { + "test": { + "command": "./gradlew :project-graph:test", + "options": { + "args": [] + }, + "cache": true + }, + "lint": { + "command": "./gradlew :project-graph:ktfmtCheck", + "cache": true + }, + "format": { + "command": "./gradlew :project-graph:ktfmtFormat", + "cache": true + }, + "publish-staging": { + "command": "./gradlew :project-graph:publish", + "cache": true, + "outputs": ["{projectRoot}/build/staging"] + }, + "zip-staging": { + "command": "zip -r ../deployment.zip .", + "options": { + "cwd": "{projectRoot}/build/staging" + }, + "inputs": ["{projectRoot}/build/staging"], + "outputs": ["{projectRoot}/build/deployment.zip"], + "dependsOn": ["publish-staging"] + }, + "maven": { + "command": "npx ts-node publish-maven.ts --deploymentZipPath=build/deployment.zip", + "options": { + "cwd": "{projectRoot}" + }, + "inputs": ["{projectRoot}/build/deployment.zip"], + "dependsOn": ["zip-staging"] + } + } +} diff --git a/packages/gradle/project-graph/publish-maven.ts b/packages/gradle/project-graph/publish-maven.ts new file mode 100644 index 0000000000..12d20b5866 --- /dev/null +++ b/packages/gradle/project-graph/publish-maven.ts @@ -0,0 +1,133 @@ +import axios from 'axios'; +import * as fs from 'fs'; +import * as FormData from 'form-data'; + +function parseArgs() { + const args = process.argv.slice(2); + const result: Record = {}; + args.forEach((arg) => { + const [key, value] = arg.replace(/^--/, '').split('='); + result[key] = value; + }); + return result; +} + +async function publishToMavenApi( + username: string, + password: string, + deploymentZipPath = 'deployment.zip' +) { + const token = Buffer.from(`${username}:${password}`).toString('base64'); + console.log(`📦 Publishing to Maven Central...`); + + const url = 'https://central.sonatype.com/api/v1/publisher/upload'; + const form = new FormData(); + form.append('bundle', fs.createReadStream(deploymentZipPath)); + + let uploadId: string; + try { + const response = await axios.post(url, form, { + headers: { + Authorization: `Basic ${token}`, + ...form.getHeaders(), + }, + }); + uploadId = response.data.toString().trim(); + console.log(`✅ Upload ID: ${uploadId}`); + } catch (err: any) { + console.error('🚫 Upload failed:', err.response?.data || err.message); + process.exit(1); + } + + let currentStatus = await getUploadStatus(uploadId, token); + if (['PENDING', 'VALIDATING', 'PUBLISHING'].includes(currentStatus)) { + currentStatus = await retryUntilValidatedOrPublished( + currentStatus, + uploadId, + token + ); + } + + if (!['VALIDATED', 'PUBLISHED'].includes(currentStatus)) { + console.error(`🚫 Upload failed with final status: ${currentStatus}`); + process.exit(1); + } + + console.log(`📦 Upload is ${currentStatus}, proceeding to deploy...`); + if (currentStatus === 'PUBLISHED') { + console.log('✅ Already published, skipping deployment.'); + return; + } + + const deployUrl = `https://central.sonatype.com/api/v1/publisher/deployment/${uploadId}`; + try { + const deployRes = await axios.post(deployUrl, null, { + headers: { Authorization: `Basic ${token}` }, + }); + console.log(`🚀 Deployment response: ${deployRes.data}`); + } catch (err: any) { + console.error('🚫 Deployment failed:', err.response?.data || err.message); + process.exit(1); + } +} + +async function getUploadStatus( + uploadId: string, + token: string +): Promise { + const url = `https://central.sonatype.com/api/v1/publisher/status?id=${uploadId}`; + try { + const response = await axios.post(url, null, { + headers: { Authorization: `Basic ${token}` }, + }); + const state = response.data.deploymentState; + console.log(`📡 Current deployment state: ${state}`); + return state; + } catch (err: any) { + console.error( + '🚫 Failed to get status:', + err.response?.data || err.message + ); + return 'FAILED'; + } +} + +async function retryUntilValidatedOrPublished( + currentStatus: string, + uploadId: string, + token: string, + retries = 10, + delay = 10_000 +): Promise { + for (let i = 0; i < retries; i++) { + console.log(`🔁 Checking status (attempt ${i + 1}/${retries})...`); + await sleep(delay); + currentStatus = await getUploadStatus(uploadId, token); + if (['VALIDATED', 'PUBLISHED', 'FAILED'].includes(currentStatus)) break; + } + return currentStatus; +} + +function sleep(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +// Entry +(async function main() { + let { username, password, deploymentZipPath } = parseArgs(); + + username = username || process.env.MAVEN_USERNAME; + password = password || process.env.MAVEN_PASSWORD; + + if (!username || !password) { + console.error('❌ Missing MAVEN_USERNAME or MAVEN_PASSWORD'); + process.exit(1); + } + + if (!deploymentZipPath) { + console.error('❌ Missing required --deploymentZipPath argument'); + process.exit(1); + } + + await publishToMavenApi(username, password, deploymentZipPath); +})(); diff --git a/packages/gradle/project-graph/settings.gradle.kts b/packages/gradle/project-graph/settings.gradle.kts new file mode 100644 index 0000000000..d264f3bb97 --- /dev/null +++ b/packages/gradle/project-graph/settings.gradle.kts @@ -0,0 +1,16 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * The settings file is used to specify which projects to include in your build. + * For more detailed information on multi-project builds, please refer to https://docs.gradle.org/8.5/userguide/building_swift_projects.html in the Gradle documentation. + */ + +pluginManagement { + repositories { + mavenLocal() + mavenCentral() + gradlePluginPortal() + } +} + +rootProject.name = "project-graph" diff --git a/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/NxProjectGraphReportPlugin.kt b/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/NxProjectGraphReportPlugin.kt new file mode 100644 index 0000000000..0b91fa86e0 --- /dev/null +++ b/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/NxProjectGraphReportPlugin.kt @@ -0,0 +1,94 @@ +package dev.nx.gradle + +import java.util.* +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.tasks.TaskProvider + +class NxProjectGraphReportPlugin : Plugin { + override fun apply(project: Project) { + project.logger.info("${Date()} Applying NxProjectGraphReportPlugin to ${project.name}") + + val nxProjectReportTask: TaskProvider = + project.tasks.register("nxProjectReport", NxProjectReportTask::class.java) { task -> + val hashProperty = + project.findProperty("hash")?.toString() + ?: run { + project.logger.warn( + "No 'hash' property was provided for $project. Using default hash value: 'default-hash'") + "default-hash" + } + + val cwdProperty = + project.findProperty("cwd")?.toString() + ?: run { + project.logger.warn( + "No 'cwd' property was provided for $project. Using default hash value: ${System.getProperty("user.dir")}") + System.getProperty("user.dir") + } + + val workspaceRootProperty = + project.findProperty("workspaceRoot")?.toString() + ?: run { + project.logger.warn( + "No 'workspaceRoot' property was provided for $project. Using default hash value: ${System.getProperty("user.dir")}") + System.getProperty("user.dir") + } + + val targetNameOverrides: Map = + project.properties + .filterKeys { it.endsWith("TargetName") } + .mapValues { it.value.toString() } + task.projectName.set(project.name) + task.projectRef.set(project) + task.hash.set(hashProperty) + task.targetNameOverrides.set(targetNameOverrides) + task.cwd.set(cwdProperty) + task.workspaceRoot.set(workspaceRootProperty) + + task.description = "Create Nx project report for ${project.name}" + task.group = "Reporting" + + task.doFirst { it.logger.info("${Date()} Running nxProjectReport for ${project.name}") } + } + + // Ensure all included builds are processed only once using lazy evaluation + project.gradle.includedBuilds.distinct().forEach { includedBuild -> + nxProjectReportTask.configure { it.dependsOn(includedBuild.task(":nxProjectReport")) } + } + + // Ensure all subprojects are processed only once using lazy evaluation + project.subprojects.distinct().forEach { subProject -> + // Add a dependency on each subproject's nxProjectReport task + nxProjectReportTask.configure { + it.dependsOn(subProject.tasks.matching { it.name == "nxProjectReport" }) + } + } + + project.tasks.register("nxProjectGraph").configure { task -> + task.dependsOn(nxProjectReportTask) + task.description = "Create Nx project graph for ${project.name}" + task.group = "Reporting" + + val outputFileProvider = nxProjectReportTask.map { it.outputFile } + + task.doFirst { it.logger.info("${Date()} Running nxProjectGraph for ${project.name}") } + + task.doLast { println(outputFileProvider.get().path) } + } + + // Ensure all included builds are processed only once using lazy evaluation + project.gradle.includedBuilds.distinct().forEach { includedBuild -> + project.tasks.named("nxProjectGraph").configure { + it.dependsOn(includedBuild.task(":nxProjectGraph")) + } + } + + // Ensure all subprojects are processed only once using lazy evaluation + project.subprojects.distinct().forEach { subProject -> + project.tasks.named("nxProjectGraph").configure { + it.dependsOn(subProject.tasks.matching { it.name == "nxProjectGraph" }) + } + } + } +} diff --git a/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/NxProjectReportTask.kt b/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/NxProjectReportTask.kt new file mode 100644 index 0000000000..71cc67313f --- /dev/null +++ b/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/NxProjectReportTask.kt @@ -0,0 +1,63 @@ +package dev.nx.gradle + +import com.google.gson.Gson +import dev.nx.gradle.utils.createNodeForProject +import java.io.File +import java.util.* +import javax.inject.Inject +import org.gradle.api.DefaultTask +import org.gradle.api.Project +import org.gradle.api.file.ProjectLayout +import org.gradle.api.provider.MapProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.* + +@CacheableTask +abstract class NxProjectReportTask @Inject constructor(private val projectLayout: ProjectLayout) : + DefaultTask() { + + companion object { + private val gson = Gson() + } + + @get:Input abstract val projectName: Property + + @get:Input abstract val hash: Property + + @get:Input abstract val cwd: Property + + @get:Input abstract val workspaceRoot: Property + + @get:Input abstract val targetNameOverrides: MapProperty + + // Don't compute report at configuration time, move it to execution time + @get:Internal // Prevent Gradle from caching this reference + abstract val projectRef: Property + + @get:OutputFile + val outputFile: File + get() = projectLayout.buildDirectory.file("nx/${projectName.get()}.json").get().asFile + + @TaskAction + fun action() { + logger.info("${Date()} Apply task action NxProjectReportTask for ${projectName.get()}") + logger.info("${Date()} Hash input: ${hash.get()}") + logger.info("${Date()} Target Name Overrides ${targetNameOverrides.get()}") + val project = projectRef.get() // Get project reference at execution time + val report = + createNodeForProject( + project, + targetNameOverrides.get(), + workspaceRoot.get(), + cwd.get()) // Compute report at execution time + val reportJson = gson.toJson(report) + + if (outputFile.exists() && outputFile.readText() == reportJson) { + logger.info("${Date()} No change in the node report for ${projectName.get()}") + return + } + + logger.info("${Date()} Writing node report for ${projectName.get()}") + outputFile.writeText(reportJson) + } +} diff --git a/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/data/Dependency.kt b/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/data/Dependency.kt new file mode 100644 index 0000000000..87c8b8dc5f --- /dev/null +++ b/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/data/Dependency.kt @@ -0,0 +1,6 @@ +package dev.nx.gradle.data + +import java.io.Serializable + +data class Dependency(val source: String, val target: String, var sourceFile: String) : + Serializable diff --git a/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/data/ExternalDepData.kt b/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/data/ExternalDepData.kt new file mode 100644 index 0000000000..c1a2b5599b --- /dev/null +++ b/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/data/ExternalDepData.kt @@ -0,0 +1,10 @@ +package dev.nx.gradle.data + +import java.io.Serializable +import org.gradle.api.tasks.Input + +data class ExternalDepData( + @Input val version: String?, + @Input val packageName: String, + @Input val hash: String? +) : Serializable diff --git a/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/data/ExternalNode.kt b/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/data/ExternalNode.kt new file mode 100644 index 0000000000..fd326b0865 --- /dev/null +++ b/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/data/ExternalNode.kt @@ -0,0 +1,11 @@ +package dev.nx.gradle.data + +import java.io.Serializable +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.Nested + +data class ExternalNode( + @Input var type: String?, + @Input val name: String, + @Nested var data: ExternalDepData +) : Serializable diff --git a/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/data/GradleNodeReport.kt b/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/data/GradleNodeReport.kt new file mode 100644 index 0000000000..7929cdebf2 --- /dev/null +++ b/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/data/GradleNodeReport.kt @@ -0,0 +1,11 @@ +package dev.nx.gradle.data + +import java.io.Serializable +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.Nested + +data class GradleNodeReport( + @Nested val nodes: Map, + @Input val dependencies: Set, + @Nested val externalNodes: Map +) : Serializable diff --git a/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/data/GradleTargets.kt b/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/data/GradleTargets.kt new file mode 100644 index 0000000000..de80c6c7b5 --- /dev/null +++ b/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/data/GradleTargets.kt @@ -0,0 +1,17 @@ +package dev.nx.gradle.data + +import java.io.Serializable + +typealias NxTarget = MutableMap + +typealias NxTargets = MutableMap + +typealias TargetGroup = MutableList + +typealias TargetGroups = MutableMap + +data class GradleTargets( + val targets: NxTargets, + val targetGroups: TargetGroups, + var externalNodes: MutableMap +) : Serializable diff --git a/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/data/NodeMetadata.kt b/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/data/NodeMetadata.kt new file mode 100644 index 0000000000..4c2d4d02ce --- /dev/null +++ b/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/data/NodeMetadata.kt @@ -0,0 +1,9 @@ +package dev.nx.gradle.data + +import java.io.Serializable + +data class NodeMetadata( + val targetGroups: TargetGroups, + val technologies: List, + val description: String? +) : Serializable diff --git a/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/data/ProjectNode.kt b/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/data/ProjectNode.kt new file mode 100644 index 0000000000..fa9508ae77 --- /dev/null +++ b/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/data/ProjectNode.kt @@ -0,0 +1,10 @@ +package dev.nx.gradle.data + +import java.io.Serializable +import org.gradle.api.tasks.Input + +data class ProjectNode( + @Input val targets: NxTargets, + @Input val metadata: NodeMetadata, + @Input val name: String +) : Serializable diff --git a/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/utils/CiTargetsUtils.kt b/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/utils/CiTargetsUtils.kt new file mode 100644 index 0000000000..c6a9a8d00b --- /dev/null +++ b/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/utils/CiTargetsUtils.kt @@ -0,0 +1,143 @@ +package dev.nx.gradle.utils + +import dev.nx.gradle.data.* +import java.io.File +import org.gradle.api.Task +import org.gradle.api.file.FileCollection + +const val testCiTargetGroup = "verification" + +/** + * Add atomized ci test targets Going to loop through each test files and create a target for each + * It is going to modify targets and targetGroups in place + */ +fun addTestCiTargets( + testFiles: FileCollection, + projectBuildPath: String, + testTask: Task, + targets: NxTargets, + targetGroups: TargetGroups, + projectRoot: String, + workspaceRoot: String, + ciTargetName: String +) { + ensureTargetGroupExists(targetGroups, testCiTargetGroup) + + val gradlewCommand = getGradlewCommand() + val ciDependsOn = mutableListOf>() + + val filteredTestFiles = testFiles.filter { isTestFile(it, workspaceRoot) } + + filteredTestFiles.forEach { testFile -> + val className = getTestClassNameIfAnnotated(testFile) ?: return@forEach + + val testCiTarget = + buildTestCiTarget( + gradlewCommand = gradlewCommand, + projectBuildPath = projectBuildPath, + testClassName = className, + testFile = testFile, + testTask = testTask, + projectRoot = projectRoot, + workspaceRoot = workspaceRoot) + + val targetName = "$ciTargetName--$className" + targets[targetName] = testCiTarget + targetGroups[testCiTargetGroup]?.add(targetName) + + ciDependsOn.add(mapOf("target" to targetName, "projects" to "self", "params" to "forward")) + } + + testTask.logger.info("$testTask ci tasks: $ciDependsOn") + + if (ciDependsOn.isNotEmpty()) { + ensureParentCiTarget( + targets = targets, + targetGroups = targetGroups, + ciTargetName = ciTargetName, + projectBuildPath = projectBuildPath, + dependsOn = ciDependsOn) + } +} + +private fun getTestClassNameIfAnnotated(file: File): String? { + if (!file.exists()) return null + + val content = file.readText() + if (!content.contains("@Test")) return null + + val classRegex = Regex("""class\s+([A-Za-z_][A-Za-z0-9_]*)""") + val match = classRegex.find(content) + return match?.groupValues?.get(1) +} + +fun ensureTargetGroupExists(targetGroups: TargetGroups, group: String) { + if (!targetGroups.containsKey(group)) { + targetGroups[group] = mutableListOf() + } +} + +private fun isTestFile(file: File, workspaceRoot: String): Boolean { + val fileName = file.name.substringBefore(".") + val regex = "^(?!abstract).*?(Test)(s)?\\d*".toRegex(RegexOption.IGNORE_CASE) + return file.path.startsWith(workspaceRoot) && regex.matches(fileName) +} + +private fun buildTestCiTarget( + gradlewCommand: String, + projectBuildPath: String, + testClassName: String, + testFile: File, + testTask: Task, + projectRoot: String, + workspaceRoot: String +): MutableMap { + val target = + mutableMapOf( + "command" to "$gradlewCommand ${projectBuildPath}:test --tests $testClassName", + "metadata" to + getMetadata("Runs Gradle test $testClassName in CI", projectBuildPath, "test"), + "cache" to true, + "inputs" to arrayOf(replaceRootInPath(testFile.path, projectRoot, workspaceRoot))) + + getDependsOnForTask(testTask, null) + ?.takeIf { it.isNotEmpty() } + ?.let { + testTask.logger.info("$testTask: processed ${it.size} dependsOn") + target["dependsOn"] = it + } + + getOutputsForTask(testTask, projectRoot, workspaceRoot) + ?.takeIf { it.isNotEmpty() } + ?.let { + testTask.logger.info("$testTask: processed ${it.size} outputs") + target["outputs"] = it + } + + return target +} + +private fun ensureParentCiTarget( + targets: NxTargets, + targetGroups: TargetGroups, + ciTargetName: String, + projectBuildPath: String, + dependsOn: List> +) { + val ciTarget = + targets.getOrPut(ciTargetName) { + mutableMapOf().apply { + put("executor", "nx:noop") + put("metadata", getMetadata("Runs Gradle Tests in CI", projectBuildPath, "test", "test")) + put("dependsOn", mutableListOf>()) + put("cache", true) + } + } + + val dependsOnList = ciTarget.getOrPut("dependsOn") { mutableListOf() } as MutableList + dependsOnList.addAll(dependsOn) + + if (targetGroups[testCiTargetGroup]?.contains(ciTargetName) != true) { + targetGroups[testCiTargetGroup]?.add(ciTargetName) + } +} diff --git a/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/utils/ProjectUtils.kt b/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/utils/ProjectUtils.kt new file mode 100644 index 0000000000..5984a1ac33 --- /dev/null +++ b/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/utils/ProjectUtils.kt @@ -0,0 +1,159 @@ +package dev.nx.gradle.utils + +import dev.nx.gradle.data.* +import java.util.* +import org.gradle.api.Project + +/** Loops through a project and populate dependencies and nodes for each target */ +fun createNodeForProject( + project: Project, + targetNameOverrides: Map, + workspaceRoot: String, + cwd: String +): GradleNodeReport { + val logger = project.logger + logger.info("${Date()} ${project.name} createNodeForProject: get nodes and dependencies") + + // Initialize dependencies with an empty Set to prevent null issues + val dependencies: MutableSet = + try { + getDependenciesForProject(project) + } catch (e: Exception) { + logger.info( + "${Date()} ${project.name} createNodeForProject: get dependencies error: ${e.message}") + mutableSetOf() + } + logger.info("${Date()} ${project.name} createNodeForProject: got dependencies") + + // Initialize nodes and externalNodes with empty maps to prevent null issues + var nodes: Map + var externalNodes: Map + + try { + val gradleTargets: GradleTargets = + processTargetsForProject(project, dependencies, targetNameOverrides, workspaceRoot, cwd) + val projectRoot = project.projectDir.path + val projectNode = + ProjectNode( + targets = gradleTargets.targets, + metadata = + NodeMetadata(gradleTargets.targetGroups, listOf("gradle"), project.description), + name = project.name) + nodes = mapOf(projectRoot to projectNode) + externalNodes = gradleTargets.externalNodes + logger.info( + "${Date()} ${project.name} createNodeForProject: get nodes and external nodes for $projectRoot") + } catch (e: Exception) { + logger.info("${project.name}: get nodes error: ${e.message}") + nodes = emptyMap() + externalNodes = emptyMap() + } + return GradleNodeReport(nodes, dependencies, externalNodes) +} + +/** + * Process targets for project + * + * @return targets and targetGroups + */ +fun processTargetsForProject( + project: Project, + dependencies: MutableSet, + targetNameOverrides: Map, + workspaceRoot: String, + cwd: String +): GradleTargets { + val targets: NxTargets = mutableMapOf>() + val targetGroups: TargetGroups = mutableMapOf>() + val externalNodes = mutableMapOf() + val projectRoot = project.projectDir.path + project.logger.info("Using workspace root $workspaceRoot") + + var projectBuildPath: String = + project + .buildTreePath // get the build path of project e.g. :app, :utils:number-utils, :buildSrc + if (projectBuildPath.endsWith(":")) { // root project is ":", manually remove last : + projectBuildPath = projectBuildPath.dropLast(1) + } + + val logger = project.logger + + logger.info("${Date()} ${project}: process targets") + + var gradleProject = project.buildTreePath + if (!gradleProject.endsWith(":")) { + gradleProject += ":" + } + + project.tasks.forEach { task -> + try { + logger.info("${Date()} ${project.name}: Processing $task") + val taskName = targetNameOverrides.getOrDefault(task.name + "TargetName", task.name) + // add task to target groups + val group: String? = task.group + if (!group.isNullOrBlank()) { + if (targetGroups.contains(group)) { + targetGroups[group]?.add(task.name) + } else { + targetGroups[group] = mutableListOf(task.name) + } + } + + val target = + processTask( + task, + projectBuildPath, + projectRoot, + workspaceRoot, + cwd, + externalNodes, + dependencies, + targetNameOverrides) + targets[taskName] = target + + val ciTargetName = targetNameOverrides.getOrDefault("ciTargetName", null) + ciTargetName?.let { + if (task.name.startsWith("compileTest")) { + val testTask = project.getTasksByName("test", false) + if (testTask.isNotEmpty()) { + addTestCiTargets( + task.inputs.sourceFiles, + projectBuildPath, + testTask.first(), + targets, + targetGroups, + projectRoot, + workspaceRoot, + it) + } + } + + // Add the `$ciTargetName-check` target when processing the "check" task + if (task.name == "check") { + val replacedDependencies = + (target["dependsOn"] as? List<*>)?.map { dep -> + if (dep.toString() == targetNameOverrides.getOrDefault("testTargetName", "test")) + ciTargetName + else dep.toString() + } ?: emptyList() + + // Copy the original target and override "dependsOn" + val newTarget = target.toMutableMap() + newTarget["dependsOn"] = replacedDependencies + + val ciCheckTargetName = "$ciTargetName-check" + targets[ciCheckTargetName] = newTarget + + ensureTargetGroupExists(targetGroups, testCiTargetGroup) + targetGroups[testCiTargetGroup]?.add(ciCheckTargetName) + } + } + logger.info("${Date()} ${project.name}: Processed $task") + } catch (e: Exception) { + logger.info("${task}: process task error $e") + logger.debug("Stack trace:", e) + } + } + + return GradleTargets(targets, targetGroups, externalNodes) +} diff --git a/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/utils/TaskUtils.kt b/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/utils/TaskUtils.kt new file mode 100644 index 0000000000..ac49eab006 --- /dev/null +++ b/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/utils/TaskUtils.kt @@ -0,0 +1,348 @@ +package dev.nx.gradle.utils + +import dev.nx.gradle.data.* +import org.gradle.api.Named +import org.gradle.api.NamedDomainObjectProvider +import org.gradle.api.Task +import org.gradle.api.tasks.TaskProvider + +/** + * Process a task and convert it into target Going to populate: + * - cache + * - inputs + * - outputs + * - command + * - metadata + * - options with cwd and args + */ +fun processTask( + task: Task, + projectBuildPath: String, + projectRoot: String, + workspaceRoot: String, + cwd: String, + externalNodes: MutableMap, + dependencies: MutableSet, + targetNameOverrides: Map +): MutableMap { + val logger = task.logger + logger.info("NxProjectReportTask: process $task for $projectRoot") + val target = mutableMapOf() + target["cache"] = true // set cache to be always true + + // process inputs + val inputs = getInputsForTask(task, projectRoot, workspaceRoot, externalNodes) + if (!inputs.isNullOrEmpty()) { + logger.info("${task}: processed ${inputs.size} inputs") + target["inputs"] = inputs + } + + // process outputs + val outputs = getOutputsForTask(task, projectRoot, workspaceRoot) + if (!outputs.isNullOrEmpty()) { + logger.info("${task}: processed ${outputs.size} outputs") + target["outputs"] = outputs + } + + // process dependsOn + val dependsOn = getDependsOnForTask(task, dependencies, targetNameOverrides) + if (!dependsOn.isNullOrEmpty()) { + logger.info("${task}: processed ${dependsOn.size} dependsOn") + target["dependsOn"] = dependsOn + } + + val gradlewCommand = getGradlewCommand() + target["command"] = "$gradlewCommand ${projectBuildPath}:${task.name}" + + val metadata = getMetadata(task.description ?: "Run ${task.name}", projectBuildPath, task.name) + target["metadata"] = metadata + + target["options"] = mapOf("cwd" to cwd) + + return target +} + +fun getGradlewCommand(): String { + val gradlewCommand: String + val operatingSystem = System.getProperty("os.name").lowercase() + gradlewCommand = + if (operatingSystem.contains("win")) { + ".\\gradlew.bat" + } else { + "./gradlew" + } + return gradlewCommand +} + +/** + * Parse task and get inputs for this task + * + * @param task task to process + * @return a list of inputs including external dependencies, null if empty or an error occurred + */ +fun getInputsForTask( + task: Task, + projectRoot: String, + workspaceRoot: String, + externalNodes: MutableMap? +): MutableList? { + return try { + val mappedInputsIncludeExternal: MutableList = mutableListOf() + val inputs = task.inputs + val externalDependencies = mutableListOf() + inputs.sourceFiles.forEach { file -> + val path: String = file.path + // replace the absolute path to contain {projectRoot} or {workspaceRoot} + val pathWithReplacedRoot = replaceRootInPath(path, projectRoot, workspaceRoot) + if (pathWithReplacedRoot != null) { // if the path is inside workspace + mappedInputsIncludeExternal.add((pathWithReplacedRoot)) + } + // if the path is outside of workspace + if (pathWithReplacedRoot == null && + externalNodes != null) { // add it to external dependencies + try { + val externalDep = getExternalDepFromInputFile(path, externalNodes, task.logger) + externalDep?.let { externalDependencies.add(it) } + } catch (e: Exception) { + task.logger.info("${task}: get external dependency error $e") + } + } + } + if (externalDependencies.isNotEmpty()) { + mappedInputsIncludeExternal.add(mutableMapOf("externalDependencies" to externalDependencies)) + } + if (mappedInputsIncludeExternal.isNotEmpty()) { + return mappedInputsIncludeExternal + } + return null + } catch (e: Exception) { + // Log the error but don't fail the build + task.logger.info("Error getting outputs for ${task.path}: ${e.message}") + task.logger.debug("Stack trace:", e) + null + } +} + +/** + * Get outputs for task + * + * @param task task to process + * @return list of outputs file, will not include if output file is outside workspace, null if empty + * or an error occurred + */ +fun getOutputsForTask(task: Task, projectRoot: String, workspaceRoot: String): List? { + return try { + val outputs = task.outputs.files + if (!outputs.isEmpty) { + return outputs.mapNotNull { file -> + val path: String = file.path + replaceRootInPath(path, projectRoot, workspaceRoot) + } + } + null + } catch (e: Exception) { + // Log the error but don't fail the build + task.logger.info("Error getting outputs for ${task.path}: ${e.message}") + task.logger.debug("Stack trace:", e) + null + } +} + +/** + * Get dependsOn for task, handling configuration timing safely. Rewrites dependency task names + * based on targetNameOverrides (e.g., test -> ci). + * + * @param task task to process + * @param dependencies optional set to collect inter-project Dependency objects + * @param targetNameOverrides optional map of overrides (e.g., test -> ci) + * @return list of dependsOn task names (possibly replaced), or null if none found or error occurred + */ +fun getDependsOnForTask( + task: Task, + dependencies: MutableSet?, + targetNameOverrides: Map = emptyMap() +): List? { + + fun mapTasksToNames(tasks: Collection): List { + return tasks.map { depTask -> + val depProject = depTask.project + val taskProject = task.project + + if (task.name != "buildDependents" && depProject != taskProject && dependencies != null) { + dependencies.add( + Dependency( + taskProject.projectDir.path, + depProject.projectDir.path, + taskProject.buildFile.path)) + } + + // Check if this task name needs to be overridden + val taskName = targetNameOverrides.getOrDefault(depTask.name + "TargetName", depTask.name) + val overriddenTaskName = + if (depProject == taskProject) { + taskName + } else { + "${depProject.name}:${taskName}" + } + + overriddenTaskName + } + } + + return try { + val dependsOnEntries = task.dependsOn + + // Prefer task.dependsOn + if (dependsOnEntries.isNotEmpty()) { + val resolvedTasks = + dependsOnEntries.flatMap { dep -> + when (dep) { + is Task -> listOf(dep) + + is TaskProvider<*>, + is NamedDomainObjectProvider<*> -> { + val providerName = (dep as Named).name + val foundTask = task.project.tasks.findByName(providerName) + if (foundTask != null) { + listOf(foundTask) + } else { + task.logger.info( + "${dep::class.simpleName} '$providerName' did not resolve to a task in project ${task.project.name}") + emptyList() + } + } + + is String -> { + val foundTask = task.project.tasks.findByPath(dep) + if (foundTask != null) { + listOf(foundTask) + } else { + task.logger.info( + "Task string '$dep' could not be resolved in project ${task.project.name}") + emptyList() + } + } + + else -> { + task.logger.info( + "Unhandled dependency type ${dep::class.java} for task ${task.path}") + emptyList() + } + } + } + + if (resolvedTasks.isNotEmpty()) { + return mapTasksToNames(resolvedTasks) + } + } + + // Fallback: taskDependencies.getDependencies(task) + val fallbackDeps = + try { + task.taskDependencies.getDependencies(null) + } catch (e: Exception) { + task.logger.info("Error calling getDependencies for ${task.path}: ${e.message}") + task.logger.debug("Stack trace:", e) + emptySet() + } + + if (fallbackDeps.isNotEmpty()) { + return mapTasksToNames(fallbackDeps) + } + + null + } catch (e: Exception) { + task.logger.info("Unexpected error getting dependencies for ${task.path}: ${e.message}") + task.logger.debug("Stack trace:", e) + null + } +} + +/** + * Get metadata for task + * + * @param description + */ +fun getMetadata( + description: String?, + projectBuildPath: String, + taskName: String, + nonAtomizedTarget: String? = null +): Map { + val gradlewCommand = getGradlewCommand() + return mapOf( + "description" to description, + "technologies" to arrayOf("gradle"), + "help" to mapOf("command" to "$gradlewCommand help --task ${projectBuildPath}:${taskName}"), + "nonAtomizedTarget" to nonAtomizedTarget) +} + +/** + * Converts a file path like: + * org.apache.commons/commons-lang3/3.13.0/b7263237aa89c1f99b327197c41d0669707a462e/commons-lang3-3.13.0.jar + * + * Into an external dependency with key: "gradle:commons-lang3-3.13.0" with value: { "type": + * "gradle", "name": "commons-lang3", "data": { "version": "3.13.0", "packageName": + * "org.apache.commons.commons-lang3", "hash": "b7263237aa89c1f99b327197c41d0669707a462e",} } + * + * @param inputFile Path to the dependency jar. + * @param externalNodes Map to populate with the resulting ExternalNode. + * @return The external dependency key (e.g., gradle:commons-lang3-3.13.0), or null if parsing + * fails. + */ +fun getExternalDepFromInputFile( + inputFile: String, + externalNodes: MutableMap, + logger: org.gradle.api.logging.Logger +): String? { + try { + val segments = inputFile.split("/") + + // Expecting at least 5 segments to safely extract group, package, version, hash, filename + if (segments.size < 5) { + logger.warn("Invalid input path: '$inputFile'. Expected at least 5 segments.") + return null + } + + val fileName = segments.last() + + // Remove any file extension (after the last dot), if present + val nameKey = fileName.substringBeforeLast(".", fileName) + + val hash = segments[segments.size - 2] + val version = segments[segments.size - 3] + val packageName = segments[segments.size - 4] + val packageGroup = segments[segments.size - 5] + + val fullPackageName = "$packageGroup.$packageName" + + val data = ExternalDepData(version, fullPackageName, hash) + val externalKey = "gradle:$nameKey" + val node = ExternalNode("gradle", externalKey, data) + + externalNodes[externalKey] = node + + return externalKey + } catch (e: Exception) { + logger.warn("Failed to parse inputFile '$inputFile': ${e.message}") + logger.debug("Stack trace:", e) + return null + } +} + +/** + * Going to replace the projectRoot with {projectRoot} and workspaceRoot with {workspaceRoot} + * + * @return mapped path if inside workspace, null if outside workspace + */ +fun replaceRootInPath(p: String, projectRoot: String, workspaceRoot: String): String? { + var path = p + if (path.startsWith(projectRoot)) { + path = path.replace(projectRoot, "{projectRoot}") + return path + } else if (path.startsWith(workspaceRoot)) { + path = path.replace(workspaceRoot, "{workspaceRoot}") + return path + } + return null +} diff --git a/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/utils/projectDependencyUtils.kt b/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/utils/projectDependencyUtils.kt new file mode 100644 index 0000000000..e869d3e3b1 --- /dev/null +++ b/packages/gradle/project-graph/src/main/kotlin/dev/nx/gradle/utils/projectDependencyUtils.kt @@ -0,0 +1,30 @@ +package dev.nx.gradle.utils + +import dev.nx.gradle.data.Dependency +import org.gradle.api.Project + +private val dependencyCache = mutableMapOf>() + +fun getDependenciesForProject(project: Project): MutableSet { + return dependencyCache + .getOrPut(project) { buildDependenciesForProject(project) } + .toMutableSet() // Return a new mutable copy to prevent modifying the cached set +} + +private fun buildDependenciesForProject(project: Project): Set { + val dependencies = mutableSetOf() + + // Include subprojects manually + project.subprojects.forEach { childProject -> + dependencies.add( + Dependency(project.projectDir.path, childProject.projectDir.path, project.buildFile.path)) + } + + // Include included builds manually + project.gradle.includedBuilds.forEach { includedBuild -> + dependencies.add( + Dependency(project.projectDir.path, includedBuild.projectDir.path, project.buildFile.path)) + } + + return dependencies +} diff --git a/packages/gradle/project-graph/src/test/kotlin/dev/nx/gradle/utils/AddTestCiTargetsTest.kt b/packages/gradle/project-graph/src/test/kotlin/dev/nx/gradle/utils/AddTestCiTargetsTest.kt new file mode 100644 index 0000000000..58d41d8561 --- /dev/null +++ b/packages/gradle/project-graph/src/test/kotlin/dev/nx/gradle/utils/AddTestCiTargetsTest.kt @@ -0,0 +1,81 @@ +package dev.nx.gradle.utils + +import dev.nx.gradle.data.* +import java.io.File +import kotlin.test.assertEquals +import kotlin.test.assertTrue +import org.gradle.api.Project +import org.gradle.api.Task +import org.gradle.testfixtures.ProjectBuilder +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test + +class AddTestCiTargetsTest { + + private lateinit var project: Project + private lateinit var testTask: Task + private lateinit var workspaceRoot: File + private lateinit var projectRoot: File + + @BeforeEach + fun setup() { + workspaceRoot = createTempDir("workspace") + projectRoot = File(workspaceRoot, "project-a").apply { mkdirs() } + + project = ProjectBuilder.builder().withProjectDir(projectRoot).build() + testTask = project.task("test") + } + + @Test + fun `should generate test CI targets and group correctly`() { + val testFile1 = + File(projectRoot, "src/test/kotlin/MyFirstTest.kt").apply { + parentFile.mkdirs() + writeText("@Test class MyFirstTest") + } + + val testFile2 = + File(projectRoot, "src/test/kotlin/AnotherTest.kt").apply { + parentFile.mkdirs() + writeText("@Test class AnotherTest") + } + + val testFiles = project.files(testFile1, testFile2) + + val targets = mutableMapOf>() + val targetGroups = mutableMapOf>() + val ciTargetName = "ci" + + addTestCiTargets( + testFiles = testFiles, + projectBuildPath = ":project-a", + testTask = testTask, + targets = targets, + targetGroups = targetGroups, + projectRoot = projectRoot.absolutePath, + workspaceRoot = workspaceRoot.absolutePath, + ciTargetName = ciTargetName) + + // Assert each test file created a CI target + assertTrue(targets.containsKey("ci--MyFirstTest")) + assertTrue(targets.containsKey("ci--AnotherTest")) + + // Assert test group contains individual targets and parent ci task + val group = targetGroups[testCiTargetGroup] + assertTrue(group != null) + assertTrue(group!!.contains("ci--MyFirstTest")) + assertTrue(group.contains("ci--AnotherTest")) + assertTrue(group.contains("ci")) + + // Assert parent CI task includes dependsOn + val parentCi = targets["ci"] + val dependsOn = parentCi?.get("dependsOn") as? List<*> + assertEquals(2, dependsOn!!.size) + + val firstTarget = targets["ci--MyFirstTest"]!! + assertTrue(firstTarget["command"].toString().contains("--tests MyFirstTest")) + assertEquals(true, firstTarget["cache"]) + assertTrue((firstTarget["inputs"] as Array<*>)[0].toString().contains("{projectRoot}")) + assertEquals("nx:noop", parentCi["executor"]) + } +} diff --git a/packages/gradle/project-graph/src/test/kotlin/dev/nx/gradle/utils/CreateNodeForProjectTest.kt b/packages/gradle/project-graph/src/test/kotlin/dev/nx/gradle/utils/CreateNodeForProjectTest.kt new file mode 100644 index 0000000000..49289e86b1 --- /dev/null +++ b/packages/gradle/project-graph/src/test/kotlin/dev/nx/gradle/utils/CreateNodeForProjectTest.kt @@ -0,0 +1,54 @@ +package dev.nx.gradle.utils + +import dev.nx.gradle.data.* +import kotlin.test.* +import org.gradle.testfixtures.ProjectBuilder + +class CreateNodeForProjectTest { + + @Test + fun `should return GradleNodeReport with targets and metadata`() { + // Arrange + val workspaceRoot = createTempDir("workspace").absolutePath + val projectDir = createTempDir("project") + val project = ProjectBuilder.builder().withProjectDir(projectDir).build() + + // Create a couple of dummy tasks + project.task("compileJava").apply { + group = "build" + description = "Compiles Java sources" + } + + project.task("test").apply { + group = "verification" + description = "Runs the tests" + } + + val targetNameOverrides = mapOf() + + // Act + val result = + createNodeForProject( + project = project, + targetNameOverrides = targetNameOverrides, + workspaceRoot = workspaceRoot, + cwd = "{projectRoot}") + + // Assert + val projectRoot = project.projectDir.absolutePath + assertTrue(result.nodes.containsKey(projectRoot), "Expected node for project root") + + val projectNode = result.nodes[projectRoot] + assertNotNull(projectNode, "ProjectNode should not be null") + + // Check target metadata + assertEquals(project.name, projectNode.name) + assertNotNull(projectNode.targets["compileJava"], "Expected compileJava target") + assertNotNull(projectNode.targets["test"], "Expected test target") + assertEquals("build", projectNode.metadata.targetGroups.keys.firstOrNull()) + + // Dependencies and external nodes should default to empty + assertTrue(result.dependencies.isEmpty(), "Expected no dependencies") + assertTrue(result.externalNodes.isEmpty(), "Expected no external nodes") + } +} diff --git a/packages/gradle/project-graph/src/test/kotlin/dev/nx/gradle/utils/ProcessTaskUtilsTest.kt b/packages/gradle/project-graph/src/test/kotlin/dev/nx/gradle/utils/ProcessTaskUtilsTest.kt new file mode 100644 index 0000000000..994a92234e --- /dev/null +++ b/packages/gradle/project-graph/src/test/kotlin/dev/nx/gradle/utils/ProcessTaskUtilsTest.kt @@ -0,0 +1,96 @@ +package dev.nx.gradle.utils + +import dev.nx.gradle.data.Dependency +import dev.nx.gradle.data.ExternalNode +import org.gradle.testfixtures.ProjectBuilder +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Test +import org.mockito.kotlin.* + +class ProcessTaskUtilsTest { + + @Test + fun `test replaceRootInPath`() { + val path = "/home/user/workspace/project/src/main/java" + val projectRoot = "/home/user/workspace/project" + val workspaceRoot = "/home/user/workspace" + + assertEquals("{projectRoot}/src/main/java", replaceRootInPath(path, projectRoot, workspaceRoot)) + assertEquals( + "{workspaceRoot}/project/src/main/java", + replaceRootInPath(path, "/other/path", workspaceRoot)) + assertNull(replaceRootInPath("/external/other", projectRoot, workspaceRoot)) + } + + @Test + fun `test getGradlewCommand`() { + val command = getGradlewCommand() + assertTrue(command.contains("gradlew")) + } + + @Test + fun `test getMetadata`() { + val metadata = getMetadata("Compile Java", ":project", "compileJava") + assertEquals("Compile Java", metadata["description"]) + assertEquals("gradle", (metadata["technologies"] as Array<*>)[0]) + } + + @Test + fun `test getExternalDepFromInputFile valid path`() { + val externalNodes = mutableMapOf() + val path = "org/apache/commons/commons-lang3/3.13.0/hash/commons-lang3-3.13.0.jar" + + val key = getExternalDepFromInputFile(path, externalNodes, mock()) + + assertEquals("gradle:commons-lang3-3.13.0", key) + assertTrue(externalNodes.containsKey("gradle:commons-lang3-3.13.0")) + } + + @Test + fun `test getExternalDepFromInputFile invalid path`() { + val externalNodes = mutableMapOf() + val key = getExternalDepFromInputFile("invalid/path.jar", externalNodes, mock()) + + assertNull(key) + assertTrue(externalNodes.isEmpty()) + } + + @Test + fun `test getDependsOnForTask with direct dependsOn`() { + val project = ProjectBuilder.builder().build() + val taskA = project.tasks.register("taskA").get() + val taskB = project.tasks.register("taskB").get() + + taskA.dependsOn(taskB) + + val dependencies = mutableSetOf() + val dependsOn = getDependsOnForTask(taskA, dependencies) + + assertNotNull(dependsOn) + assertTrue(dependsOn!!.contains("taskB")) + } + + @Test + fun `test processTask basic properties`() { + val project = ProjectBuilder.builder().build() + val task = project.tasks.register("compileJava").get() + task.group = "build" + task.description = "Compiles Java source files" + + val result = + processTask( + task, + projectBuildPath = ":project", + projectRoot = project.projectDir.path, + workspaceRoot = project.rootDir.path, + cwd = ".", + externalNodes = mutableMapOf(), + dependencies = mutableSetOf(), + targetNameOverrides = emptyMap()) + + assertEquals(true, result["cache"]) + assertTrue((result["command"] as String).contains("gradlew")) + assertNotNull(result["metadata"]) + assertNotNull(result["options"]) + } +} diff --git a/packages/gradle/src/generators/ci-workflow/__snapshots__/generator.spec.ts.snap b/packages/gradle/src/generators/ci-workflow/__snapshots__/generator.spec.ts.snap index cf486e7f42..732167fefb 100644 --- a/packages/gradle/src/generators/ci-workflow/__snapshots__/generator.spec.ts.snap +++ b/packages/gradle/src/generators/ci-workflow/__snapshots__/generator.spec.ts.snap @@ -13,7 +13,7 @@ jobs: _JAVA_OPTIONS: '-Xmx3g' GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.workers.max=2' docker: - - image: cimg/openjdk:17.0-node + - image: cimg/openjdk:21.0-node steps: - checkout @@ -66,15 +66,15 @@ jobs: # Uncomment this line to enable task distribution # - run: npx nx-cloud start-ci-run --distribute-on="3 linux-medium-jvm" --stop-agents-after="build" - - name: Set up JDK 17 for x64 + - name: Set up JDK 21 for x64 uses: actions/setup-java@v4 with: - java-version: '17' + java-version: '21' distribution: 'temurin' architecture: x64 - name: Setup Gradle - uses: gradle/gradle-build-action@v2 + uses: gradle/gradle-build-action@v4 - uses: nrwl/nx-set-shas@v4 @@ -96,7 +96,7 @@ jobs: _JAVA_OPTIONS: '-Xmx3g' GRADLE_OPTS: '-Dorg.gradle.daemon=false -Dorg.gradle.workers.max=2' docker: - - image: cimg/openjdk:17.0-node + - image: cimg/openjdk:21.0-node steps: - checkout @@ -149,15 +149,15 @@ jobs: # Connect your workspace by running "nx connect" and uncomment this line to enable task distribution # - run: npx nx-cloud start-ci-run --distribute-on="3 linux-medium-jvm" --stop-agents-after="build" - - name: Set up JDK 17 for x64 + - name: Set up JDK 21 for x64 uses: actions/setup-java@v4 with: - java-version: '17' + java-version: '21' distribution: 'temurin' architecture: x64 - name: Setup Gradle - uses: gradle/gradle-build-action@v2 + uses: gradle/gradle-build-action@v4 - uses: nrwl/nx-set-shas@v4 diff --git a/packages/gradle/src/generators/ci-workflow/files/circleci/.circleci/config.yml.template b/packages/gradle/src/generators/ci-workflow/files/circleci/.circleci/config.yml.template index 39828ee160..c7a6ba4cca 100644 --- a/packages/gradle/src/generators/ci-workflow/files/circleci/.circleci/config.yml.template +++ b/packages/gradle/src/generators/ci-workflow/files/circleci/.circleci/config.yml.template @@ -10,7 +10,7 @@ jobs: _JAVA_OPTIONS: "-Xmx3g" GRADLE_OPTS: "-Dorg.gradle.daemon=false -Dorg.gradle.workers.max=2" docker: - - image: cimg/openjdk:17.0-node + - image: cimg/openjdk:21.0-node steps: - checkout diff --git a/packages/gradle/src/generators/ci-workflow/files/github/.github/workflows/__workflowFileName__.yml.template b/packages/gradle/src/generators/ci-workflow/files/github/.github/workflows/__workflowFileName__.yml.template index 3f7227ec8a..2a384492c6 100644 --- a/packages/gradle/src/generators/ci-workflow/files/github/.github/workflows/__workflowFileName__.yml.template +++ b/packages/gradle/src/generators/ci-workflow/files/github/.github/workflows/__workflowFileName__.yml.template @@ -25,15 +25,15 @@ jobs: <% if (connectedToCloud) { %># Uncomment this line to enable task distribution<% } else { %># Connect your workspace by running "nx connect" and uncomment this line to enable task distribution<% } %> # - run: <%= packageManagerPrefix %> nx-cloud start-ci-run --distribute-on="3 linux-medium-jvm" --stop-agents-after="build" - - name: Set up JDK 17 for x64 + - name: Set up JDK 21 for x64 uses: actions/setup-java@v4 with: - java-version: '17' + java-version: '21' distribution: 'temurin' architecture: x64 - name: Setup Gradle - uses: gradle/gradle-build-action@v2 + uses: gradle/gradle-build-action@v4 - uses: nrwl/nx-set-shas@v4 diff --git a/packages/gradle/src/generators/init/init.spec.ts b/packages/gradle/src/generators/init/init.spec.ts index 881688c79f..42a1e09bf6 100644 --- a/packages/gradle/src/generators/init/init.spec.ts +++ b/packages/gradle/src/generators/init/init.spec.ts @@ -24,7 +24,6 @@ describe('@nx/gradle:init', () => { "options": { "buildTargetName": "build", "classesTargetName": "classes", - "includeSubprojectsTasks": false, "testTargetName": "test", }, "plugin": "@nx/gradle", @@ -49,7 +48,6 @@ describe('@nx/gradle:init', () => { "options": { "buildTargetName": "build", "classesTargetName": "classes", - "includeSubprojectsTasks": false, "testTargetName": "test", }, "plugin": "@nx/gradle", diff --git a/packages/gradle/src/generators/init/init.ts b/packages/gradle/src/generators/init/init.ts index 2a7f9028ec..55950788aa 100644 --- a/packages/gradle/src/generators/init/init.ts +++ b/packages/gradle/src/generators/init/init.ts @@ -9,7 +9,11 @@ import { Tree, updateNxJson, } from '@nx/devkit'; -import { nxVersion } from '../../utils/versions'; +import { + gradleProjectGraphPluginName, + gradleProjectGraphVersion, + nxVersion, +} from '../../utils/versions'; import { InitGeneratorSchema } from './schema'; import { hasGradlePlugin } from '../../utils/has-gradle-plugin'; import { dirname, join, basename } from 'path'; @@ -52,7 +56,6 @@ function addPlugin(tree: Tree) { testTargetName: 'test', classesTargetName: 'classes', buildTargetName: 'build', - includeSubprojectsTasks: false, }, }); updateNxJson(tree, nxJson); @@ -67,16 +70,18 @@ export async function addBuildGradleFileNextToSettingsGradle(tree: Tree) { '**/settings.gradle?(.kts)', ]); settingsGradleFiles.forEach((settingsGradleFile) => { - addProjectReportToBuildGradle(settingsGradleFile, tree); + addNxProjectGraphPluginToBuildGradle(settingsGradleFile, tree); }); } /** * - creates a build.gradle file next to the settings.gradle file if it does not exist. - * - adds the project-report plugin to the build.gradle file if it does not exist. - * - adds a task to generate project reports for all subprojects and included builds. + * - adds the NxProjectGraphPlugin plugin to the build.gradle file if it does not exist. */ -function addProjectReportToBuildGradle(settingsGradleFile: string, tree: Tree) { +function addNxProjectGraphPluginToBuildGradle( + settingsGradleFile: string, + tree: Tree +) { const filename = basename(settingsGradleFile); let gradleFilePath = 'build.gradle'; if (filename.endsWith('.kts')) { @@ -90,53 +95,49 @@ function addProjectReportToBuildGradle(settingsGradleFile: string, tree: Tree) { buildGradleContent = tree.read(gradleFilePath).toString(); } - if (buildGradleContent.includes('allprojects')) { - if (!buildGradleContent.includes('"project-report"')) { - logger.warn(`Please add the project-report plugin to your ${gradleFilePath}: -allprojects { - apply { - plugin("project-report") - } -}`); + const nxProjectGraphReportPlugin = filename.endsWith('.kts') + ? `id("${gradleProjectGraphPluginName}") version("${gradleProjectGraphVersion}")` + : `id "${gradleProjectGraphPluginName}" version "${gradleProjectGraphVersion}"`; + if (buildGradleContent.includes('plugins {')) { + if (!buildGradleContent.includes(gradleProjectGraphPluginName)) { + buildGradleContent = buildGradleContent.replace( + 'plugins {', + `plugins { + ${nxProjectGraphReportPlugin}` + ); } } else { - buildGradleContent += `\n\rallprojects { + buildGradleContent = `plugins { + ${nxProjectGraphReportPlugin} +}\n\r${buildGradleContent}`; + } + + const applyNxProjectGraphReportPlugin = `plugin("${gradleProjectGraphPluginName}")`; + if (buildGradleContent.includes('allprojects {')) { + if ( + !buildGradleContent.includes( + `plugin("${gradleProjectGraphPluginName}")` + ) && + !buildGradleContent.includes(`plugin('${gradleProjectGraphPluginName}')`) + ) { + logger.warn( + `Please add the ${gradleProjectGraphPluginName} plugin to your ${gradleFilePath}: +allprojects { apply { - plugin("project-report") + ${applyNxProjectGraphReportPlugin} } -}`; +}` + ); + } + } else { + buildGradleContent = `${buildGradleContent}\n\rallprojects { + apply { + ${applyNxProjectGraphReportPlugin} + } + }`; } - if (!buildGradleContent.includes(`tasks.register("projectReportAll")`)) { - if (gradleFilePath.endsWith('.kts')) { - buildGradleContent += `\n\rtasks.register("projectReportAll") { - // All project reports of subprojects - allprojects.forEach { - dependsOn(it.tasks.get("projectReport")) - } - - // All projectReportAll of included builds - gradle.includedBuilds.forEach { - dependsOn(it.task(":projectReportAll")) - } -}`; - } else { - buildGradleContent += `\n\rtasks.register("projectReportAll") { - // All project reports of subprojects - allprojects.forEach { - dependsOn(it.tasks.getAt("projectReport")) - } - - // All projectReportAll of included builds - gradle.includedBuilds.forEach { - dependsOn(it.task(":projectReportAll")) - } - }`; - } - } - if (buildGradleContent) { - tree.write(gradleFilePath, buildGradleContent); - } + tree.write(gradleFilePath, buildGradleContent); } export function updateNxJsonConfiguration(tree: Tree) { diff --git a/packages/gradle/src/migrations/19-4-0/add-project-report-all.ts b/packages/gradle/src/migrations/19-4-0/add-project-report-all.ts index 0d9824e95e..d022419548 100644 --- a/packages/gradle/src/migrations/19-4-0/add-project-report-all.ts +++ b/packages/gradle/src/migrations/19-4-0/add-project-report-all.ts @@ -1,5 +1,5 @@ -import { Tree } from '@nx/devkit'; -import { addBuildGradleFileNextToSettingsGradle } from '../../generators/init/init'; +import { globAsync, logger, Tree } from '@nx/devkit'; +import { basename, dirname, join } from 'node:path'; /** * This migration adds task `projectReportAll` to build.gradle files @@ -7,3 +7,83 @@ import { addBuildGradleFileNextToSettingsGradle } from '../../generators/init/in export default async function update(tree: Tree) { await addBuildGradleFileNextToSettingsGradle(tree); } + +/** + * This function creates and populate build.gradle file next to the settings.gradle file. + */ +export async function addBuildGradleFileNextToSettingsGradle(tree: Tree) { + const settingsGradleFiles = await globAsync(tree, [ + '**/settings.gradle?(.kts)', + ]); + settingsGradleFiles.forEach((settingsGradleFile) => { + addProjectReportToBuildGradle(settingsGradleFile, tree); + }); +} + +/** + * - creates a build.gradle file next to the settings.gradle file if it does not exist. + * - adds the project-report plugin to the build.gradle file if it does not exist. + * - adds a task to generate project reports for all subprojects and included builds. + */ +function addProjectReportToBuildGradle(settingsGradleFile: string, tree: Tree) { + const filename = basename(settingsGradleFile); + let gradleFilePath = 'build.gradle'; + if (filename.endsWith('.kts')) { + gradleFilePath = 'build.gradle.kts'; + } + gradleFilePath = join(dirname(settingsGradleFile), gradleFilePath); + let buildGradleContent = ''; + if (!tree.exists(gradleFilePath)) { + tree.write(gradleFilePath, buildGradleContent); // create a build.gradle file near settings.gradle file if it does not exist + } else { + buildGradleContent = tree.read(gradleFilePath).toString(); + } + + if (buildGradleContent.includes('allprojects')) { + if (!buildGradleContent.includes('"project-report"')) { + logger.warn(`Please add the project-report plugin to your ${gradleFilePath}: +allprojects { + apply { + plugin("project-report") + } +}`); + } + } else { + buildGradleContent += `\n\rallprojects { + apply { + plugin("project-report") + } +}`; + } + + if (!buildGradleContent.includes(`tasks.register("projectReportAll")`)) { + if (gradleFilePath.endsWith('.kts')) { + buildGradleContent += `\n\rtasks.register("projectReportAll") { + // All project reports of subprojects + allprojects.forEach { + dependsOn(it.tasks.get("projectReport")) + } + + // All projectReportAll of included builds + gradle.includedBuilds.forEach { + dependsOn(it.task(":projectReportAll")) + } +}`; + } else { + buildGradleContent += `\n\rtasks.register("projectReportAll") { + // All project reports of subprojects + allprojects.forEach { + dependsOn(it.tasks.getAt("projectReport")) + } + + // All projectReportAll of included builds + gradle.includedBuilds.forEach { + dependsOn(it.task(":projectReportAll")) + } + }`; + } + } + if (buildGradleContent) { + tree.write(gradleFilePath, buildGradleContent); + } +} diff --git a/packages/gradle/src/migrations/20-2-0/add-include-subprojects-tasks.md b/packages/gradle/src/migrations/20-2-0/add-include-subprojects-tasks.md index b6ddf6d0e5..fc3742986d 100644 --- a/packages/gradle/src/migrations/20-2-0/add-include-subprojects-tasks.md +++ b/packages/gradle/src/migrations/20-2-0/add-include-subprojects-tasks.md @@ -1,11 +1,9 @@ -#### Add includeSubprojectsTasks to build.gradle File +#### Add includeSubprojectsTasks to @nx/gradle Plugin Options -Add includeSubprojectsTasks to build.gradle file +Add includeSubprojectsTasks to @nx/gradle plugin options in nx.json file #### Sample Code Changes -Update import paths for `withModuleFederation` and `withModuleFederationForSSR`. - {% tabs %} {% tab label="Before" %} diff --git a/packages/gradle/src/migrations/20-2-0/add-include-subprojects-tasks.ts b/packages/gradle/src/migrations/20-2-0/add-include-subprojects-tasks.ts index b81506bbdf..216edef9bb 100644 --- a/packages/gradle/src/migrations/20-2-0/add-include-subprojects-tasks.ts +++ b/packages/gradle/src/migrations/20-2-0/add-include-subprojects-tasks.ts @@ -1,6 +1,6 @@ import { Tree, readNxJson, updateNxJson } from '@nx/devkit'; import { hasGradlePlugin } from '../../utils/has-gradle-plugin'; -import { GradlePluginOptions } from '../../plugin/nodes'; +import { GradlePluginOptions } from '../../plugin-v1/nodes'; // This function add options includeSubprojectsTasks as true in nx.json for gradle plugin export default function update(tree: Tree) { diff --git a/packages/gradle/src/migrations/21-0-0/change-plugin-to-v1.md b/packages/gradle/src/migrations/21-0-0/change-plugin-to-v1.md new file mode 100644 index 0000000000..99023a0c2f --- /dev/null +++ b/packages/gradle/src/migrations/21-0-0/change-plugin-to-v1.md @@ -0,0 +1,26 @@ +#### Change @nx/gradle plugin to @nx/gradle/plugin-v1 + +Change @nx/gradle plugin to version 1 in nx.json + +#### Sample Code Changes + +{% tabs %} +{% tab label="Before" %} + +```json {% fileName="nx.json" %} +{ + "plugins": ["@nx/gradle"] +} +``` + +{% /tab %} +{% tab label="After" %} + +```json {% highlightLines=[5] fileName="nx.json" %} +{ + "plugins": ["@nx/gradle/plugin-v1"] +} +``` + +{% /tab %} +{% /tabs %} diff --git a/packages/gradle/src/migrations/21-0-0/change-plugin-to-v1.spec.ts b/packages/gradle/src/migrations/21-0-0/change-plugin-to-v1.spec.ts new file mode 100644 index 0000000000..ebb455143d --- /dev/null +++ b/packages/gradle/src/migrations/21-0-0/change-plugin-to-v1.spec.ts @@ -0,0 +1,57 @@ +import { Tree, readNxJson } from '@nx/devkit'; +import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; +import update from './change-plugin-to-v1'; + +describe('ChangePluginToV1', () => { + let tree: Tree; + + beforeAll(() => { + tree = createTreeWithEmptyWorkspace(); + }); + + it('should not add @nx/gradle plugin if it does not exist', async () => { + tree.write('nx.json', JSON.stringify({ namedInputs: {} })); + update(tree); + expect(readNxJson(tree)).toMatchInlineSnapshot(` + { + "namedInputs": {}, + } + `); + }); + + it('should change @nx/gradle to @nx/gradle/plugin-v1 plugin', async () => { + tree.write('nx.json', JSON.stringify({ plugins: ['@nx/gradle'] })); + update(tree); + expect(readNxJson(tree)).toMatchInlineSnapshot(` + { + "plugins": [ + "@nx/gradle/plugin-v1", + ], + } + `); + }); + + it('should add change to @nx/gradle plugin with options', async () => { + tree.write( + 'nx.json', + JSON.stringify({ + plugins: [ + { plugin: '@nx/gradle', options: { testTargetName: 'test' } }, + ], + }) + ); + update(tree); + expect(readNxJson(tree)).toMatchInlineSnapshot(` + { + "plugins": [ + { + "options": { + "testTargetName": "test", + }, + "plugin": "@nx/gradle/plugin-v1", + }, + ], + } + `); + }); +}); diff --git a/packages/gradle/src/migrations/21-0-0/change-plugin-to-v1.ts b/packages/gradle/src/migrations/21-0-0/change-plugin-to-v1.ts new file mode 100644 index 0000000000..3bb8745229 --- /dev/null +++ b/packages/gradle/src/migrations/21-0-0/change-plugin-to-v1.ts @@ -0,0 +1,25 @@ +import { Tree, readNxJson, updateNxJson } from '@nx/devkit'; +import { hasGradlePlugin } from '../../utils/has-gradle-plugin'; + +/* This function changes the plugin to v1 + * Replace @nx/gradle with @nx/gradle/plugin-v1 + */ +export default function update(tree: Tree) { + const nxJson = readNxJson(tree); + if (!nxJson) { + return; + } + if (!hasGradlePlugin(tree)) { + return; + } + let gradlePluginIndex = nxJson.plugins.findIndex((p) => + typeof p === 'string' ? p === '@nx/gradle' : p.plugin === '@nx/gradle' + ); + let gradlePlugin = nxJson.plugins[gradlePluginIndex]; + if (typeof gradlePlugin === 'string') { + nxJson.plugins[gradlePluginIndex] = '@nx/gradle/plugin-v1'; + } else { + gradlePlugin.plugin = '@nx/gradle/plugin-v1'; + } + updateNxJson(tree, nxJson); +} diff --git a/packages/gradle/src/plugin-v1/dependencies.ts b/packages/gradle/src/plugin-v1/dependencies.ts new file mode 100644 index 0000000000..8a72bbce17 --- /dev/null +++ b/packages/gradle/src/plugin-v1/dependencies.ts @@ -0,0 +1,96 @@ +import { + CreateDependencies, + CreateDependenciesContext, + DependencyType, + FileMap, + RawProjectGraphDependency, + validateDependency, +} from '@nx/devkit'; +import { basename, dirname } from 'node:path'; + +import { getCurrentGradleReport } from './utils/get-gradle-report'; +import { GRADLE_BUILD_FILES } from '../utils/split-config-files'; + +export const createDependencies: CreateDependencies = async ( + _, + context: CreateDependenciesContext +) => { + const gradleFiles: string[] = findGradleFiles(context.filesToProcess); + if (gradleFiles.length === 0) { + return []; + } + + const gradleDependenciesStart = performance.mark('gradleDependencies:start'); + const { + gradleFileToGradleProjectMap, + gradleProjectNameToProjectRootMap, + gradleProjectToDepsMap, + gradleProjectToChildProjects, + } = getCurrentGradleReport(); + const dependencies: Set = new Set(); + + for (const gradleFile of gradleFiles) { + const gradleProject = gradleFileToGradleProjectMap.get(gradleFile); + const projectName = Object.values(context.projects).find( + (project) => project.root === dirname(gradleFile) + )?.name; + const dependedProjects: Set = + gradleProjectToDepsMap.get(gradleProject); + + if (projectName && dependedProjects?.size) { + dependedProjects?.forEach((dependedProject) => { + const targetProjectRoot = gradleProjectNameToProjectRootMap.get( + dependedProject + ) as string; + const targetProjectName = Object.values(context.projects).find( + (project) => project.root === targetProjectRoot + )?.name; + if (targetProjectName) { + const dependency: RawProjectGraphDependency = { + source: projectName as string, + target: targetProjectName as string, + type: DependencyType.static, + sourceFile: gradleFile, + }; + validateDependency(dependency, context); + dependencies.add(dependency); + } + }); + } + gradleProjectToChildProjects.get(gradleProject)?.forEach((childProject) => { + if (childProject) { + const dependency: RawProjectGraphDependency = { + source: projectName as string, + target: childProject, + type: DependencyType.static, + sourceFile: gradleFile, + }; + validateDependency(dependency, context); + dependencies.add(dependency); + } + }); + } + + const gradleDependenciesEnd = performance.mark('gradleDependencies:end'); + performance.measure( + 'gradleDependencies', + gradleDependenciesStart.name, + gradleDependenciesEnd.name + ); + + return Array.from(dependencies); +}; + +function findGradleFiles(fileMap: FileMap): string[] { + const gradleFiles: string[] = []; + + for (const [_, files] of Object.entries(fileMap.projectFileMap)) { + for (const file of files) { + if (GRADLE_BUILD_FILES.has(basename(file.file))) { + gradleFiles.push(file.file); + } + } + } + + return gradleFiles; +} diff --git a/packages/gradle/src/plugin-v1/nodes.spec.ts b/packages/gradle/src/plugin-v1/nodes.spec.ts new file mode 100644 index 0000000000..ec17dc59aa --- /dev/null +++ b/packages/gradle/src/plugin-v1/nodes.spec.ts @@ -0,0 +1,587 @@ +import { CreateNodesContext } from '@nx/devkit'; + +import { TempFs } from 'nx/src/internal-testing-utils/temp-fs'; +import { type GradleReport } from './utils/get-gradle-report'; + +let gradleReport: GradleReport; +jest.mock('./utils/get-gradle-report', () => { + return { + GRADLE_BUILD_FILES: new Set(['build.gradle', 'build.gradle.kts']), + populateGradleReport: jest.fn().mockImplementation(() => void 0), + getCurrentGradleReport: jest.fn().mockImplementation(() => gradleReport), + }; +}); + +import { createNodesV2 } from './nodes'; + +describe('@nx/gradle/plugin-v1/nodes', () => { + let createNodesFunction = createNodesV2[1]; + let context: CreateNodesContext; + let tempFs: TempFs; + let cwd: string; + + beforeEach(async () => { + tempFs = new TempFs('test'); + gradleReport = { + gradleFileToGradleProjectMap: new Map([ + ['proj/build.gradle', 'proj'], + ]), + gradleProjectToDepsMap: new Map>(), + gradleFileToOutputDirsMap: new Map>([ + ['proj/build.gradle', new Map([['build', 'build']])], + ]), + gradleProjectToTasksMap: new Map>([ + ['proj', new Set(['test'])], + ]), + gradleProjectToTasksTypeMap: new Map>([ + [ + 'proj', + new Map([ + ['test', 'Verification'], + ['build', 'Build'], + ]), + ], + ]), + gradleProjectToProjectName: new Map([['proj', 'proj']]), + gradleProjectNameToProjectRootMap: new Map([ + ['proj', 'proj'], + ]), + gradleProjectToChildProjects: new Map(), + }; + cwd = process.cwd(); + process.chdir(tempFs.tempDir); + context = { + nxJsonConfiguration: { + namedInputs: { + default: ['{projectRoot}/**/*'], + production: ['!{projectRoot}/**/*.spec.ts'], + }, + }, + workspaceRoot: tempFs.tempDir, + configFiles: [], + }; + + await tempFs.createFiles({ + 'proj/build.gradle': ``, + gradlew: '', + }); + }); + + afterEach(() => { + jest.resetModules(); + process.chdir(cwd); + }); + + it('should create nodes based on gradle', async () => { + const results = await createNodesFunction( + ['proj/build.gradle'], + { + buildTargetName: 'build', + }, + context + ); + + expect(results).toMatchInlineSnapshot(` + [ + [ + "proj/build.gradle", + { + "projects": { + "proj": { + "metadata": { + "targetGroups": { + "Verification": [ + "test", + ], + }, + "technologies": [ + "gradle", + ], + }, + "name": "proj", + "projectType": "application", + "targets": { + "test": { + "cache": true, + "command": "./gradlew proj:test", + "dependsOn": [ + "testClasses", + ], + "inputs": [ + "default", + "^production", + ], + "metadata": { + "help": { + "command": "./gradlew help --task proj:test", + "example": { + "options": { + "args": [ + "--rerun", + ], + }, + }, + }, + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": ".", + }, + }, + }, + }, + }, + }, + ], + ] + `); + }); + + it('should create nodes include subprojects tasks', async () => { + const results = await createNodesFunction( + ['proj/build.gradle'], + { + buildTargetName: 'build', + includeSubprojectsTasks: true, + }, + context + ); + + expect(results).toMatchInlineSnapshot(` + [ + [ + "proj/build.gradle", + { + "projects": { + "proj": { + "metadata": { + "targetGroups": { + "Build": [ + "build", + ], + "Verification": [ + "test", + ], + }, + "technologies": [ + "gradle", + ], + }, + "name": "proj", + "projectType": "application", + "targets": { + "build": { + "cache": true, + "command": "./gradlew proj:build", + "dependsOn": [ + "^build", + "classes", + "test", + ], + "inputs": [ + "production", + "^production", + ], + "metadata": { + "help": { + "command": "./gradlew help --task proj:build", + "example": { + "options": { + "args": [ + "--rerun", + ], + }, + }, + }, + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": ".", + }, + "outputs": [ + "build", + ], + }, + "test": { + "cache": true, + "command": "./gradlew proj:test", + "dependsOn": [ + "testClasses", + ], + "inputs": [ + "default", + "^production", + ], + "metadata": { + "help": { + "command": "./gradlew help --task proj:test", + "example": { + "options": { + "args": [ + "--rerun", + ], + }, + }, + }, + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": ".", + }, + }, + }, + }, + }, + }, + ], + ] + `); + }); + + it('should create nodes based on gradle for nested project root', async () => { + gradleReport = { + gradleFileToGradleProjectMap: new Map([ + ['nested/nested/proj/build.gradle', 'proj'], + ]), + gradleProjectToDepsMap: new Map>(), + gradleFileToOutputDirsMap: new Map>([ + ['nested/nested/proj/build.gradle', new Map([['build', 'build']])], + ]), + gradleProjectToTasksMap: new Map>([ + ['proj', new Set(['test'])], + ]), + gradleProjectToTasksTypeMap: new Map>([ + ['proj', new Map([['test', 'Verification']])], + ]), + gradleProjectToProjectName: new Map([['proj', 'proj']]), + gradleProjectNameToProjectRootMap: new Map([ + ['proj', 'proj'], + ]), + gradleProjectToChildProjects: new Map(), + }; + await tempFs.createFiles({ + 'nested/nested/proj/build.gradle': ``, + }); + + const results = await createNodesFunction( + ['nested/nested/proj/build.gradle'], + { + buildTargetName: 'build', + }, + context + ); + + expect(results).toMatchInlineSnapshot(` + [ + [ + "nested/nested/proj/build.gradle", + { + "projects": { + "nested/nested/proj": { + "metadata": { + "targetGroups": { + "Verification": [ + "test", + ], + }, + "technologies": [ + "gradle", + ], + }, + "name": "proj", + "projectType": "application", + "targets": { + "test": { + "cache": true, + "command": "./gradlew proj:test", + "dependsOn": [ + "testClasses", + ], + "inputs": [ + "default", + "^production", + ], + "metadata": { + "help": { + "command": "./gradlew help --task proj:test", + "example": { + "options": { + "args": [ + "--rerun", + ], + }, + }, + }, + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": ".", + }, + }, + }, + }, + }, + }, + ], + ] + `); + }); + + describe('with atomized tests targets', () => { + beforeEach(async () => { + gradleReport = { + gradleFileToGradleProjectMap: new Map([ + ['nested/nested/proj/build.gradle', 'proj'], + ]), + gradleProjectToDepsMap: new Map>(), + gradleFileToOutputDirsMap: new Map>([ + ['nested/nested/proj/build.gradle', new Map([['build', 'build']])], + ]), + gradleProjectToTasksMap: new Map>([ + ['proj', new Set(['test'])], + ]), + gradleProjectToTasksTypeMap: new Map>([ + ['proj', new Map([['test', 'Test']])], + ]), + gradleProjectToProjectName: new Map([['proj', 'proj']]), + gradleProjectNameToProjectRootMap: new Map([ + ['proj', 'proj'], + ]), + gradleProjectToChildProjects: new Map(), + }; + await tempFs.createFiles({ + 'nested/nested/proj/build.gradle': ``, + }); + await tempFs.createFiles({ + 'proj/src/test/java/test/rootTest.java': ``, + }); + await tempFs.createFiles({ + 'nested/nested/proj/src/test/java/test/aTest.java': ``, + }); + await tempFs.createFiles({ + 'nested/nested/proj/src/test/java/test/bTest.java': ``, + }); + await tempFs.createFiles({ + 'nested/nested/proj/src/test/java/test/cTests.java': ``, + }); + }); + + it('should create nodes with atomized tests targets based on gradle for nested project root', async () => { + const results = await createNodesFunction( + [ + 'nested/nested/proj/build.gradle', + 'proj/src/test/java/test/rootTest.java', + 'nested/nested/proj/src/test/java/test/aTest.java', + 'nested/nested/proj/src/test/java/test/bTest.java', + 'nested/nested/proj/src/test/java/test/cTests.java', + ], + { + buildTargetName: 'build', + ciTargetName: 'test-ci', + }, + context + ); + + expect(results).toMatchInlineSnapshot(` + [ + [ + "nested/nested/proj/build.gradle", + { + "projects": { + "nested/nested/proj": { + "metadata": { + "targetGroups": { + "Test": [ + "test-ci--aTest", + "test-ci--bTest", + "test-ci--cTests", + "test-ci", + "test", + ], + }, + "technologies": [ + "gradle", + ], + }, + "name": "proj", + "projectType": "application", + "targets": { + "test": { + "cache": false, + "command": "./gradlew proj:test", + "dependsOn": [ + "testClasses", + ], + "inputs": [ + "default", + "^production", + ], + "metadata": { + "help": { + "command": "./gradlew help --task proj:test", + "example": { + "options": { + "args": [ + "--rerun", + ], + }, + }, + }, + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": ".", + }, + }, + "test-ci": { + "cache": true, + "dependsOn": [ + { + "params": "forward", + "projects": "self", + "target": "test-ci--aTest", + }, + { + "params": "forward", + "projects": "self", + "target": "test-ci--bTest", + }, + { + "params": "forward", + "projects": "self", + "target": "test-ci--cTests", + }, + ], + "executor": "nx:noop", + "inputs": [ + "default", + "^production", + ], + "metadata": { + "description": "Runs Gradle Tests in CI", + "help": { + "command": "./gradlew help --task proj:test", + "example": { + "options": { + "args": [ + "--rerun", + ], + }, + }, + }, + "nonAtomizedTarget": "test", + "technologies": [ + "gradle", + ], + }, + }, + "test-ci--aTest": { + "cache": true, + "command": "./gradlew proj:test --tests aTest", + "dependsOn": [ + "testClasses", + ], + "inputs": [ + "default", + "^production", + ], + "metadata": { + "description": "Runs Gradle test nested/nested/proj/src/test/java/test/aTest.java in CI", + "help": { + "command": "./gradlew help --task proj:test", + "example": { + "options": { + "args": [ + "--rerun", + ], + }, + }, + }, + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": ".", + }, + }, + "test-ci--bTest": { + "cache": true, + "command": "./gradlew proj:test --tests bTest", + "dependsOn": [ + "testClasses", + ], + "inputs": [ + "default", + "^production", + ], + "metadata": { + "description": "Runs Gradle test nested/nested/proj/src/test/java/test/bTest.java in CI", + "help": { + "command": "./gradlew help --task proj:test", + "example": { + "options": { + "args": [ + "--rerun", + ], + }, + }, + }, + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": ".", + }, + }, + "test-ci--cTests": { + "cache": true, + "command": "./gradlew proj:test --tests cTests", + "dependsOn": [ + "testClasses", + ], + "inputs": [ + "default", + "^production", + ], + "metadata": { + "description": "Runs Gradle test nested/nested/proj/src/test/java/test/cTests.java in CI", + "help": { + "command": "./gradlew help --task proj:test", + "example": { + "options": { + "args": [ + "--rerun", + ], + }, + }, + }, + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": ".", + }, + }, + }, + }, + }, + }, + ], + ] + `); + }); + }); +}); diff --git a/packages/gradle/src/plugin-v1/nodes.ts b/packages/gradle/src/plugin-v1/nodes.ts new file mode 100644 index 0000000000..145e29d807 --- /dev/null +++ b/packages/gradle/src/plugin-v1/nodes.ts @@ -0,0 +1,435 @@ +import { + CreateNodes, + CreateNodesV2, + CreateNodesContext, + ProjectConfiguration, + TargetConfiguration, + createNodesFromFiles, + readJsonFile, + writeJsonFile, + CreateNodesFunction, + logger, +} from '@nx/devkit'; +import { calculateHashForCreateNodes } from '@nx/devkit/src/utils/calculate-hash-for-create-nodes'; +import { existsSync } from 'node:fs'; +import { basename, dirname, join } from 'node:path'; +import { workspaceDataDirectory } from 'nx/src/utils/cache-directory'; +import { findProjectForPath } from 'nx/src/devkit-internals'; + +import { + populateGradleReport, + getCurrentGradleReport, + GradleReport, +} from './utils/get-gradle-report'; +import { hashObject } from 'nx/src/hasher/file-hasher'; +import { + gradleConfigAndTestGlob, + gradleConfigGlob, + splitConfigFiles, +} from '../utils/split-config-files'; +import { getGradleExecFile, findGradlewFile } from '../utils/exec-gradle'; + +const cacheableTaskType = new Set(['Build', 'Verification']); +const dependsOnMap = { + build: ['^build', 'classes', 'test'], + testClasses: ['classes'], + test: ['testClasses'], + classes: ['^classes'], +}; + +interface GradleTask { + type: string; + name: string; +} + +export interface GradlePluginOptions { + includeSubprojectsTasks?: boolean; // default is false, show all gradle tasks in the project + ciTargetName?: string; + testTargetName?: string; + classesTargetName?: string; + buildTargetName?: string; + [taskTargetName: string]: string | undefined | boolean; +} + +function normalizeOptions(options: GradlePluginOptions): GradlePluginOptions { + options ??= {}; + options.testTargetName ??= 'test'; + options.classesTargetName ??= 'classes'; + options.buildTargetName ??= 'build'; + return options; +} + +type GradleTargets = Record>; + +function readTargetsCache(cachePath: string): GradleTargets { + return existsSync(cachePath) ? readJsonFile(cachePath) : {}; +} + +export function writeTargetsToCache(cachePath: string, results: GradleTargets) { + writeJsonFile(cachePath, results); +} + +export const createNodesV2: CreateNodesV2 = [ + gradleConfigAndTestGlob, + async (files, options, context) => { + const { buildFiles, projectRoots, gradlewFiles, testFiles } = + splitConfigFiles(files); + const optionsHash = hashObject(options); + const cachePath = join( + workspaceDataDirectory, + `gradle-${optionsHash}.hash` + ); + const targetsCache = readTargetsCache(cachePath); + + await populateGradleReport( + context.workspaceRoot, + gradlewFiles.map((f) => join(context.workspaceRoot, f)) + ); + const gradleReport = getCurrentGradleReport(); + const gradleProjectRootToTestFilesMap = getGradleProjectRootToTestFilesMap( + testFiles, + projectRoots + ); + + try { + return createNodesFromFiles( + makeCreateNodesForGradleConfigFile( + gradleReport, + targetsCache, + gradleProjectRootToTestFilesMap + ), + buildFiles, + options, + context + ); + } finally { + writeTargetsToCache(cachePath, targetsCache); + } + }, +]; + +export const makeCreateNodesForGradleConfigFile = + ( + gradleReport: GradleReport, + targetsCache: GradleTargets = {}, + gradleProjectRootToTestFilesMap: Record = {} + ): CreateNodesFunction => + async ( + gradleFilePath, + options: GradlePluginOptions | undefined, + context: CreateNodesContext + ) => { + const projectRoot = dirname(gradleFilePath); + options = normalizeOptions(options); + + const hash = await calculateHashForCreateNodes( + projectRoot, + options ?? {}, + context + ); + targetsCache[hash] ??= await createGradleProject( + gradleReport, + gradleFilePath, + options, + context, + gradleProjectRootToTestFilesMap[projectRoot] + ); + const project = targetsCache[hash]; + if (!project) { + return {}; + } + return { + projects: { + [projectRoot]: project, + }, + }; + }; + +/** + @deprecated This is replaced with {@link createNodesV2}. Update your plugin to export its own `createNodesV2` function that wraps this one instead. + This function will change to the v2 function in Nx 20. + */ +export const createNodes: CreateNodes = [ + gradleConfigGlob, + async (buildFile, options, context) => { + logger.warn( + '`createNodes` is deprecated. Update your plugin to utilize createNodesV2 instead. In Nx 20, this will change to the createNodesV2 API.' + ); + const { gradlewFiles } = splitConfigFiles(context.configFiles); + await populateGradleReport(context.workspaceRoot, gradlewFiles); + const gradleReport = getCurrentGradleReport(); + const internalCreateNodes = + makeCreateNodesForGradleConfigFile(gradleReport); + return await internalCreateNodes(buildFile, options, context); + }, +]; + +async function createGradleProject( + gradleReport: GradleReport, + gradleFilePath: string, + options: GradlePluginOptions | undefined, + context: CreateNodesContext, + testFiles = [] +) { + try { + const { + gradleProjectToTasksTypeMap, + gradleProjectToTasksMap, + gradleFileToOutputDirsMap, + gradleFileToGradleProjectMap, + gradleProjectToProjectName, + } = gradleReport; + + const gradleProject = gradleFileToGradleProjectMap.get( + gradleFilePath + ) as string; + const projectName = gradleProjectToProjectName.get(gradleProject); + if (!projectName) { + return; + } + + const tasksTypeMap: Map = gradleProjectToTasksTypeMap.get( + gradleProject + ) as Map; + const tasksSet = gradleProjectToTasksMap.get(gradleProject) as Set; + let tasks: GradleTask[] = []; + tasksSet.forEach((taskName) => { + tasks.push({ + type: tasksTypeMap?.get(taskName) as string, + name: taskName, + }); + }); + if (options.includeSubprojectsTasks) { + tasksTypeMap.forEach((taskType, taskName) => { + if (!tasksSet.has(taskName)) { + tasks.push({ + type: taskType, + name: taskName, + }); + } + }); + } + + const outputDirs = gradleFileToOutputDirsMap.get(gradleFilePath) as Map< + string, + string + >; + + const { targets, targetGroups } = await createGradleTargets( + tasks, + options, + context, + outputDirs, + gradleProject, + gradleFilePath, + testFiles + ); + const project: Partial = { + name: projectName, + projectType: 'application', + targets, + metadata: { + targetGroups, + technologies: ['gradle'], + }, + }; + + return project; + } catch (e) { + console.error(e); + return undefined; + } +} + +async function createGradleTargets( + tasks: GradleTask[], + options: GradlePluginOptions | undefined, + context: CreateNodesContext, + outputDirs: Map, + gradleProject: string, + gradleBuildFilePath: string, + testFiles: string[] = [] +): Promise<{ + targetGroups: Record; + targets: Record; +}> { + const inputsMap = createInputsMap(context); + const gradlewFileDirectory = dirname( + findGradlewFile(gradleBuildFilePath, context.workspaceRoot) + ); + + const targets: Record = {}; + const targetGroups: Record = {}; + for (const task of tasks) { + const targetName = options?.[`${task.name}TargetName`] ?? task.name; + + let outputs = [outputDirs.get(task.name)].filter(Boolean); + if (task.name === 'test') { + outputs = [ + outputDirs.get('testReport'), + outputDirs.get('testResults'), + ].filter(Boolean); + getTestCiTargets( + testFiles, + gradleProject, + targetName as string, + options.ciTargetName, + inputsMap['test'], + outputs, + task.type, + targets, + targetGroups, + gradlewFileDirectory + ); + } + + const taskCommandToRun = `${gradleProject ? gradleProject + ':' : ''}${ + task.name + }`; + + targets[targetName as string] = { + command: `${getGradleExecFile()} ${taskCommandToRun}`, + options: { + cwd: gradlewFileDirectory, + }, + cache: cacheableTaskType.has(task.type), + inputs: inputsMap[task.name], + dependsOn: dependsOnMap[task.name], + metadata: { + technologies: ['gradle'], + help: { + command: `${getGradleExecFile()} help --task ${taskCommandToRun}`, + example: { + options: { + args: ['--rerun'], + }, + }, + }, + }, + ...(outputs && outputs.length ? { outputs } : {}), + }; + + if (task.type) { + if (!targetGroups[task.type]) { + targetGroups[task.type] = []; + } + targetGroups[task.type].push(targetName as string); + } + } + return { targetGroups, targets }; +} + +function createInputsMap( + context: CreateNodesContext +): Record { + const namedInputs = context.nxJsonConfiguration.namedInputs; + return { + build: namedInputs?.production + ? ['production', '^production'] + : ['default', '^default'], + test: ['default', namedInputs?.production ? '^production' : '^default'], + classes: namedInputs?.production + ? ['production', '^production'] + : ['default', '^default'], + }; +} + +function getTestCiTargets( + testFiles: string[], + gradleProject: string, + testTargetName: string, + ciTargetName: string, + inputs: TargetConfiguration['inputs'], + outputs: string[], + targetGroupName: string, + targets: Record, + targetGroups: Record, + gradlewFileDirectory: string +): void { + if (!testFiles || testFiles.length === 0 || !ciTargetName) { + return; + } + const taskCommandToRun = `${gradleProject ? gradleProject + ':' : ''}test`; + + if (!targetGroups[targetGroupName]) { + targetGroups[targetGroupName] = []; + } + + const dependsOn: TargetConfiguration['dependsOn'] = []; + testFiles.forEach((testFile) => { + const testName = basename(testFile).split('.')[0]; + const targetName = ciTargetName + '--' + testName; + + targets[targetName] = { + command: `${getGradleExecFile()} ${taskCommandToRun} --tests ${testName}`, + options: { + cwd: gradlewFileDirectory, + }, + cache: true, + inputs, + dependsOn: dependsOnMap['test'], + metadata: { + technologies: ['gradle'], + description: `Runs Gradle test ${testFile} in CI`, + help: { + command: `${getGradleExecFile()} help --task ${taskCommandToRun}`, + example: { + options: { + args: ['--rerun'], + }, + }, + }, + }, + ...(outputs && outputs.length > 0 ? { outputs } : {}), + }; + targetGroups[targetGroupName].push(targetName); + dependsOn.push({ + target: targetName, + projects: 'self', + params: 'forward', + }); + }); + + targets[ciTargetName] = { + executor: 'nx:noop', + cache: true, + inputs, + dependsOn: dependsOn, + ...(outputs && outputs.length > 0 ? { outputs } : {}), + metadata: { + technologies: ['gradle'], + description: 'Runs Gradle Tests in CI', + nonAtomizedTarget: testTargetName, + help: { + command: `${getGradleExecFile()} help --task ${taskCommandToRun}`, + example: { + options: { + args: ['--rerun'], + }, + }, + }, + }, + }; + targetGroups[targetGroupName].push(ciTargetName); +} + +function getGradleProjectRootToTestFilesMap( + testFiles: string[], + projectRoots: string[] +): Record | undefined { + if (testFiles.length === 0 || projectRoots.length === 0) { + return; + } + const roots = new Map(projectRoots.map((root) => [root, root])); + const testFilesToGradleProjectMap: Record = {}; + testFiles.forEach((testFile) => { + const projectRoot = findProjectForPath(testFile, roots); + if (projectRoot) { + if (!testFilesToGradleProjectMap[projectRoot]) { + testFilesToGradleProjectMap[projectRoot] = []; + } + testFilesToGradleProjectMap[projectRoot].push(testFile); + } + }); + return testFilesToGradleProjectMap; +} diff --git a/packages/gradle/src/utils/__mocks__/gradle-composite-dependencies.txt b/packages/gradle/src/plugin-v1/utils/__mocks__/gradle-composite-dependencies.txt similarity index 100% rename from packages/gradle/src/utils/__mocks__/gradle-composite-dependencies.txt rename to packages/gradle/src/plugin-v1/utils/__mocks__/gradle-composite-dependencies.txt diff --git a/packages/gradle/src/utils/__mocks__/gradle-custom-dependencies.txt b/packages/gradle/src/plugin-v1/utils/__mocks__/gradle-custom-dependencies.txt similarity index 100% rename from packages/gradle/src/utils/__mocks__/gradle-custom-dependencies.txt rename to packages/gradle/src/plugin-v1/utils/__mocks__/gradle-custom-dependencies.txt diff --git a/packages/gradle/src/utils/__mocks__/gradle-dependencies.txt b/packages/gradle/src/plugin-v1/utils/__mocks__/gradle-dependencies.txt similarity index 100% rename from packages/gradle/src/utils/__mocks__/gradle-dependencies.txt rename to packages/gradle/src/plugin-v1/utils/__mocks__/gradle-dependencies.txt diff --git a/packages/gradle/src/utils/__mocks__/gradle-project-report-println.txt b/packages/gradle/src/plugin-v1/utils/__mocks__/gradle-project-report-println.txt similarity index 57% rename from packages/gradle/src/utils/__mocks__/gradle-project-report-println.txt rename to packages/gradle/src/plugin-v1/utils/__mocks__/gradle-project-report-println.txt index 25aea1d09d..3f0854d474 100644 --- a/packages/gradle/src/utils/__mocks__/gradle-project-report-println.txt +++ b/packages/gradle/src/plugin-v1/utils/__mocks__/gradle-project-report-println.txt @@ -1,8 +1,5 @@ > Task :dependencyReport -See the report at: file:///tmp/build/reports/project/dependencies.txt - -> Task :htmlDependencyReport -See the report at: file:///tmp/build/reports/project/dependencies/index.html +See the report at: file://__dirname__/__mocks__/gradle-dependencies.txt > Task :propertyReport See the report at: file:///tmp/build/reports/project/properties.txt @@ -11,10 +8,7 @@ See the report at: file:///tmp/build/reports/project/properties.txt See the report at: file:///tmp/build/reports/project/tasks.txt > Task :app:dependencyReport -See the report at: file:///tmp/app/build/reports/project/dependencies.txt - -> Task :app:htmlDependencyReport -See the report at: file:///tmp/app/build/reports/project/dependencies/index.html +See the report at: file://__dirname__/__mocks__/gradle-dependencies.txt > Task :app:propertyReport See the report at: file:///tmp/app/build/reports/project/properties.txt @@ -25,10 +19,7 @@ NAMED TASK1: This is executed during the configuration phase See the report at: file:///tmp/app/build/reports/project/tasks.txt > Task :list:dependencyReport -See the report at: file:///tmp/list/build/reports/project/dependencies.txt - -> Task :list:htmlDependencyReport -See the report at: file:///tmp/list/build/reports/project/dependencies/index.html +See the report at: file://__dirname__/__mocks__/gradle-dependencies.txt > Task :list:propertyReport See the report at: file:///tmp/list/build/reports/project/properties.txt @@ -37,10 +28,7 @@ See the report at: file:///tmp/list/build/reports/project/properties.txt See the report at: file:///tmp/list/build/reports/project/tasks.txt > Task :utilities:dependencyReport -See the report at: file:///tmp/utilities/build/reports/project/dependencies.txt - -> Task :utilities:htmlDependencyReport -See the report at: file:///tmp/utilities/build/reports/project/dependencies/index.html +See the report at: file://__dirname__/__mocks__/gradle-dependencies.txt > Task :utilities:propertyReport See the report at: file:///tmp/utilities/build/reports/project/properties.txt diff --git a/packages/gradle/src/utils/__mocks__/gradle-project-report.txt b/packages/gradle/src/plugin-v1/utils/__mocks__/gradle-project-report.txt similarity index 67% rename from packages/gradle/src/utils/__mocks__/gradle-project-report.txt rename to packages/gradle/src/plugin-v1/utils/__mocks__/gradle-project-report.txt index 9d961171cf..27632b2b6c 100644 --- a/packages/gradle/src/utils/__mocks__/gradle-project-report.txt +++ b/packages/gradle/src/plugin-v1/utils/__mocks__/gradle-project-report.txt @@ -1,5 +1,5 @@ > Task :dependencyReport -See the report at: file:///tmp/build/reports/project/dependencies.txt +See the report at: file://__dirname__/__mocks__/gradle-dependencies.txt > Task :htmlDependencyReport See the report at: file:///tmp/build/reports/project/dependencies/index.html @@ -11,10 +11,7 @@ See the report at: file:///tmp/build/reports/project/properties.txt See the report at: file:///tmp/build/reports/project/tasks.txt > Task :app:dependencyReport -See the report at: file:///tmp/app/build/reports/project/dependencies.txt - -> Task :app:htmlDependencyReport -See the report at: file:///tmp/app/build/reports/project/dependencies/index.html +See the report at: file://__dirname__/__mocks__/gradle-dependencies.txt > Task :app:propertyReport See the report at: file:///tmp/app/build/reports/project/properties.txt @@ -23,7 +20,7 @@ See the report at: file:///tmp/app/build/reports/project/properties.txt See the report at: file:///tmp/app/build/reports/project/tasks.txt > Task :list:dependencyReport -See the report at: file:///tmp/list/build/reports/project/dependencies.txt +See the report at: file://__dirname__/__mocks__/gradle-dependencies.txt > Task :list:htmlDependencyReport See the report at: file:///tmp/list/build/reports/project/dependencies/index.html @@ -35,10 +32,7 @@ See the report at: file:///tmp/list/build/reports/project/properties.txt See the report at: file:///tmp/list/build/reports/project/tasks.txt > Task :utilities:dependencyReport -See the report at: file:///tmp/utilities/build/reports/project/dependencies.txt - -> Task :utilities:htmlDependencyReport -See the report at: file:///tmp/utilities/build/reports/project/dependencies/index.html +See the report at: file://__dirname__/__mocks__/gradle-dependencies.txt > Task :utilities:propertyReport See the report at: file:///tmp/utilities/build/reports/project/properties.txt diff --git a/packages/gradle/src/utils/__mocks__/gradle-properties-report-child-projects.txt b/packages/gradle/src/plugin-v1/utils/__mocks__/gradle-properties-report-child-projects.txt similarity index 100% rename from packages/gradle/src/utils/__mocks__/gradle-properties-report-child-projects.txt rename to packages/gradle/src/plugin-v1/utils/__mocks__/gradle-properties-report-child-projects.txt diff --git a/packages/gradle/src/utils/__mocks__/gradle-properties-report-no-child-projects.txt b/packages/gradle/src/plugin-v1/utils/__mocks__/gradle-properties-report-no-child-projects.txt similarity index 100% rename from packages/gradle/src/utils/__mocks__/gradle-properties-report-no-child-projects.txt rename to packages/gradle/src/plugin-v1/utils/__mocks__/gradle-properties-report-no-child-projects.txt diff --git a/packages/gradle/src/utils/get-gradle-report.spec.ts b/packages/gradle/src/plugin-v1/utils/get-gradle-report.spec.ts similarity index 65% rename from packages/gradle/src/utils/get-gradle-report.spec.ts rename to packages/gradle/src/plugin-v1/utils/get-gradle-report.spec.ts index 80af85c937..cba5c9bdaa 100644 --- a/packages/gradle/src/utils/get-gradle-report.spec.ts +++ b/packages/gradle/src/plugin-v1/utils/get-gradle-report.spec.ts @@ -1,31 +1,103 @@ import { readFileSync } from 'fs'; +import { fileSync } from 'tmp'; import { join } from 'path'; import { processGradleDependencies, processProjectReports, + writeGradleReportToCache, } from './get-gradle-report'; describe('processProjectReports', () => { + const tmpFile = fileSync(); + it('should process project reports', () => { const projectReportLines = readFileSync( join(__dirname, '__mocks__/gradle-project-report.txt'), 'utf-8' - ).split('\n'); + ) + .replaceAll('__dirname__', __dirname) + .split('\n'); const report = processProjectReports(projectReportLines); expect( Object.keys(Object.fromEntries(report.gradleProjectToTasksTypeMap)) ).toEqual(['', ':app', ':list', ':utilities']); + + writeGradleReportToCache(tmpFile.name, report); + expect(readFileSync(tmpFile.name).toString()).toMatchInlineSnapshot(` + "{ + "gradleFileToGradleProjectMap": {}, + "gradleProjectToDepsMap": { + "": [ + ":utilities" + ], + ":app": [ + ":utilities" + ], + ":list": [ + ":utilities" + ], + ":utilities": [ + ":utilities" + ] + }, + "gradleFileToOutputDirsMap": {}, + "gradleProjectToTasksTypeMap": { + "": {}, + ":app": {}, + ":list": {}, + ":utilities": {} + }, + "gradleProjectToTasksMap": {}, + "gradleProjectToProjectName": {}, + "gradleProjectNameToProjectRootMap": {}, + "gradleProjectToChildProjects": {} + }" + `); }); it('should process project reports with println', () => { const projectReportLines = readFileSync( join(__dirname, '__mocks__/gradle-project-report-println.txt'), 'utf-8' - ).split('\n'); + ) + .replaceAll('__dirname__', __dirname) + .split('\n'); const report = processProjectReports(projectReportLines); expect( Object.keys(Object.fromEntries(report.gradleProjectToTasksTypeMap)) ).toEqual(['', ':app', ':list', ':utilities']); + + writeGradleReportToCache(tmpFile.name, report); + expect(readFileSync(tmpFile.name).toString()).toMatchInlineSnapshot(` + "{ + "gradleFileToGradleProjectMap": {}, + "gradleProjectToDepsMap": { + "": [ + ":utilities" + ], + ":app": [ + ":utilities" + ], + ":list": [ + ":utilities" + ], + ":utilities": [ + ":utilities" + ] + }, + "gradleFileToOutputDirsMap": {}, + "gradleProjectToTasksTypeMap": { + "": {}, + ":app": {}, + ":list": {}, + ":utilities": {} + }, + "gradleProjectToTasksMap": {}, + "gradleProjectToProjectName": {}, + "gradleProjectNameToProjectRootMap": {}, + "gradleProjectToChildProjects": {} + }" + `); }); it('should process properties report with child projects', () => { diff --git a/packages/gradle/src/utils/get-gradle-report.ts b/packages/gradle/src/plugin-v1/utils/get-gradle-report.ts similarity index 93% rename from packages/gradle/src/utils/get-gradle-report.ts rename to packages/gradle/src/plugin-v1/utils/get-gradle-report.ts index d518cd47b7..0d7bcaae7f 100644 --- a/packages/gradle/src/utils/get-gradle-report.ts +++ b/packages/gradle/src/plugin-v1/utils/get-gradle-report.ts @@ -11,18 +11,15 @@ import { import { hashWithWorkspaceContext } from 'nx/src/utils/workspace-context'; import { dirname } from 'path'; -import { gradleConfigAndTestGlob } from './split-config-files'; -import { - getProjectReportLines, - fileSeparator, - newLineSeparator, -} from './get-project-report-lines'; +import { gradleConfigAndTestGlob } from '../../utils/split-config-files'; +import { getProjectReportLines } from './get-project-report-lines'; import { workspaceDataDirectory } from 'nx/src/utils/cache-directory'; +import { fileSeparator, newLineSeparator } from '../../utils/exec-gradle'; export interface GradleReport { gradleFileToGradleProjectMap: Map; - buildFileToDepsMap: Map>; gradleFileToOutputDirsMap: Map>; + gradleProjectToDepsMap: Map>; gradleProjectToTasksTypeMap: Map>; gradleProjectToTasksMap: Map>; gradleProjectToProjectName: Map; @@ -33,7 +30,7 @@ export interface GradleReport { export interface GradleReportJSON { hash: string; gradleFileToGradleProjectMap: Record; - buildFileToDepsMap: Record>; + gradleProjectToDepsMap: Record>; gradleFileToOutputDirsMap: Record>; gradleProjectToTasksTypeMap: Record>; gradleProjectToTasksMap: Record>; @@ -56,8 +53,10 @@ function readGradleReportCache( gradleFileToGradleProjectMap: new Map( Object.entries(gradleReportJson['gradleFileToGradleProjectMap']) ), - buildFileToDepsMap: new Map( - Object.entries(gradleReportJson['buildFileToDepsMap']) + gradleProjectToDepsMap: new Map( + Object.entries(gradleReportJson['gradleProjectToDepsMap']).map( + ([key, value]) => [key, new Set(value)] + ) ), gradleFileToOutputDirsMap: new Map( Object.entries(gradleReportJson['gradleFileToOutputDirsMap']).map( @@ -96,7 +95,12 @@ export function writeGradleReportToCache( gradleFileToGradleProjectMap: Object.fromEntries( results.gradleFileToGradleProjectMap ), - buildFileToDepsMap: Object.fromEntries(results.buildFileToDepsMap), + gradleProjectToDepsMap: Object.fromEntries( + Array.from(results.gradleProjectToDepsMap).map(([key, value]) => [ + key, + Array.from(value), + ]) + ), gradleFileToOutputDirsMap: Object.fromEntries( Array.from(results.gradleFileToOutputDirsMap).map(([key, value]) => [ key, @@ -215,7 +219,7 @@ export function processProjectReports( * Map of Gradle File path to Gradle Project Name */ const gradleFileToGradleProjectMap = new Map(); - const dependenciesMap = new Map(); + const gradleProjectToDepsMap = new Map>(); /** * Map of Gradle Build File to tasks type map */ @@ -223,10 +227,6 @@ export function processProjectReports( const gradleProjectToTasksMap = new Map>(); const gradleProjectToProjectName = new Map(); const gradleProjectNameToProjectRootMap = new Map(); - /** - * Map of buildFile to dependencies report path - */ - const buildFileToDepsMap = new Map>(); /** * Map fo possible output files of each gradle file * e.g. {build.gradle.kts: { projectReportDir: '' testReportDir: '' }} @@ -253,7 +253,10 @@ export function processProjectReports( index++; } const [_, file] = projectReportLines[index].split(fileSeparator); - dependenciesMap.set(gradleProject, file); + gradleProjectToDepsMap.set( + gradleProject, + processGradleDependencies(file) + ); } if (line.endsWith('propertyReport')) { const gradleProject = line.substring( @@ -320,13 +323,6 @@ export function processProjectReports( relative(workspaceRoot, absBuildFilePath) ); const buildDir = relative(workspaceRoot, absBuildDirPath); - const depsFile = dependenciesMap.get(gradleProject); - if (depsFile) { - buildFileToDepsMap.set( - buildFile, - processGradleDependencies(depsFile) - ); - } outputDirMap.set('build', `{workspaceRoot}/${buildDir}`); outputDirMap.set( @@ -389,9 +385,9 @@ export function processProjectReports( return { gradleFileToGradleProjectMap, - buildFileToDepsMap, gradleFileToOutputDirsMap, gradleProjectToTasksTypeMap, + gradleProjectToDepsMap, gradleProjectToTasksMap, gradleProjectToProjectName, gradleProjectNameToProjectRootMap, diff --git a/packages/gradle/src/utils/get-project-report-lines.ts b/packages/gradle/src/plugin-v1/utils/get-project-report-lines.ts similarity index 87% rename from packages/gradle/src/utils/get-project-report-lines.ts rename to packages/gradle/src/plugin-v1/utils/get-project-report-lines.ts index 3c5ae4606b..78d434c589 100644 --- a/packages/gradle/src/utils/get-project-report-lines.ts +++ b/packages/gradle/src/plugin-v1/utils/get-project-report-lines.ts @@ -1,16 +1,7 @@ import { AggregateCreateNodesError, logger, output } from '@nx/devkit'; -import { execGradleAsync } from './exec-gradle'; +import { execGradleAsync, newLineSeparator } from '../../utils/exec-gradle'; import { existsSync } from 'fs'; import { dirname, join } from 'path'; -import { execSync } from 'child_process'; - -export const fileSeparator = process.platform.startsWith('win') - ? 'file:///' - : 'file://'; - -export const newLineSeparator = process.platform.startsWith('win') - ? '\r\n' - : '\n'; /** * This function executes the gradle projectReportAll task and returns the output as an array of lines. @@ -21,8 +12,6 @@ export async function getProjectReportLines( gradlewFile: string ): Promise { let projectReportBuffer: Buffer; - - // Attempt to run projectReport or projectReportAll task, regardless of build.gradle or build.gradle.kts location try { projectReportBuffer = await execGradleAsync(gradlewFile, [ 'projectReportAll', diff --git a/packages/gradle/src/plugin/__snapshots__/nodes.spec.ts.snap b/packages/gradle/src/plugin/__snapshots__/nodes.spec.ts.snap new file mode 100644 index 0000000000..620e9490da --- /dev/null +++ b/packages/gradle/src/plugin/__snapshots__/nodes.spec.ts.snap @@ -0,0 +1,849 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`@nx/gradle/plugin/nodes should create nodes based on gradle 1`] = ` +[ + [ + "proj/build.gradle", + { + "externalNodes": {}, + "projects": { + "proj": { + "metadata": { + "targetGroups": { + "help": [ + "buildEnvironment", + ], + }, + "technologies": [ + "gradle", + ], + }, + "name": "gradle-tutorial", + "root": "proj", + "targets": { + "buildEnvironment": { + "cache": true, + "command": "./gradlew :buildEnvironment", + "metadata": { + "description": "Displays all buildscript dependencies declared in root project 'gradle-tutorial'.", + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": "proj", + }, + }, + }, + }, + }, + }, + ], +] +`; + +exports[`@nx/gradle/plugin/nodes should create nodes based on gradle for nested project root 1`] = ` +[ + [ + "nested/nested/proj/build.gradle", + { + "externalNodes": {}, + "projects": { + "nested/nested/proj": { + "metadata": { + "targetGroups": { + "help": [ + "buildEnvironment", + ], + }, + "technologies": [ + "gradle", + ], + }, + "name": "my-composite", + "root": "nested/nested/proj", + "targets": { + "buildEnvironment": { + "cache": true, + "command": "./gradlew :buildEnvironment", + "metadata": { + "description": "Displays all buildscript dependencies declared in root project 'my-composite'.", + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": "nested/nested/proj", + }, + }, + }, + }, + }, + }, + ], +] +`; + +exports[`@nx/gradle/plugin/nodes should create nodes with atomized tests targets based on gradle if ciTargetName is specified 1`] = ` +[ + [ + "proj/application/build.gradle", + { + "externalNodes": {}, + "projects": { + "proj/application": { + "metadata": { + "targetGroups": { + "verification": [ + "ci", + ], + }, + "technologies": [ + "gradle", + ], + }, + "name": "application", + "root": "proj/application", + "targets": { + "ci": { + "cache": true, + "dependsOn": [ + { + "params": "forward", + "projects": "self", + "target": "ci--DemoApplicationTest10", + }, + { + "params": "forward", + "projects": "self", + "target": "ci--DemoApplicationTest7", + }, + { + "params": "forward", + "projects": "self", + "target": "ci--DemoApplicationTest6", + }, + { + "params": "forward", + "projects": "self", + "target": "ci--DemoApplicationTest3", + }, + { + "params": "forward", + "projects": "self", + "target": "ci--DemoApplicationTest2", + }, + { + "params": "forward", + "projects": "self", + "target": "ci--DemoApplicationTest9", + }, + { + "params": "forward", + "projects": "self", + "target": "ci--DemoApplicationTest", + }, + { + "params": "forward", + "projects": "self", + "target": "ci--DemoApplicationTest5", + }, + { + "params": "forward", + "projects": "self", + "target": "ci--DemoApplicationTest4", + }, + { + "params": "forward", + "projects": "self", + "target": "ci--DemoApplicationTest8", + }, + ], + "executor": "nx:noop", + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest10.java", + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest7.java", + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest6.java", + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest3.java", + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest2.java", + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest9.java", + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest.java", + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest5.java", + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest4.java", + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest8.java", + ], + "metadata": { + "description": "Runs Gradle Tests in CI", + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": "proj", + }, + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin", + ], + }, + "ci--DemoApplicationTest": { + "cache": true, + "command": "./gradlew :application:test --tests DemoApplicationTest", + "dependsOn": [ + "application:classes", + "application:compileJava", + "library:jar", + ], + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest.java", + ], + "metadata": { + "description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest.java in CI", + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": "proj", + }, + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin", + ], + }, + "ci--DemoApplicationTest10": { + "cache": true, + "command": "./gradlew :application:test --tests DemoApplicationTest10", + "dependsOn": [ + "application:classes", + "application:compileJava", + "library:jar", + ], + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest10.java", + ], + "metadata": { + "description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest10.java in CI", + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": "proj", + }, + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin", + ], + }, + "ci--DemoApplicationTest2": { + "cache": true, + "command": "./gradlew :application:test --tests DemoApplicationTest2", + "dependsOn": [ + "application:classes", + "application:compileJava", + "library:jar", + ], + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest2.java", + ], + "metadata": { + "description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest2.java in CI", + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": "proj", + }, + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin", + ], + }, + "ci--DemoApplicationTest3": { + "cache": true, + "command": "./gradlew :application:test --tests DemoApplicationTest3", + "dependsOn": [ + "application:classes", + "application:compileJava", + "library:jar", + ], + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest3.java", + ], + "metadata": { + "description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest3.java in CI", + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": "proj", + }, + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin", + ], + }, + "ci--DemoApplicationTest4": { + "cache": true, + "command": "./gradlew :application:test --tests DemoApplicationTest4", + "dependsOn": [ + "application:classes", + "application:compileJava", + "library:jar", + ], + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest4.java", + ], + "metadata": { + "description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest4.java in CI", + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": "proj", + }, + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin", + ], + }, + "ci--DemoApplicationTest5": { + "cache": true, + "command": "./gradlew :application:test --tests DemoApplicationTest5", + "dependsOn": [ + "application:classes", + "application:compileJava", + "library:jar", + ], + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest5.java", + ], + "metadata": { + "description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest5.java in CI", + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": "proj", + }, + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin", + ], + }, + "ci--DemoApplicationTest6": { + "cache": true, + "command": "./gradlew :application:test --tests DemoApplicationTest6", + "dependsOn": [ + "application:classes", + "application:compileJava", + "library:jar", + ], + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest6.java", + ], + "metadata": { + "description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest6.java in CI", + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": "proj", + }, + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin", + ], + }, + "ci--DemoApplicationTest7": { + "cache": true, + "command": "./gradlew :application:test --tests DemoApplicationTest7", + "dependsOn": [ + "application:classes", + "application:compileJava", + "library:jar", + ], + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest7.java", + ], + "metadata": { + "description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest7.java in CI", + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": "proj", + }, + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin", + ], + }, + "ci--DemoApplicationTest8": { + "cache": true, + "command": "./gradlew :application:test --tests DemoApplicationTest8", + "dependsOn": [ + "application:classes", + "application:compileJava", + "library:jar", + ], + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest8.java", + ], + "metadata": { + "description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest8.java in CI", + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": "proj", + }, + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin", + ], + }, + "ci--DemoApplicationTest9": { + "cache": true, + "command": "./gradlew :application:test --tests DemoApplicationTest9", + "dependsOn": [ + "application:classes", + "application:compileJava", + "library:jar", + ], + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest9.java", + ], + "metadata": { + "description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest9.java in CI", + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": "proj", + }, + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin", + ], + }, + }, + }, + }, + }, + ], +] +`; + +exports[`@nx/gradle/plugin/nodes should not create nodes with atomized tests targets based on gradle if ciTargetName is not specified 1`] = ` +[ + [ + "proj/application/build.gradle", + { + "externalNodes": {}, + "projects": { + "proj/application": { + "metadata": { + "targetGroups": { + "verification": [ + "ci", + ], + }, + "technologies": [ + "gradle", + ], + }, + "name": "application", + "root": "proj/application", + "targets": { + "ci": { + "cache": true, + "dependsOn": [ + { + "params": "forward", + "projects": "self", + "target": "ci--DemoApplicationTest10", + }, + { + "params": "forward", + "projects": "self", + "target": "ci--DemoApplicationTest7", + }, + { + "params": "forward", + "projects": "self", + "target": "ci--DemoApplicationTest6", + }, + { + "params": "forward", + "projects": "self", + "target": "ci--DemoApplicationTest3", + }, + { + "params": "forward", + "projects": "self", + "target": "ci--DemoApplicationTest2", + }, + { + "params": "forward", + "projects": "self", + "target": "ci--DemoApplicationTest9", + }, + { + "params": "forward", + "projects": "self", + "target": "ci--DemoApplicationTest", + }, + { + "params": "forward", + "projects": "self", + "target": "ci--DemoApplicationTest5", + }, + { + "params": "forward", + "projects": "self", + "target": "ci--DemoApplicationTest4", + }, + { + "params": "forward", + "projects": "self", + "target": "ci--DemoApplicationTest8", + }, + ], + "executor": "nx:noop", + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest10.java", + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest7.java", + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest6.java", + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest3.java", + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest2.java", + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest9.java", + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest.java", + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest5.java", + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest4.java", + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest8.java", + ], + "metadata": { + "description": "Runs Gradle Tests in CI", + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": "proj", + }, + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin", + ], + }, + "ci--DemoApplicationTest": { + "cache": true, + "command": "./gradlew :application:test --tests DemoApplicationTest", + "dependsOn": [ + "application:classes", + "application:compileJava", + "library:jar", + ], + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest.java", + ], + "metadata": { + "description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest.java in CI", + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": "proj", + }, + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin", + ], + }, + "ci--DemoApplicationTest10": { + "cache": true, + "command": "./gradlew :application:test --tests DemoApplicationTest10", + "dependsOn": [ + "application:classes", + "application:compileJava", + "library:jar", + ], + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest10.java", + ], + "metadata": { + "description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest10.java in CI", + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": "proj", + }, + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin", + ], + }, + "ci--DemoApplicationTest2": { + "cache": true, + "command": "./gradlew :application:test --tests DemoApplicationTest2", + "dependsOn": [ + "application:classes", + "application:compileJava", + "library:jar", + ], + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest2.java", + ], + "metadata": { + "description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest2.java in CI", + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": "proj", + }, + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin", + ], + }, + "ci--DemoApplicationTest3": { + "cache": true, + "command": "./gradlew :application:test --tests DemoApplicationTest3", + "dependsOn": [ + "application:classes", + "application:compileJava", + "library:jar", + ], + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest3.java", + ], + "metadata": { + "description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest3.java in CI", + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": "proj", + }, + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin", + ], + }, + "ci--DemoApplicationTest4": { + "cache": true, + "command": "./gradlew :application:test --tests DemoApplicationTest4", + "dependsOn": [ + "application:classes", + "application:compileJava", + "library:jar", + ], + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest4.java", + ], + "metadata": { + "description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest4.java in CI", + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": "proj", + }, + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin", + ], + }, + "ci--DemoApplicationTest5": { + "cache": true, + "command": "./gradlew :application:test --tests DemoApplicationTest5", + "dependsOn": [ + "application:classes", + "application:compileJava", + "library:jar", + ], + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest5.java", + ], + "metadata": { + "description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest5.java in CI", + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": "proj", + }, + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin", + ], + }, + "ci--DemoApplicationTest6": { + "cache": true, + "command": "./gradlew :application:test --tests DemoApplicationTest6", + "dependsOn": [ + "application:classes", + "application:compileJava", + "library:jar", + ], + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest6.java", + ], + "metadata": { + "description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest6.java in CI", + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": "proj", + }, + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin", + ], + }, + "ci--DemoApplicationTest7": { + "cache": true, + "command": "./gradlew :application:test --tests DemoApplicationTest7", + "dependsOn": [ + "application:classes", + "application:compileJava", + "library:jar", + ], + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest7.java", + ], + "metadata": { + "description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest7.java in CI", + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": "proj", + }, + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin", + ], + }, + "ci--DemoApplicationTest8": { + "cache": true, + "command": "./gradlew :application:test --tests DemoApplicationTest8", + "dependsOn": [ + "application:classes", + "application:compileJava", + "library:jar", + ], + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest8.java", + ], + "metadata": { + "description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest8.java in CI", + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": "proj", + }, + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin", + ], + }, + "ci--DemoApplicationTest9": { + "cache": true, + "command": "./gradlew :application:test --tests DemoApplicationTest9", + "dependsOn": [ + "application:classes", + "application:compileJava", + "library:jar", + ], + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest9.java", + ], + "metadata": { + "description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest9.java in CI", + "technologies": [ + "gradle", + ], + }, + "options": { + "cwd": "proj", + }, + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin", + ], + }, + }, + }, + }, + }, + ], +] +`; diff --git a/packages/gradle/src/plugin/dependencies.ts b/packages/gradle/src/plugin/dependencies.ts index 24d5003b2c..65b2e21673 100644 --- a/packages/gradle/src/plugin/dependencies.ts +++ b/packages/gradle/src/plugin/dependencies.ts @@ -2,94 +2,71 @@ import { CreateDependencies, CreateDependenciesContext, DependencyType, - FileMap, - RawProjectGraphDependency, + logger, + normalizePath, + StaticDependency, validateDependency, + workspaceRoot, } from '@nx/devkit'; -import { basename, dirname } from 'node:path'; +import { relative } from 'node:path'; -import { getCurrentGradleReport } from '../utils/get-gradle-report'; -import { GRADLE_BUILD_FILES } from '../utils/split-config-files'; +import { + getCurrentProjectGraphReport, + populateProjectGraph, +} from './utils/get-project-graph-from-gradle-plugin'; +import { GradlePluginOptions } from './utils/gradle-plugin-options'; +import { GRALDEW_FILES, splitConfigFiles } from '../utils/split-config-files'; +import { globWithWorkspaceContext } from 'nx/src/utils/workspace-context'; -export const createDependencies: CreateDependencies = async ( - _, +export const createDependencies: CreateDependencies< + GradlePluginOptions +> = async ( + options: GradlePluginOptions, context: CreateDependenciesContext ) => { - const gradleFiles: string[] = findGradleFiles(context.filesToProcess); - if (gradleFiles.length === 0) { - return []; - } - - const gradleDependenciesStart = performance.mark('gradleDependencies:start'); - const { - gradleFileToGradleProjectMap, - gradleProjectNameToProjectRootMap, - buildFileToDepsMap, - gradleProjectToChildProjects, - } = getCurrentGradleReport(); - const dependencies: Set = new Set(); - - for (const gradleFile of gradleFiles) { - const gradleProject = gradleFileToGradleProjectMap.get(gradleFile); - const projectName = Object.values(context.projects).find( - (project) => project.root === dirname(gradleFile) - )?.name; - const dependedProjects: Set = buildFileToDepsMap.get(gradleFile); - - if (projectName && dependedProjects?.size) { - dependedProjects?.forEach((dependedProject) => { - const targetProjectRoot = gradleProjectNameToProjectRootMap.get( - dependedProject - ) as string; - const targetProjectName = Object.values(context.projects).find( - (project) => project.root === targetProjectRoot - )?.name; - if (targetProjectName) { - const dependency: RawProjectGraphDependency = { - source: projectName as string, - target: targetProjectName as string, - type: DependencyType.static, - sourceFile: gradleFile, - }; - validateDependency(dependency, context); - dependencies.add(dependency); - } - }); - } - gradleProjectToChildProjects.get(gradleProject)?.forEach((childProject) => { - if (childProject) { - const dependency: RawProjectGraphDependency = { - source: projectName as string, - target: childProject, - type: DependencyType.static, - sourceFile: gradleFile, - }; - validateDependency(dependency, context); - dependencies.add(dependency); - } - }); - } - - const gradleDependenciesEnd = performance.mark('gradleDependencies:end'); - performance.measure( - 'gradleDependencies', - gradleDependenciesStart.name, - gradleDependenciesEnd.name + const files = await globWithWorkspaceContext( + workspaceRoot, + Array.from(GRALDEW_FILES) ); + const { gradlewFiles } = splitConfigFiles(files); + await populateProjectGraph(context.workspaceRoot, gradlewFiles, options); + const { dependencies: dependenciesFromReport } = + getCurrentProjectGraphReport(); - return Array.from(dependencies); -}; - -function findGradleFiles(fileMap: FileMap): string[] { - const gradleFiles: string[] = []; - - for (const [_, files] of Object.entries(fileMap.projectFileMap)) { - for (const file of files) { - if (GRADLE_BUILD_FILES.has(basename(file.file))) { - gradleFiles.push(file.file); + const dependencies: Array = []; + dependenciesFromReport.forEach((dependencyFromPlugin: StaticDependency) => { + try { + const source = + relative(workspaceRoot, dependencyFromPlugin.source) || '.'; + const sourceProjectName = + Object.values(context.projects).find( + (project) => source === project.root + )?.name ?? dependencyFromPlugin.source; + const target = + relative(workspaceRoot, dependencyFromPlugin.target) || '.'; + const targetProjectName = + Object.values(context.projects).find( + (project) => target === project.root + )?.name ?? dependencyFromPlugin.target; + if (!sourceProjectName || !targetProjectName) { + return; } + const dependency: StaticDependency = { + source: sourceProjectName, + target: targetProjectName, + type: DependencyType.static, + sourceFile: normalizePath( + relative(workspaceRoot, dependencyFromPlugin.sourceFile) + ), + }; + validateDependency(dependency, context); + dependencies.push(dependency); + } catch { + logger.warn( + `Unable to parse dependency from gradle plugin: ${dependencyFromPlugin.source} -> ${dependencyFromPlugin.target}` + ); } - } + }); - return gradleFiles; -} + return dependencies; +}; diff --git a/packages/gradle/src/plugin/nodes.spec.ts b/packages/gradle/src/plugin/nodes.spec.ts index c6dd65f87f..31bee1d8cb 100644 --- a/packages/gradle/src/plugin/nodes.spec.ts +++ b/packages/gradle/src/plugin/nodes.spec.ts @@ -1,20 +1,22 @@ -import { CreateNodesContext } from '@nx/devkit'; - +import { CreateNodesContext, readJsonFile } from '@nx/devkit'; +import { join } from 'path'; import { TempFs } from 'nx/src/internal-testing-utils/temp-fs'; -import { type GradleReport } from '../utils/get-gradle-report'; +import { type ProjectGraphReport } from './utils/get-project-graph-from-gradle-plugin'; -let gradleReport: GradleReport; -jest.mock('../utils/get-gradle-report', () => { +let gradleReport: ProjectGraphReport; +jest.mock('./utils/get-project-graph-from-gradle-plugin', () => { return { GRADLE_BUILD_FILES: new Set(['build.gradle', 'build.gradle.kts']), - populateGradleReport: jest.fn().mockImplementation(() => void 0), - getCurrentGradleReport: jest.fn().mockImplementation(() => gradleReport), + populateProjectGraph: jest.fn().mockImplementation(() => void 0), + getCurrentProjectGraphReport: jest + .fn() + .mockImplementation(() => gradleReport), }; }); import { createNodesV2 } from './nodes'; -describe('@nx/gradle/plugin', () => { +describe('@nx/gradle/plugin/nodes', () => { let createNodesFunction = createNodesV2[1]; let context: CreateNodesContext; let tempFs: TempFs; @@ -22,32 +24,9 @@ describe('@nx/gradle/plugin', () => { beforeEach(async () => { tempFs = new TempFs('test'); - gradleReport = { - gradleFileToGradleProjectMap: new Map([ - ['proj/build.gradle', 'proj'], - ]), - buildFileToDepsMap: new Map>(), - gradleFileToOutputDirsMap: new Map>([ - ['proj/build.gradle', new Map([['build', 'build']])], - ]), - gradleProjectToTasksMap: new Map>([ - ['proj', new Set(['test'])], - ]), - gradleProjectToTasksTypeMap: new Map>([ - [ - 'proj', - new Map([ - ['test', 'Verification'], - ['build', 'Build'], - ]), - ], - ]), - gradleProjectToProjectName: new Map([['proj', 'proj']]), - gradleProjectNameToProjectRootMap: new Map([ - ['proj', 'proj'], - ]), - gradleProjectToChildProjects: new Map(), - }; + gradleReport = readJsonFile( + join(__dirname, 'utils/__mocks__/gradle_tutorial.json') + ); cwd = process.cwd(); process.chdir(tempFs.tempDir); context = { @@ -81,190 +60,13 @@ describe('@nx/gradle/plugin', () => { context ); - expect(results).toMatchInlineSnapshot(` - [ - [ - "proj/build.gradle", - { - "projects": { - "proj": { - "metadata": { - "targetGroups": { - "Verification": [ - "test", - ], - }, - "technologies": [ - "gradle", - ], - }, - "name": "proj", - "projectType": "application", - "targets": { - "test": { - "cache": true, - "command": "./gradlew proj:test", - "dependsOn": [ - "testClasses", - ], - "inputs": [ - "default", - "^production", - ], - "metadata": { - "help": { - "command": "./gradlew help --task proj:test", - "example": { - "options": { - "args": [ - "--rerun", - ], - }, - }, - }, - "technologies": [ - "gradle", - ], - }, - "options": { - "cwd": ".", - }, - }, - }, - }, - }, - }, - ], - ] - `); - }); - - it('should create nodes include subprojects tasks', async () => { - const results = await createNodesFunction( - ['proj/build.gradle'], - { - buildTargetName: 'build', - includeSubprojectsTasks: true, - }, - context - ); - - expect(results).toMatchInlineSnapshot(` - [ - [ - "proj/build.gradle", - { - "projects": { - "proj": { - "metadata": { - "targetGroups": { - "Build": [ - "build", - ], - "Verification": [ - "test", - ], - }, - "technologies": [ - "gradle", - ], - }, - "name": "proj", - "projectType": "application", - "targets": { - "build": { - "cache": true, - "command": "./gradlew proj:build", - "dependsOn": [ - "^build", - "classes", - "test", - ], - "inputs": [ - "production", - "^production", - ], - "metadata": { - "help": { - "command": "./gradlew help --task proj:build", - "example": { - "options": { - "args": [ - "--rerun", - ], - }, - }, - }, - "technologies": [ - "gradle", - ], - }, - "options": { - "cwd": ".", - }, - "outputs": [ - "build", - ], - }, - "test": { - "cache": true, - "command": "./gradlew proj:test", - "dependsOn": [ - "testClasses", - ], - "inputs": [ - "default", - "^production", - ], - "metadata": { - "help": { - "command": "./gradlew help --task proj:test", - "example": { - "options": { - "args": [ - "--rerun", - ], - }, - }, - }, - "technologies": [ - "gradle", - ], - }, - "options": { - "cwd": ".", - }, - }, - }, - }, - }, - }, - ], - ] - `); + expect(results).toMatchSnapshot(); }); it('should create nodes based on gradle for nested project root', async () => { - gradleReport = { - gradleFileToGradleProjectMap: new Map([ - ['nested/nested/proj/build.gradle', 'proj'], - ]), - buildFileToDepsMap: new Map>(), - gradleFileToOutputDirsMap: new Map>([ - ['nested/nested/proj/build.gradle', new Map([['build', 'build']])], - ]), - gradleProjectToTasksMap: new Map>([ - ['proj', new Set(['test'])], - ]), - gradleProjectToTasksTypeMap: new Map>([ - ['proj', new Map([['test', 'Verification']])], - ]), - gradleProjectToProjectName: new Map([['proj', 'proj']]), - gradleProjectNameToProjectRootMap: new Map([ - ['proj', 'proj'], - ]), - gradleProjectToChildProjects: new Map(), - }; + gradleReport = readJsonFile( + join(__dirname, '/utils/__mocks__/gradle_composite.json') + ); await tempFs.createFiles({ 'nested/nested/proj/build.gradle': ``, }); @@ -277,311 +79,30 @@ describe('@nx/gradle/plugin', () => { context ); - expect(results).toMatchInlineSnapshot(` - [ - [ - "nested/nested/proj/build.gradle", - { - "projects": { - "nested/nested/proj": { - "metadata": { - "targetGroups": { - "Verification": [ - "test", - ], - }, - "technologies": [ - "gradle", - ], - }, - "name": "proj", - "projectType": "application", - "targets": { - "test": { - "cache": true, - "command": "./gradlew proj:test", - "dependsOn": [ - "testClasses", - ], - "inputs": [ - "default", - "^production", - ], - "metadata": { - "help": { - "command": "./gradlew help --task proj:test", - "example": { - "options": { - "args": [ - "--rerun", - ], - }, - }, - }, - "technologies": [ - "gradle", - ], - }, - "options": { - "cwd": ".", - }, - }, - }, - }, - }, - }, - ], - ] - `); + expect(results).toMatchSnapshot(); }); - describe('with atomized tests targets', () => { - beforeEach(async () => { - gradleReport = { - gradleFileToGradleProjectMap: new Map([ - ['nested/nested/proj/build.gradle', 'proj'], - ]), - buildFileToDepsMap: new Map>(), - gradleFileToOutputDirsMap: new Map>([ - ['nested/nested/proj/build.gradle', new Map([['build', 'build']])], - ]), - gradleProjectToTasksMap: new Map>([ - ['proj', new Set(['test'])], - ]), - gradleProjectToTasksTypeMap: new Map>([ - ['proj', new Map([['test', 'Test']])], - ]), - gradleProjectToProjectName: new Map([['proj', 'proj']]), - gradleProjectNameToProjectRootMap: new Map([ - ['proj', 'proj'], - ]), - gradleProjectToChildProjects: new Map(), - }; - await tempFs.createFiles({ - 'nested/nested/proj/build.gradle': ``, - }); - await tempFs.createFiles({ - 'proj/src/test/java/test/rootTest.java': ``, - }); - await tempFs.createFiles({ - 'nested/nested/proj/src/test/java/test/aTest.java': ``, - }); - await tempFs.createFiles({ - 'nested/nested/proj/src/test/java/test/bTest.java': ``, - }); - await tempFs.createFiles({ - 'nested/nested/proj/src/test/java/test/cTests.java': ``, - }); - }); + it('should create nodes with atomized tests targets based on gradle if ciTargetName is specified', async () => { + const results = await createNodesFunction( + ['proj/application/build.gradle'], + { + buildTargetName: 'build', + ciTargetName: 'test-ci', + }, + context + ); - it('should create nodes with atomized tests targets based on gradle for nested project root', async () => { - const results = await createNodesFunction( - [ - 'nested/nested/proj/build.gradle', - 'proj/src/test/java/test/rootTest.java', - 'nested/nested/proj/src/test/java/test/aTest.java', - 'nested/nested/proj/src/test/java/test/bTest.java', - 'nested/nested/proj/src/test/java/test/cTests.java', - ], - { - buildTargetName: 'build', - ciTargetName: 'test-ci', - }, - context - ); + expect(results).toMatchSnapshot(); + }); - expect(results).toMatchInlineSnapshot(` - [ - [ - "nested/nested/proj/build.gradle", - { - "projects": { - "nested/nested/proj": { - "metadata": { - "targetGroups": { - "Test": [ - "test-ci--aTest", - "test-ci--bTest", - "test-ci--cTests", - "test-ci", - "test", - ], - }, - "technologies": [ - "gradle", - ], - }, - "name": "proj", - "projectType": "application", - "targets": { - "test": { - "cache": false, - "command": "./gradlew proj:test", - "dependsOn": [ - "testClasses", - ], - "inputs": [ - "default", - "^production", - ], - "metadata": { - "help": { - "command": "./gradlew help --task proj:test", - "example": { - "options": { - "args": [ - "--rerun", - ], - }, - }, - }, - "technologies": [ - "gradle", - ], - }, - "options": { - "cwd": ".", - }, - }, - "test-ci": { - "cache": true, - "dependsOn": [ - { - "params": "forward", - "projects": "self", - "target": "test-ci--aTest", - }, - { - "params": "forward", - "projects": "self", - "target": "test-ci--bTest", - }, - { - "params": "forward", - "projects": "self", - "target": "test-ci--cTests", - }, - ], - "executor": "nx:noop", - "inputs": [ - "default", - "^production", - ], - "metadata": { - "description": "Runs Gradle Tests in CI", - "help": { - "command": "./gradlew help --task proj:test", - "example": { - "options": { - "args": [ - "--rerun", - ], - }, - }, - }, - "nonAtomizedTarget": "test", - "technologies": [ - "gradle", - ], - }, - }, - "test-ci--aTest": { - "cache": true, - "command": "./gradlew proj:test --tests aTest", - "dependsOn": [ - "testClasses", - ], - "inputs": [ - "default", - "^production", - ], - "metadata": { - "description": "Runs Gradle test nested/nested/proj/src/test/java/test/aTest.java in CI", - "help": { - "command": "./gradlew help --task proj:test", - "example": { - "options": { - "args": [ - "--rerun", - ], - }, - }, - }, - "technologies": [ - "gradle", - ], - }, - "options": { - "cwd": ".", - }, - }, - "test-ci--bTest": { - "cache": true, - "command": "./gradlew proj:test --tests bTest", - "dependsOn": [ - "testClasses", - ], - "inputs": [ - "default", - "^production", - ], - "metadata": { - "description": "Runs Gradle test nested/nested/proj/src/test/java/test/bTest.java in CI", - "help": { - "command": "./gradlew help --task proj:test", - "example": { - "options": { - "args": [ - "--rerun", - ], - }, - }, - }, - "technologies": [ - "gradle", - ], - }, - "options": { - "cwd": ".", - }, - }, - "test-ci--cTests": { - "cache": true, - "command": "./gradlew proj:test --tests cTests", - "dependsOn": [ - "testClasses", - ], - "inputs": [ - "default", - "^production", - ], - "metadata": { - "description": "Runs Gradle test nested/nested/proj/src/test/java/test/cTests.java in CI", - "help": { - "command": "./gradlew help --task proj:test", - "example": { - "options": { - "args": [ - "--rerun", - ], - }, - }, - }, - "technologies": [ - "gradle", - ], - }, - "options": { - "cwd": ".", - }, - }, - }, - }, - }, - }, - ], - ] - `); - }); + it('should not create nodes with atomized tests targets based on gradle if ciTargetName is not specified', async () => { + const results = await createNodesFunction( + ['proj/application/build.gradle'], + { + buildTargetName: 'build', + }, + context + ); + expect(results).toMatchSnapshot(); }); }); diff --git a/packages/gradle/src/plugin/nodes.ts b/packages/gradle/src/plugin/nodes.ts index 6c61721dd4..e5f58519ae 100644 --- a/packages/gradle/src/plugin/nodes.ts +++ b/packages/gradle/src/plugin/nodes.ts @@ -1,67 +1,36 @@ import { - CreateNodes, CreateNodesV2, CreateNodesContext, ProjectConfiguration, - TargetConfiguration, createNodesFromFiles, readJsonFile, writeJsonFile, CreateNodesFunction, - logger, + workspaceRoot, + ProjectGraphExternalNode, } from '@nx/devkit'; import { calculateHashForCreateNodes } from '@nx/devkit/src/utils/calculate-hash-for-create-nodes'; import { existsSync } from 'node:fs'; -import { basename, dirname, join } from 'node:path'; +import { dirname, join } from 'node:path'; import { workspaceDataDirectory } from 'nx/src/utils/cache-directory'; -import { findProjectForPath } from 'nx/src/devkit-internals'; -import { - populateGradleReport, - getCurrentGradleReport, - GradleReport, -} from '../utils/get-gradle-report'; import { hashObject } from 'nx/src/hasher/file-hasher'; import { gradleConfigAndTestGlob, - gradleConfigGlob, splitConfigFiles, } from '../utils/split-config-files'; -import { getGradleExecFile, findGraldewFile } from '../utils/exec-gradle'; - -const cacheableTaskType = new Set(['Build', 'Verification']); -const dependsOnMap = { - build: ['^build', 'classes', 'test'], - testClasses: ['classes'], - test: ['testClasses'], - classes: ['^classes'], -}; - -interface GradleTask { - type: string; - name: string; -} - -export interface GradlePluginOptions { - includeSubprojectsTasks?: boolean; // default is false, show all gradle tasks in the project - ciTargetName?: string; - testTargetName?: string; - classesTargetName?: string; - buildTargetName?: string; - [taskTargetName: string]: string | undefined | boolean; -} - -function normalizeOptions(options: GradlePluginOptions): GradlePluginOptions { - options ??= {}; - options.testTargetName ??= 'test'; - options.classesTargetName ??= 'classes'; - options.buildTargetName ??= 'build'; - return options; -} +import { + getCurrentProjectGraphReport, + populateProjectGraph, +} from './utils/get-project-graph-from-gradle-plugin'; +import { + GradlePluginOptions, + normalizeOptions, +} from './utils/gradle-plugin-options'; type GradleTargets = Record>; -function readTargetsCache(cachePath: string): GradleTargets { +function readProjectsCache(cachePath: string): GradleTargets { return existsSync(cachePath) ? readJsonFile(cachePath) : {}; } @@ -72,47 +41,39 @@ export function writeTargetsToCache(cachePath: string, results: GradleTargets) { export const createNodesV2: CreateNodesV2 = [ gradleConfigAndTestGlob, async (files, options, context) => { - const { buildFiles, projectRoots, gradlewFiles, testFiles } = - splitConfigFiles(files); + const { buildFiles, gradlewFiles } = splitConfigFiles(files); const optionsHash = hashObject(options); const cachePath = join( workspaceDataDirectory, `gradle-${optionsHash}.hash` ); - const targetsCache = readTargetsCache(cachePath); + const projectsCache = readProjectsCache(cachePath); - await populateGradleReport( + await populateProjectGraph( context.workspaceRoot, - gradlewFiles.map((f) => join(context.workspaceRoot, f)) - ); - const gradleReport = getCurrentGradleReport(); - const gradleProjectRootToTestFilesMap = getGradleProjectRootToTestFilesMap( - testFiles, - projectRoots + gradlewFiles.map((f) => join(context.workspaceRoot, f)), + options ); + const { nodes, externalNodes } = getCurrentProjectGraphReport(); try { return createNodesFromFiles( - makeCreateNodesForGradleConfigFile( - gradleReport, - targetsCache, - gradleProjectRootToTestFilesMap - ), + makeCreateNodesForGradleConfigFile(nodes, projectsCache, externalNodes), buildFiles, options, context ); } finally { - writeTargetsToCache(cachePath, targetsCache); + writeTargetsToCache(cachePath, projectsCache); } }, ]; export const makeCreateNodesForGradleConfigFile = ( - gradleReport: GradleReport, - targetsCache: GradleTargets = {}, - gradleProjectRootToTestFilesMap: Record = {} + projects: Record>, + projectsCache: GradleTargets = {}, + externalNodes: Record = {} ): CreateNodesFunction => async ( gradleFilePath, @@ -127,309 +88,18 @@ export const makeCreateNodesForGradleConfigFile = options ?? {}, context ); - targetsCache[hash] ??= await createGradleProject( - gradleReport, - gradleFilePath, - options, - context, - gradleProjectRootToTestFilesMap[projectRoot] - ); - const project = targetsCache[hash]; + projectsCache[hash] ??= + projects[projectRoot] ?? projects[join(workspaceRoot, projectRoot)]; + const project = projectsCache[hash]; if (!project) { return {}; } + project.root = projectRoot; + return { projects: { [projectRoot]: project, }, + externalNodes: externalNodes, }; }; - -/** - @deprecated This is replaced with {@link createNodesV2}. Update your plugin to export its own `createNodesV2` function that wraps this one instead. - This function will change to the v2 function in Nx 20. - */ -export const createNodes: CreateNodes = [ - gradleConfigGlob, - async (buildFile, options, context) => { - logger.warn( - '`createNodes` is deprecated. Update your plugin to utilize createNodesV2 instead. In Nx 20, this will change to the createNodesV2 API.' - ); - const { gradlewFiles } = splitConfigFiles(context.configFiles); - await populateGradleReport(context.workspaceRoot, gradlewFiles); - const gradleReport = getCurrentGradleReport(); - const internalCreateNodes = - makeCreateNodesForGradleConfigFile(gradleReport); - return await internalCreateNodes(buildFile, options, context); - }, -]; - -async function createGradleProject( - gradleReport: GradleReport, - gradleFilePath: string, - options: GradlePluginOptions | undefined, - context: CreateNodesContext, - testFiles = [] -) { - try { - const { - gradleProjectToTasksTypeMap, - gradleProjectToTasksMap, - gradleFileToOutputDirsMap, - gradleFileToGradleProjectMap, - gradleProjectToProjectName, - } = gradleReport; - - const gradleProject = gradleFileToGradleProjectMap.get( - gradleFilePath - ) as string; - const projectName = gradleProjectToProjectName.get(gradleProject); - if (!projectName) { - return; - } - - const tasksTypeMap: Map = gradleProjectToTasksTypeMap.get( - gradleProject - ) as Map; - const tasksSet = gradleProjectToTasksMap.get(gradleProject) as Set; - let tasks: GradleTask[] = []; - tasksSet.forEach((taskName) => { - tasks.push({ - type: tasksTypeMap?.get(taskName) as string, - name: taskName, - }); - }); - if (options.includeSubprojectsTasks) { - tasksTypeMap.forEach((taskType, taskName) => { - if (!tasksSet.has(taskName)) { - tasks.push({ - type: taskType, - name: taskName, - }); - } - }); - } - - const outputDirs = gradleFileToOutputDirsMap.get(gradleFilePath) as Map< - string, - string - >; - - const { targets, targetGroups } = await createGradleTargets( - tasks, - options, - context, - outputDirs, - gradleProject, - gradleFilePath, - testFiles - ); - const project: Partial = { - name: projectName, - projectType: 'application', - targets, - metadata: { - targetGroups, - technologies: ['gradle'], - }, - }; - - return project; - } catch (e) { - console.error(e); - return undefined; - } -} - -async function createGradleTargets( - tasks: GradleTask[], - options: GradlePluginOptions | undefined, - context: CreateNodesContext, - outputDirs: Map, - gradleProject: string, - gradleBuildFilePath: string, - testFiles: string[] = [] -): Promise<{ - targetGroups: Record; - targets: Record; -}> { - const inputsMap = createInputsMap(context); - const gradlewFileDirectory = dirname( - findGraldewFile(gradleBuildFilePath, context.workspaceRoot) - ); - - const targets: Record = {}; - const targetGroups: Record = {}; - for (const task of tasks) { - const targetName = options?.[`${task.name}TargetName`] ?? task.name; - - let outputs = [outputDirs.get(task.name)].filter(Boolean); - if (task.name === 'test') { - outputs = [ - outputDirs.get('testReport'), - outputDirs.get('testResults'), - ].filter(Boolean); - getTestCiTargets( - testFiles, - gradleProject, - targetName as string, - options.ciTargetName, - inputsMap['test'], - outputs, - task.type, - targets, - targetGroups, - gradlewFileDirectory - ); - } - - const taskCommandToRun = `${gradleProject ? gradleProject + ':' : ''}${ - task.name - }`; - - targets[targetName as string] = { - command: `${getGradleExecFile()} ${taskCommandToRun}`, - options: { - cwd: gradlewFileDirectory, - }, - cache: cacheableTaskType.has(task.type), - inputs: inputsMap[task.name], - dependsOn: dependsOnMap[task.name], - metadata: { - technologies: ['gradle'], - help: { - command: `${getGradleExecFile()} help --task ${taskCommandToRun}`, - example: { - options: { - args: ['--rerun'], - }, - }, - }, - }, - ...(outputs && outputs.length ? { outputs } : {}), - }; - - if (task.type) { - if (!targetGroups[task.type]) { - targetGroups[task.type] = []; - } - targetGroups[task.type].push(targetName as string); - } - } - return { targetGroups, targets }; -} - -function createInputsMap( - context: CreateNodesContext -): Record { - const namedInputs = context.nxJsonConfiguration.namedInputs; - return { - build: namedInputs?.production - ? ['production', '^production'] - : ['default', '^default'], - test: ['default', namedInputs?.production ? '^production' : '^default'], - classes: namedInputs?.production - ? ['production', '^production'] - : ['default', '^default'], - }; -} - -function getTestCiTargets( - testFiles: string[], - gradleProject: string, - testTargetName: string, - ciTargetName: string, - inputs: TargetConfiguration['inputs'], - outputs: string[], - targetGroupName: string, - targets: Record, - targetGroups: Record, - gradlewFileDirectory: string -): void { - if (!testFiles || testFiles.length === 0 || !ciTargetName) { - return; - } - const taskCommandToRun = `${gradleProject ? gradleProject + ':' : ''}test`; - - if (!targetGroups[targetGroupName]) { - targetGroups[targetGroupName] = []; - } - - const dependsOn: TargetConfiguration['dependsOn'] = []; - testFiles.forEach((testFile) => { - const testName = basename(testFile).split('.')[0]; - const targetName = ciTargetName + '--' + testName; - - targets[targetName] = { - command: `${getGradleExecFile()} ${taskCommandToRun} --tests ${testName}`, - options: { - cwd: gradlewFileDirectory, - }, - cache: true, - inputs, - dependsOn: dependsOnMap['test'], - metadata: { - technologies: ['gradle'], - description: `Runs Gradle test ${testFile} in CI`, - help: { - command: `${getGradleExecFile()} help --task ${taskCommandToRun}`, - example: { - options: { - args: ['--rerun'], - }, - }, - }, - }, - ...(outputs && outputs.length > 0 ? { outputs } : {}), - }; - targetGroups[targetGroupName].push(targetName); - dependsOn.push({ - target: targetName, - projects: 'self', - params: 'forward', - }); - }); - - targets[ciTargetName] = { - executor: 'nx:noop', - cache: true, - inputs, - dependsOn: dependsOn, - ...(outputs && outputs.length > 0 ? { outputs } : {}), - metadata: { - technologies: ['gradle'], - description: 'Runs Gradle Tests in CI', - nonAtomizedTarget: testTargetName, - help: { - command: `${getGradleExecFile()} help --task ${taskCommandToRun}`, - example: { - options: { - args: ['--rerun'], - }, - }, - }, - }, - }; - targetGroups[targetGroupName].push(ciTargetName); -} - -function getGradleProjectRootToTestFilesMap( - testFiles: string[], - projectRoots: string[] -): Record | undefined { - if (testFiles.length === 0 || projectRoots.length === 0) { - return; - } - const roots = new Map(projectRoots.map((root) => [root, root])); - const testFilesToGradleProjectMap: Record = {}; - testFiles.forEach((testFile) => { - const projectRoot = findProjectForPath(testFile, roots); - if (projectRoot) { - if (!testFilesToGradleProjectMap[projectRoot]) { - testFilesToGradleProjectMap[projectRoot] = []; - } - testFilesToGradleProjectMap[projectRoot].push(testFile); - } - }); - return testFilesToGradleProjectMap; -} diff --git a/packages/gradle/src/plugin/utils/__mocks__/gradle_composite.json b/packages/gradle/src/plugin/utils/__mocks__/gradle_composite.json new file mode 100644 index 0000000000..eeb6326286 --- /dev/null +++ b/packages/gradle/src/plugin/utils/__mocks__/gradle_composite.json @@ -0,0 +1,38 @@ +{ + "nodes": { + "nested/nested/proj": { + "targets": { + "buildEnvironment": { + "cache": true, + "metadata": { + "description": "Displays all buildscript dependencies declared in root project \u0027my-composite\u0027.", + "technologies": ["gradle"] + }, + "command": "./gradlew :buildEnvironment", + "options": { + "cwd": "nested/nested/proj" + } + } + }, + "metadata": { + "targetGroups": { + "help": ["buildEnvironment"] + }, + "technologies": ["gradle"] + }, + "name": "my-composite" + } + }, + "dependencies": [ + { + "source": "nested/nested/proj", + "target": "projectRoot/my-app", + "sourceFile": "projectRoot/build.gradle.kts" + }, + { + "source": "nested/nested/proj", + "target": "projectRoot/my-utils", + "sourceFile": "projectRoot/build.gradle.kts" + } + ] +} diff --git a/packages/gradle/src/plugin/utils/__mocks__/gradle_nx_list.json b/packages/gradle/src/plugin/utils/__mocks__/gradle_nx_list.json new file mode 100644 index 0000000000..bb83fd416e --- /dev/null +++ b/packages/gradle/src/plugin/utils/__mocks__/gradle_nx_list.json @@ -0,0 +1,590 @@ +{ + "targets": { + "assemble": { + "cache": true, + "parallelism": false, + "dependsOn": ["list:jar"], + "command": "./gradlew :list:assemble", + "metadata": { + "description": "Assembles the outputs of this project.", + "technologies": ["gradle"], + "help": { "command": "./gradlew help --task :list:assemble" } + }, + "options": { "cwd": "." } + }, + "build": { + "cache": true, + "parallelism": false, + "dependsOn": ["list:check", "list:assemble"], + "command": "./gradlew :list:build", + "metadata": { + "description": "Assembles and tests this project.", + "technologies": ["gradle"], + "help": { "command": "./gradlew help --task :list:build" } + }, + "options": { "cwd": "." } + }, + "buildDependents": { + "cache": true, + "parallelism": false, + "command": "./gradlew :list:buildDependents", + "metadata": { + "description": "Assembles and tests this project and all projects that depend on it.", + "technologies": ["gradle"], + "help": { "command": "./gradlew help --task :list:buildDependents" } + }, + "options": { "cwd": "." } + }, + "buildEnvironment": { + "cache": true, + "parallelism": false, + "command": "./gradlew :list:buildEnvironment", + "metadata": { + "description": "Displays all buildscript dependencies declared in project \u0027:list\u0027.", + "technologies": ["gradle"], + "help": { + "command": "./gradlew help --task :list:buildEnvironment" + } + }, + "options": { "cwd": "." } + }, + "buildNeeded": { + "cache": true, + "parallelism": false, + "dependsOn": ["list:build"], + "command": "./gradlew :list:buildNeeded", + "metadata": { + "description": "Assembles and tests this project and all projects it depends on.", + "technologies": ["gradle"], + "help": { "command": "./gradlew help --task :list:buildNeeded" } + }, + "options": { "cwd": "." } + }, + "check": { + "cache": true, + "parallelism": false, + "dependsOn": ["list:test"], + "command": "./gradlew :list:check", + "metadata": { + "description": "Runs all checks.", + "technologies": ["gradle"], + "help": { "command": "./gradlew help --task :list:check" } + }, + "options": { "cwd": "." } + }, + "classes": { + "cache": true, + "parallelism": false, + "dependsOn": ["list:compileJava", "list:processResources"], + "command": "./gradlew :list:classes", + "metadata": { + "description": "Assembles main classes.", + "technologies": ["gradle"], + "help": { "command": "./gradlew help --task :list:classes" } + }, + "options": { "cwd": "." } + }, + "clean": { + "cache": true, + "parallelism": false, + "command": "./gradlew :list:clean", + "metadata": { + "description": "Deletes the build directory.", + "technologies": ["gradle"], + "help": { "command": "./gradlew help --task :list:clean" } + }, + "options": { "cwd": "." } + }, + "compileJava": { + "cache": true, + "parallelism": false, + "inputs": [ + "{projectRoot}/src/main/java/org/example/list/LinkedList.java" + ], + "outputs": [ + "{projectRoot}/build/classes/java/main", + "{projectRoot}/build/generated/sources/annotationProcessor/java/main", + "{projectRoot}/build/generated/sources/headers/java/main", + "{projectRoot}/build/tmp/compileJava/previous-compilation-data.bin" + ], + "command": "./gradlew :list:compileJava", + "metadata": { + "description": "Compiles main Java source.", + "technologies": ["gradle"], + "help": { "command": "./gradlew help --task :list:compileJava" } + }, + "options": { "cwd": "." } + }, + "compileTestJava": { + "cache": true, + "parallelism": false, + "inputs": [ + "{projectRoot}/src/test/java/org/example/list/LinkedListTest.java", + "{projectRoot}/src/test/java/org/example/list/LinkedList2Test.java" + ], + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin" + ], + "dependsOn": ["list:classes", "list:compileJava"], + "command": "./gradlew :list:compileTestJava", + "metadata": { + "description": "Compiles test Java source.", + "technologies": ["gradle"], + "help": { "command": "./gradlew help --task :list:compileTestJava" } + }, + "options": { "cwd": "." } + }, + "ci--LinkedListTest": { + "command": "./gradlew :list:test --tests LinkedListTest", + "metadata": { + "description": "Runs Gradle test LinkedListTest in CI", + "technologies": ["gradle"], + "help": { "command": "./gradlew help --task :list:test" } + }, + "cache": true, + "parallelism": false, + "inputs": [ + "{projectRoot}/src/test/java/org/example/list/LinkedListTest.java" + ], + "dependsOn": [ + "list:compileTestJava", + "list:testClasses", + "list:classes", + "list:compileJava" + ], + "outputs": [ + "{projectRoot}/build/test-results/test/binary", + "{projectRoot}/build/reports/tests/test", + "{projectRoot}/build/test-results/test" + ] + }, + "ci--LinkedList2Test": { + "command": "./gradlew :list:test --tests LinkedList2Test", + "metadata": { + "description": "Runs Gradle test LinkedList2Test in CI", + "technologies": ["gradle"], + "help": { "command": "./gradlew help --task :list:test" } + }, + "cache": true, + "parallelism": false, + "inputs": [ + "{projectRoot}/src/test/java/org/example/list/LinkedList2Test.java" + ], + "dependsOn": [ + "list:compileTestJava", + "list:testClasses", + "list:classes", + "list:compileJava" + ], + "outputs": [ + "{projectRoot}/build/test-results/test/binary", + "{projectRoot}/build/reports/tests/test", + "{projectRoot}/build/test-results/test" + ] + }, + "ci": { + "executor": "nx:noop", + "metadata": { + "description": "Runs Gradle Tests in CI", + "technologies": ["gradle"], + "help": { "command": "./gradlew help --task :list:test" } + }, + "dependsOn": [ + { + "target": "ci--LinkedListTest", + "projects": "self", + "params": "forward" + }, + { + "target": "ci--LinkedList2Test", + "projects": "self", + "params": "forward" + } + ], + "cache": true, + "parallelism": false + }, + "components": { + "cache": true, + "parallelism": false, + "command": "./gradlew :list:components", + "metadata": { + "description": "Displays the components produced by project \u0027:list\u0027. [deprecated]", + "technologies": ["gradle"], + "help": { "command": "./gradlew help --task :list:components" } + }, + "options": { "cwd": "." } + }, + "nxProjectGraph": { + "cache": true, + "parallelism": false, + "dependsOn": ["list:nxProjectGraphLocal"], + "command": "./gradlew :list:nxProjectGraph", + "metadata": { + "description": "Print nodes report for Nx", + "technologies": ["gradle"], + "help": { "command": "./gradlew help --task :list:nxProjectGraph" } + }, + "options": { "cwd": "." } + }, + "createNodesLocal": { + "cache": true, + "parallelism": false, + "outputs": ["{projectRoot}/build/nx/list.json"], + "command": "./gradlew :list:nxProjectGraphLocal", + "metadata": { + "description": "Create nodes and dependencies for Nx", + "technologies": ["gradle"], + "help": { + "command": "./gradlew help --task :list:nxProjectGraphLocal" + } + }, + "options": { "cwd": "." } + }, + "dependencies": { + "cache": true, + "parallelism": false, + "command": "./gradlew :list:dependencies", + "metadata": { + "description": "Displays all dependencies declared in project \u0027:list\u0027.", + "technologies": ["gradle"], + "help": { "command": "./gradlew help --task :list:dependencies" } + }, + "options": { "cwd": "." } + }, + "dependencyInsight": { + "cache": true, + "parallelism": false, + "command": "./gradlew :list:dependencyInsight", + "metadata": { + "description": "Displays the insight into a specific dependency in project \u0027:list\u0027.", + "technologies": ["gradle"], + "help": { + "command": "./gradlew help --task :list:dependencyInsight" + } + }, + "options": { "cwd": "." } + }, + "dependencyReport": { + "cache": true, + "parallelism": false, + "outputs": ["{projectRoot}/build/reports/project/dependencies.txt"], + "command": "./gradlew :list:dependencyReport", + "metadata": { + "description": "Generates a report about your library dependencies.", + "technologies": ["gradle"], + "help": { + "command": "./gradlew help --task :list:dependencyReport" + } + }, + "options": { "cwd": "." } + }, + "dependentComponents": { + "cache": true, + "parallelism": false, + "command": "./gradlew :list:dependentComponents", + "metadata": { + "description": "Displays the dependent components of components in project \u0027:list\u0027. [deprecated]", + "technologies": ["gradle"], + "help": { + "command": "./gradlew help --task :list:dependentComponents" + } + }, + "options": { "cwd": "." } + }, + "help": { + "cache": true, + "parallelism": false, + "command": "./gradlew :list:help", + "metadata": { + "description": "Displays a help message.", + "technologies": ["gradle"], + "help": { "command": "./gradlew help --task :list:help" } + }, + "options": { "cwd": "." } + }, + "htmlDependencyReport": { + "cache": true, + "parallelism": false, + "outputs": ["{projectRoot}/build/reports/project/dependencies"], + "command": "./gradlew :list:htmlDependencyReport", + "metadata": { + "description": "Generates an HTML report about your library dependencies.", + "technologies": ["gradle"], + "help": { + "command": "./gradlew help --task :list:htmlDependencyReport" + } + }, + "options": { "cwd": "." } + }, + "jar": { + "cache": true, + "parallelism": false, + "inputs": ["{projectRoot}/build/tmp/jar/MANIFEST.MF"], + "outputs": ["{projectRoot}/build/libs/list.jar"], + "dependsOn": ["list:classes", "list:compileJava"], + "command": "./gradlew :list:jar", + "metadata": { + "description": "Assembles a jar archive containing the classes of the \u0027main\u0027 feature.", + "technologies": ["gradle"], + "help": { "command": "./gradlew help --task :list:jar" } + }, + "options": { "cwd": "." } + }, + "javaToolchains": { + "cache": true, + "parallelism": false, + "command": "./gradlew :list:javaToolchains", + "metadata": { + "description": "Displays the detected java toolchains.", + "technologies": ["gradle"], + "help": { "command": "./gradlew help --task :list:javaToolchains" } + }, + "options": { "cwd": "." } + }, + "javadoc": { + "cache": true, + "parallelism": false, + "inputs": [ + "{projectRoot}/src/main/java/org/example/list/LinkedList.java" + ], + "outputs": ["{projectRoot}/build/docs/javadoc"], + "dependsOn": ["list:classes", "list:compileJava"], + "command": "./gradlew :list:javadoc", + "metadata": { + "description": "Generates Javadoc API documentation for the \u0027main\u0027 feature.", + "technologies": ["gradle"], + "help": { "command": "./gradlew help --task :list:javadoc" } + }, + "options": { "cwd": "." } + }, + "kotlinDslAccessorsReport": { + "cache": true, + "parallelism": false, + "command": "./gradlew :list:kotlinDslAccessorsReport", + "metadata": { + "description": "Prints the Kotlin code for accessing the currently available project extensions and conventions.", + "technologies": ["gradle"], + "help": { + "command": "./gradlew help --task :list:kotlinDslAccessorsReport" + } + }, + "options": { "cwd": "." } + }, + "model": { + "cache": true, + "parallelism": false, + "command": "./gradlew :list:model", + "metadata": { + "description": "Displays the configuration model of project \u0027:list\u0027. [deprecated]", + "technologies": ["gradle"], + "help": { "command": "./gradlew help --task :list:model" } + }, + "options": { "cwd": "." } + }, + "outgoingVariants": { + "cache": true, + "parallelism": false, + "command": "./gradlew :list:outgoingVariants", + "metadata": { + "description": "Displays the outgoing variants of project \u0027:list\u0027.", + "technologies": ["gradle"], + "help": { + "command": "./gradlew help --task :list:outgoingVariants" + } + }, + "options": { "cwd": "." } + }, + "processResources": { + "cache": true, + "parallelism": false, + "outputs": ["{projectRoot}/build/resources/main"], + "command": "./gradlew :list:processResources", + "metadata": { + "description": "Processes main resources.", + "technologies": ["gradle"], + "help": { + "command": "./gradlew help --task :list:processResources" + } + }, + "options": { "cwd": "." } + }, + "processTestResources": { + "cache": true, + "parallelism": false, + "outputs": ["{projectRoot}/build/resources/test"], + "command": "./gradlew :list:processTestResources", + "metadata": { + "description": "Processes test resources.", + "technologies": ["gradle"], + "help": { + "command": "./gradlew help --task :list:processTestResources" + } + }, + "options": { "cwd": "." } + }, + "projectReport": { + "cache": true, + "parallelism": false, + "dependsOn": [ + "list:taskReport", + "list:dependencyReport", + "list:propertyReport", + "list:htmlDependencyReport" + ], + "command": "./gradlew :list:projectReport", + "metadata": { + "description": "Generates a report about your project.", + "technologies": ["gradle"], + "help": { "command": "./gradlew help --task :list:projectReport" } + }, + "options": { "cwd": "." } + }, + "projects": { + "cache": true, + "parallelism": false, + "command": "./gradlew :list:projects", + "metadata": { + "description": "Displays the sub-projects of project \u0027:list\u0027.", + "technologies": ["gradle"], + "help": { "command": "./gradlew help --task :list:projects" } + }, + "options": { "cwd": "." } + }, + "properties": { + "cache": true, + "parallelism": false, + "command": "./gradlew :list:properties", + "metadata": { + "description": "Displays the properties of project \u0027:list\u0027.", + "technologies": ["gradle"], + "help": { "command": "./gradlew help --task :list:properties" } + }, + "options": { "cwd": "." } + }, + "propertyReport": { + "cache": true, + "parallelism": false, + "outputs": ["{projectRoot}/build/reports/project/properties.txt"], + "command": "./gradlew :list:propertyReport", + "metadata": { + "description": "Generates a report about your properties.", + "technologies": ["gradle"], + "help": { "command": "./gradlew help --task :list:propertyReport" } + }, + "options": { "cwd": "." } + }, + "resolvableConfigurations": { + "cache": true, + "parallelism": false, + "command": "./gradlew :list:resolvableConfigurations", + "metadata": { + "description": "Displays the configurations that can be resolved in project \u0027:list\u0027.", + "technologies": ["gradle"], + "help": { + "command": "./gradlew help --task :list:resolvableConfigurations" + } + }, + "options": { "cwd": "." } + }, + "taskReport": { + "cache": true, + "parallelism": false, + "outputs": ["{projectRoot}/build/reports/project/tasks.txt"], + "command": "./gradlew :list:taskReport", + "metadata": { + "description": "Generates a report about your tasks.", + "technologies": ["gradle"], + "help": { "command": "./gradlew help --task :list:taskReport" } + }, + "options": { "cwd": "." } + }, + "tasks": { + "cache": true, + "parallelism": false, + "command": "./gradlew :list:tasks", + "metadata": { + "description": "Displays the tasks runnable from project \u0027:list\u0027.", + "technologies": ["gradle"], + "help": { "command": "./gradlew help --task :list:tasks" } + }, + "options": { "cwd": "." } + }, + "test": { + "cache": true, + "parallelism": false, + "outputs": [ + "{projectRoot}/build/test-results/test/binary", + "{projectRoot}/build/reports/tests/test", + "{projectRoot}/build/test-results/test" + ], + "dependsOn": [ + "list:compileTestJava", + "list:testClasses", + "list:classes", + "list:compileJava" + ], + "command": "./gradlew :list:test", + "metadata": { + "description": "Runs the test suite.", + "technologies": ["gradle"], + "help": { "command": "./gradlew help --task :list:test" } + }, + "options": { "cwd": "." } + }, + "testClasses": { + "cache": true, + "parallelism": false, + "dependsOn": ["list:processTestResources", "list:compileTestJava"], + "command": "./gradlew :list:testClasses", + "metadata": { + "description": "Assembles test classes.", + "technologies": ["gradle"], + "help": { "command": "./gradlew help --task :list:testClasses" } + }, + "options": { "cwd": "." } + } + }, + "metadata": { + "targetGroups": { + "build": [ + "assemble", + "build", + "buildDependents", + "buildNeeded", + "classes", + "clean", + "jar", + "testClasses" + ], + "help": [ + "buildEnvironment", + "dependencies", + "dependencyInsight", + "help", + "javaToolchains", + "kotlinDslAccessorsReport", + "outgoingVariants", + "projects", + "properties", + "resolvableConfigurations", + "tasks" + ], + "verification": [ + "check", + "ci--LinkedListTest", + "ci--LinkedList2Test", + "ci", + "test" + ], + "Nx Custom": ["createNodes", "createNodesLocal"], + "documentation": ["javadoc"], + "reporting": ["projectReport"] + }, + "technologies": ["gradle"] + }, + "name": "list" +} diff --git a/packages/gradle/src/plugin/utils/__mocks__/gradle_tutorial.json b/packages/gradle/src/plugin/utils/__mocks__/gradle_tutorial.json new file mode 100644 index 0000000000..3a9cdf91bd --- /dev/null +++ b/packages/gradle/src/plugin/utils/__mocks__/gradle_tutorial.json @@ -0,0 +1,344 @@ +{ + "nodes": { + "proj": { + "targets": { + "buildEnvironment": { + "cache": true, + "metadata": { + "description": "Displays all buildscript dependencies declared in root project \u0027gradle-tutorial\u0027.", + "technologies": ["gradle"] + }, + "command": "./gradlew :buildEnvironment", + "options": { "cwd": "proj" } + } + }, + "metadata": { + "targetGroups": { + "help": ["buildEnvironment"] + }, + "technologies": ["gradle"] + }, + "name": "gradle-tutorial" + }, + "proj/application": { + "targets": { + "ci--DemoApplicationTest10": { + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest10.java" + ], + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin" + ], + "cache": true, + "dependsOn": [ + "application:classes", + "application:compileJava", + "library:jar" + ], + "metadata": { + "description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest10.java in CI", + "technologies": ["gradle"] + }, + "command": "./gradlew :application:test --tests DemoApplicationTest10", + "options": { "cwd": "proj" } + }, + "ci--DemoApplicationTest7": { + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest7.java" + ], + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin" + ], + "cache": true, + "dependsOn": [ + "application:classes", + "application:compileJava", + "library:jar" + ], + "metadata": { + "description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest7.java in CI", + "technologies": ["gradle"] + }, + "command": "./gradlew :application:test --tests DemoApplicationTest7", + "options": { "cwd": "proj" } + }, + "ci--DemoApplicationTest6": { + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest6.java" + ], + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin" + ], + "cache": true, + "dependsOn": [ + "application:classes", + "application:compileJava", + "library:jar" + ], + "metadata": { + "description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest6.java in CI", + "technologies": ["gradle"] + }, + "command": "./gradlew :application:test --tests DemoApplicationTest6", + "options": { "cwd": "proj" } + }, + "ci--DemoApplicationTest3": { + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest3.java" + ], + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin" + ], + "cache": true, + "dependsOn": [ + "application:classes", + "application:compileJava", + "library:jar" + ], + "metadata": { + "description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest3.java in CI", + "technologies": ["gradle"] + }, + "command": "./gradlew :application:test --tests DemoApplicationTest3", + "options": { "cwd": "proj" } + }, + "ci--DemoApplicationTest2": { + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest2.java" + ], + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin" + ], + "cache": true, + "dependsOn": [ + "application:classes", + "application:compileJava", + "library:jar" + ], + "metadata": { + "description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest2.java in CI", + "technologies": ["gradle"] + }, + "command": "./gradlew :application:test --tests DemoApplicationTest2", + "options": { "cwd": "proj" } + }, + "ci--DemoApplicationTest9": { + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest9.java" + ], + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin" + ], + "cache": true, + "dependsOn": [ + "application:classes", + "application:compileJava", + "library:jar" + ], + "metadata": { + "description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest9.java in CI", + "technologies": ["gradle"] + }, + "command": "./gradlew :application:test --tests DemoApplicationTest9", + "options": { "cwd": "proj" } + }, + "ci--DemoApplicationTest": { + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest.java" + ], + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin" + ], + "cache": true, + "dependsOn": [ + "application:classes", + "application:compileJava", + "library:jar" + ], + "metadata": { + "description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest.java in CI", + "technologies": ["gradle"] + }, + "command": "./gradlew :application:test --tests DemoApplicationTest", + "options": { "cwd": "proj" } + }, + "ci--DemoApplicationTest5": { + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest5.java" + ], + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin" + ], + "cache": true, + "dependsOn": [ + "application:classes", + "application:compileJava", + "library:jar" + ], + "metadata": { + "description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest5.java in CI", + "technologies": ["gradle"] + }, + "command": "./gradlew :application:test --tests DemoApplicationTest5", + "options": { "cwd": "proj" } + }, + "ci--DemoApplicationTest4": { + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest4.java" + ], + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin" + ], + "cache": true, + "dependsOn": [ + "application:classes", + "application:compileJava", + "library:jar" + ], + "metadata": { + "description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest4.java in CI", + "technologies": ["gradle"] + }, + "command": "./gradlew :application:test --tests DemoApplicationTest4", + "options": { "cwd": "proj" } + }, + "ci--DemoApplicationTest8": { + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest8.java" + ], + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin" + ], + "cache": true, + "dependsOn": [ + "application:classes", + "application:compileJava", + "library:jar" + ], + "metadata": { + "description": "Runs Gradle test proj/application/src/test/java/com/example/multimodule/application/DemoApplicationTest8.java in CI", + "technologies": ["gradle"] + }, + "command": "./gradlew :application:test --tests DemoApplicationTest8", + "options": { "cwd": "proj" } + }, + "ci": { + "inputs": [ + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest10.java", + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest7.java", + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest6.java", + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest3.java", + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest2.java", + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest9.java", + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest.java", + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest5.java", + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest4.java", + "{projectRoot}/src/test/java/com/example/multimodule/application/DemoApplicationTest8.java" + ], + "outputs": [ + "{projectRoot}/build/classes/java/test", + "{projectRoot}/build/generated/sources/annotationProcessor/java/test", + "{projectRoot}/build/generated/sources/headers/java/test", + "{projectRoot}/build/tmp/compileTestJava/previous-compilation-data.bin" + ], + "cache": true, + "dependsOn": [ + { + "target": "ci--DemoApplicationTest10", + "projects": "self", + "params": "forward" + }, + { + "target": "ci--DemoApplicationTest7", + "projects": "self", + "params": "forward" + }, + { + "target": "ci--DemoApplicationTest6", + "projects": "self", + "params": "forward" + }, + { + "target": "ci--DemoApplicationTest3", + "projects": "self", + "params": "forward" + }, + { + "target": "ci--DemoApplicationTest2", + "projects": "self", + "params": "forward" + }, + { + "target": "ci--DemoApplicationTest9", + "projects": "self", + "params": "forward" + }, + { + "target": "ci--DemoApplicationTest", + "projects": "self", + "params": "forward" + }, + { + "target": "ci--DemoApplicationTest5", + "projects": "self", + "params": "forward" + }, + { + "target": "ci--DemoApplicationTest4", + "projects": "self", + "params": "forward" + }, + { + "target": "ci--DemoApplicationTest8", + "projects": "self", + "params": "forward" + } + ], + "metadata": { + "description": "Runs Gradle Tests in CI", + "technologies": ["gradle"] + }, + "options": { "cwd": "proj" }, + "executor": "nx:noop" + } + }, + "metadata": { + "targetGroups": { + "verification": ["ci"] + }, + "technologies": ["gradle"] + }, + "name": "application" + } + } +} diff --git a/packages/gradle/src/plugin/utils/get-project-graph-from-gradle-plugin.ts b/packages/gradle/src/plugin/utils/get-project-graph-from-gradle-plugin.ts new file mode 100644 index 0000000000..affe47c535 --- /dev/null +++ b/packages/gradle/src/plugin/utils/get-project-graph-from-gradle-plugin.ts @@ -0,0 +1,203 @@ +import { existsSync } from 'node:fs'; +import { join } from 'node:path'; + +import { + AggregateCreateNodesError, + hashArray, + ProjectConfiguration, + ProjectGraphExternalNode, + readJsonFile, + StaticDependency, + writeJsonFile, +} from '@nx/devkit'; + +import { hashWithWorkspaceContext } from 'nx/src/utils/workspace-context'; +import { gradleConfigAndTestGlob } from '../../utils/split-config-files'; +import { workspaceDataDirectory } from 'nx/src/utils/cache-directory'; +import { getNxProjectGraphLines } from './get-project-graph-lines'; +import { GradlePluginOptions } from './gradle-plugin-options'; +import { hashObject } from 'nx/src/devkit-internals'; + +// the output json file from the gradle plugin +export interface ProjectGraphReport { + nodes: { + [appRoot: string]: Partial; + }; + dependencies: Array; + externalNodes?: Record; +} + +export interface ProjectGraphReportCache extends ProjectGraphReport { + hash: string; +} + +function readProjectGraphReportCache( + cachePath: string, + hash: string +): ProjectGraphReport | undefined { + const projectGraphReportCache: Partial = existsSync( + cachePath + ) + ? readJsonFile(cachePath) + : undefined; + if (!projectGraphReportCache || projectGraphReportCache.hash !== hash) { + return; + } + return projectGraphReportCache as ProjectGraphReport; +} + +export function writeProjectGraphReportToCache( + cachePath: string, + results: ProjectGraphReport +) { + let projectGraphReportJson: ProjectGraphReportCache = { + hash: gradleCurrentConfigHash, + ...results, + }; + + writeJsonFile(cachePath, projectGraphReportJson); +} + +let projectGraphReportCache: ProjectGraphReport; +let gradleCurrentConfigHash: string; +let projectGraphReportCachePath: string = join( + workspaceDataDirectory, + 'gradle-nodes.hash' +); + +export function getCurrentProjectGraphReport(): ProjectGraphReport { + if (!projectGraphReportCache) { + throw new AggregateCreateNodesError( + [ + [ + null, + new Error( + `Expected cached gradle report. Please open an issue at https://github.com/nrwl/nx/issues/new/choose` + ), + ], + ], + [] + ); + } + return projectGraphReportCache; +} + +/** + * This function populates the gradle report cache. + * For each gradlew file, it runs the `nxProjectGraph` task and processes the output. + * It will throw an error if both tasks fail. + * It will accumulate the output of all gradlew files. + * @param workspaceRoot + * @param gradlewFiles absolute paths to all gradlew files in the workspace + * @returns Promise + */ +export async function populateProjectGraph( + workspaceRoot: string, + gradlewFiles: string[], + options: GradlePluginOptions +): Promise { + const gradleConfigHash = hashArray([ + await hashWithWorkspaceContext(workspaceRoot, [gradleConfigAndTestGlob]), + hashObject(options), + process.env.CI, + ]); + projectGraphReportCache ??= readProjectGraphReportCache( + projectGraphReportCachePath, + gradleConfigHash + ); + if ( + projectGraphReportCache && + (!gradleCurrentConfigHash || gradleConfigHash === gradleCurrentConfigHash) + ) { + return; + } + + const gradleProjectGraphReportStart = performance.mark( + 'gradleProjectGraphReport:start' + ); + + const projectGraphLines = await gradlewFiles.reduce( + async ( + projectGraphLines: Promise, + gradlewFile: string + ): Promise => { + const getNxProjectGraphLinesStart = performance.mark( + `${gradlewFile}GetNxProjectGraphLines:start` + ); + const allLines = await projectGraphLines; + const currentLines = await getNxProjectGraphLines( + gradlewFile, + gradleConfigHash, + options + ); + const getNxProjectGraphLinesEnd = performance.mark( + `${gradlewFile}GetNxProjectGraphLines:end` + ); + performance.measure( + `${gradlewFile}GetNxProjectGraphLines`, + getNxProjectGraphLinesStart.name, + getNxProjectGraphLinesEnd.name + ); + return [...allLines, ...currentLines]; + }, + Promise.resolve([]) + ); + + const gradleProjectGraphReportEnd = performance.mark( + 'gradleProjectGraphReport:end' + ); + performance.measure( + 'gradleProjectGraphReport', + gradleProjectGraphReportStart.name, + gradleProjectGraphReportEnd.name + ); + gradleCurrentConfigHash = gradleConfigHash; + projectGraphReportCache = processNxProjectGraph(projectGraphLines); + writeProjectGraphReportToCache( + projectGraphReportCachePath, + projectGraphReportCache + ); +} + +export function processNxProjectGraph( + projectGraphLines: string[] +): ProjectGraphReport { + let index = 0; + let projectGraphReportForAllProjects: ProjectGraphReport = { + nodes: {}, + dependencies: [], + externalNodes: {}, + }; + while (index < projectGraphLines.length) { + const line = projectGraphLines[index].trim(); + if (line.startsWith('> Task ') && line.endsWith(':nxProjectGraph')) { + while ( + index < projectGraphLines.length && + !projectGraphLines[index].includes('.json') + ) { + index++; + } + const file = projectGraphLines[index]; + const projectGraphReportJson: ProjectGraphReport = + readJsonFile(file); + projectGraphReportForAllProjects.nodes = { + ...projectGraphReportForAllProjects.nodes, + ...projectGraphReportJson.nodes, + }; + if (projectGraphReportJson.dependencies) { + projectGraphReportForAllProjects.dependencies.push( + ...projectGraphReportJson.dependencies + ); + } + if (Object.keys(projectGraphReportJson.externalNodes ?? {}).length > 0) { + projectGraphReportForAllProjects.externalNodes = { + ...projectGraphReportForAllProjects.externalNodes, + ...projectGraphReportJson.externalNodes, + }; + } + } + index++; + } + + return projectGraphReportForAllProjects; +} diff --git a/packages/gradle/src/plugin/utils/get-project-graph-lines.ts b/packages/gradle/src/plugin/utils/get-project-graph-lines.ts new file mode 100644 index 0000000000..9b0fab22f6 --- /dev/null +++ b/packages/gradle/src/plugin/utils/get-project-graph-lines.ts @@ -0,0 +1,90 @@ +import { AggregateCreateNodesError, output, workspaceRoot } from '@nx/devkit'; +import { execGradleAsync, newLineSeparator } from '../../utils/exec-gradle'; +import { GradlePluginOptions } from './gradle-plugin-options'; +import { dirname } from 'node:path'; + +export async function getNxProjectGraphLines( + gradlewFile: string, + gradleConfigHash: string, + gradlePluginOptions: GradlePluginOptions +): Promise { + if (process.env.VERCEL) { + // skip on Vercel + return []; + } + + let nxProjectGraphBuffer: Buffer; + + const gradlePluginOptionsArgs = + Object.entries(gradlePluginOptions ?? {})?.map( + ([key, value]) => `-P${key}=${value}` + ) ?? []; + + try { + nxProjectGraphBuffer = await execGradleAsync(gradlewFile, [ + 'nxProjectGraph', + `-Phash=${gradleConfigHash}`, + '--no-configuration-cache', // disable configuration cache + '--parallel', // add parallel to improve performance + '--build-cache', // enable build cache + '--warning-mode', + 'none', + ...gradlePluginOptionsArgs, + `-Pcwd=${dirname(gradlewFile)}`, + `-PworkspaceRoot=${workspaceRoot}`, + process.env.NX_VERBOSE_LOGGING ? '--info' : '', + ]); + } catch (e: Buffer | Error | any) { + if (e.toString()?.includes('ERROR: JAVA_HOME')) { + throw new AggregateCreateNodesError( + [ + [ + gradlewFile, + new Error( + `Could not find Java. Please install Java and try again: https://www.java.com/en/download/help/index_installing.html.\n\r${e.toString()}` + ), + ], + ], + [] + ); + } else if (e.toString()?.includes(`Task 'nxProjectGraph' not found`)) { + throw new AggregateCreateNodesError( + [ + [ + gradlewFile, + new Error( + `Could not run 'nxProjectGraph' task. Please run 'nx generate @nx/gradle:init' to generate the necessary tasks.\n\r${e.toString()}` + ), + ], + ], + [] + ); + } else { + throw new AggregateCreateNodesError( + [ + [ + gradlewFile, + new Error( + `Could not run 'nxProjectGraph' Gradle task. Please install Gradle and try again: https://gradle.org/install/.\r\n${e.toString()}` + ), + ], + ], + [] + ); + } + } + + const projectGraphLines = nxProjectGraphBuffer + .toString() + .split(newLineSeparator) + .filter((line) => line.trim() !== ''); + + if (process.env.NX_VERBOSE_LOGGING === 'true') { + output.log({ + title: `Successfully ran 'nxProjectGraph' task using ${gradlewFile} with hash ${gradleConfigHash}`, + bodyLines: projectGraphLines, + }); + } + + return projectGraphLines; +} diff --git a/packages/gradle/src/plugin/utils/gradle-plugin-options.ts b/packages/gradle/src/plugin/utils/gradle-plugin-options.ts new file mode 100644 index 0000000000..267f521423 --- /dev/null +++ b/packages/gradle/src/plugin/utils/gradle-plugin-options.ts @@ -0,0 +1,13 @@ +export interface GradlePluginOptions { + testTargetName?: string; + ciTargetName?: string; + [taskTargetName: string]: string | undefined | boolean; +} + +export function normalizeOptions( + options: GradlePluginOptions +): GradlePluginOptions { + options ??= {}; + options.testTargetName ??= 'test'; + return options; +} diff --git a/packages/gradle/src/utils/exec-gradle.spec.ts b/packages/gradle/src/utils/exec-gradle.spec.ts index a8b2ae1286..88e8fd54fa 100644 --- a/packages/gradle/src/utils/exec-gradle.spec.ts +++ b/packages/gradle/src/utils/exec-gradle.spec.ts @@ -1,8 +1,8 @@ import { TempFs } from 'nx/src/internal-testing-utils/temp-fs'; -import { findGraldewFile } from './exec-gradle'; +import { findGradlewFile } from './exec-gradle'; describe('exec gradle', () => { - describe('findGraldewFile', () => { + describe('findGradlewFile', () => { let tempFs: TempFs; let cwd: string; @@ -27,14 +27,14 @@ describe('exec gradle', () => { 'nested/nested/proj/src/test/java/test/aTest.java': ``, 'nested/nested/proj/src/test/java/test/bTest.java': ``, }); - let gradlewFile = findGraldewFile('proj/build.gradle', tempFs.tempDir); + let gradlewFile = findGradlewFile('proj/build.gradle', tempFs.tempDir); expect(gradlewFile).toEqual('gradlew'); - gradlewFile = findGraldewFile( + gradlewFile = findGradlewFile( 'nested/nested/proj/build.gradle', tempFs.tempDir ); expect(gradlewFile).toEqual('gradlew'); - gradlewFile = findGraldewFile( + gradlewFile = findGradlewFile( 'nested/nested/proj/settings.gradle', tempFs.tempDir ); @@ -54,16 +54,16 @@ describe('exec gradle', () => { 'nested/nested/proj/src/test/java/test/bTest.java': ``, }); - let gradlewFile = findGraldewFile('proj/build.gradle', tempFs.tempDir); + let gradlewFile = findGradlewFile('proj/build.gradle', tempFs.tempDir); expect(gradlewFile).toEqual('proj/gradlew'); - gradlewFile = findGraldewFile('proj/settings.gradle', tempFs.tempDir); + gradlewFile = findGradlewFile('proj/settings.gradle', tempFs.tempDir); expect(gradlewFile).toEqual('proj/gradlew'); - gradlewFile = findGraldewFile( + gradlewFile = findGradlewFile( 'nested/nested/proj/build.gradle', tempFs.tempDir ); expect(gradlewFile).toEqual('nested/nested/proj/gradlew'); - gradlewFile = findGraldewFile( + gradlewFile = findGradlewFile( 'nested/nested/proj/settings.gradle', tempFs.tempDir ); @@ -80,7 +80,7 @@ describe('exec gradle', () => { 'nested/nested/proj/src/test/java/test/bTest.java': ``, }); expect(() => - findGraldewFile('proj/build.gradle', tempFs.tempDir) + findGradlewFile('proj/build.gradle', tempFs.tempDir) ).toThrow(); }); }); diff --git a/packages/gradle/src/utils/exec-gradle.ts b/packages/gradle/src/utils/exec-gradle.ts index 19628bf684..543db1efd5 100644 --- a/packages/gradle/src/utils/exec-gradle.ts +++ b/packages/gradle/src/utils/exec-gradle.ts @@ -4,6 +4,14 @@ import { existsSync } from 'node:fs'; import { dirname, join } from 'node:path'; import { LARGE_BUFFER } from 'nx/src/executors/run-commands/run-commands.impl'; +export const fileSeparator = process.platform.startsWith('win') + ? 'file:///' + : 'file://'; + +export const newLineSeparator = process.platform.startsWith('win') + ? '\r\n' + : '\n'; + /** * For gradle command, it needs to be run from the directory of the gradle binary * @returns gradle binary file name @@ -54,13 +62,13 @@ export function execGradleAsync( /** * This function recursively finds the nearest gradlew file in the workspace - * @param originalFileToSearch the original file to search for + * @param originalFileToSearch the original file to search for, relative to workspace root, file path not directory path * @param wr workspace root * @param currentSearchPath the path to start searching for gradlew file * @returns the relative path of the gradlew file to workspace root, throws an error if gradlew file is not found - * It will return gradlew.bat file on windows and gradlew file on other platforms + * It will return relative path to workspace root of gradlew.bat file on windows and gradlew file on other platforms */ -export function findGraldewFile( +export function findGradlewFile( originalFileToSearch: string, wr: string = workspaceRoot, currentSearchPath?: string @@ -92,5 +100,5 @@ export function findGraldewFile( } } - return findGraldewFile(originalFileToSearch, wr, parent); + return findGradlewFile(originalFileToSearch, wr, parent); } diff --git a/packages/gradle/src/utils/split-config-files.ts b/packages/gradle/src/utils/split-config-files.ts index 2869107e88..ab0ee9e95a 100644 --- a/packages/gradle/src/utils/split-config-files.ts +++ b/packages/gradle/src/utils/split-config-files.ts @@ -8,6 +8,8 @@ export const GRADLE_TEST_FILES = [ '**/src/test/kotlin/**/*Test.kt', '**/src/test/java/**/*Tests.java', '**/src/test/kotlin/**/*Tests.kt', + '**/src/test/groovy/**/*Test.groovy', + '**/src/test/groovy/**/*Tests.groovy', ]; export const gradleConfigGlob = combineGlobPatterns( diff --git a/packages/gradle/src/utils/versions.ts b/packages/gradle/src/utils/versions.ts index e268dc8f82..5de3983d9b 100644 --- a/packages/gradle/src/utils/versions.ts +++ b/packages/gradle/src/utils/versions.ts @@ -1 +1,4 @@ export const nxVersion = require('../../package.json').version; + +export const gradleProjectGraphPluginName = 'dev.nx.gradle.project-graph'; +export const gradleProjectGraphVersion = '0.0.2'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 74bcfd8c8c..92ef571584 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -90,6 +90,9 @@ importers: fast-glob: specifier: 3.3.3 version: 3.3.3 + form-data: + specifier: ^4.0.2 + version: 4.0.2 framer-motion: specifier: ^11.3.0 version: 11.5.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -174,7 +177,7 @@ importers: version: 0.1902.0(chokidar@3.6.0) '@angular-devkit/build-angular': specifier: 19.2.0 - version: 19.2.0(stndy3yfcthbju7r3pdqp75gku) + version: 19.2.0(fiob6yppbuzqqpw7bpjs7r5k6m) '@angular-devkit/core': specifier: 19.2.0 version: 19.2.0(chokidar@3.6.0) @@ -264,7 +267,7 @@ importers: version: 1.38.0 '@module-federation/enhanced': specifier: ^0.9.0 - version: 0.9.0(@rspack/core@1.2.6(@swc/helpers@0.5.11))(bufferutil@4.0.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + version: 0.9.1(@rspack/core@1.2.6(@swc/helpers@0.5.11))(bufferutil@4.0.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(webpack@5.98.0) '@module-federation/sdk': specifier: ^0.9.0 version: 0.9.0 @@ -279,7 +282,7 @@ importers: version: 0.2.4 '@nestjs/cli': specifier: ^10.0.2 - version: 10.4.5(@swc/cli@0.6.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(chokidar@3.6.0))(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + version: 10.4.5(@swc/cli@0.6.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(chokidar@3.6.0))(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) '@nestjs/common': specifier: ^9.0.0 version: 9.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1) @@ -294,10 +297,10 @@ importers: version: 9.2.0(chokidar@3.6.0)(typescript@5.7.3) '@nestjs/swagger': specifier: ^6.0.0 - version: 6.3.0(@nestjs/common@9.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@9.4.3(@nestjs/common@9.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@9.4.3)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1))(reflect-metadata@0.2.2) + version: 6.3.0(@nestjs/common@9.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@9.4.3)(reflect-metadata@0.2.2) '@nestjs/testing': specifier: ^9.0.0 - version: 9.4.3(@nestjs/common@9.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@9.4.3(@nestjs/common@9.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@9.4.3)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@9.4.3(@nestjs/common@9.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@9.4.3)) + version: 9.4.3(@nestjs/common@9.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@9.4.3)(@nestjs/platform-express@9.4.3) '@notionhq/client': specifier: ^2.2.15 version: 2.2.15(encoding@0.1.13) @@ -309,7 +312,7 @@ importers: version: 3.13.2(rollup@4.22.0)(webpack-sources@3.2.3) '@nx/angular': specifier: 21.0.0-beta.4 - version: 21.0.0-beta.4(m2fpeifx3zewnwiuits4v2eyjm) + version: 21.0.0-beta.4(j4dvvmbta2x4s76qau4q2xjbhy) '@nx/cypress': specifier: 21.0.0-beta.4 version: 21.0.0-beta.4(@babel/traverse@7.26.9)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(@zkochan/js-yaml@0.0.7)(cypress@14.3.0)(eslint@8.57.0)(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) @@ -336,7 +339,7 @@ importers: version: 1.3.0-beta.11 '@nx/next': specifier: 21.0.0-beta.4 - version: 21.0.0-beta.4(m6qvbv3x7azwoqxph4efgoxvje) + version: 21.0.0-beta.4(@babel/core@7.25.2)(@babel/traverse@7.26.9)(@rspack/core@1.2.6(@swc/helpers@0.5.11))(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/helpers@0.5.11)(@zkochan/js-yaml@0.0.7)(bufferutil@4.0.7)(esbuild@0.25.0)(eslint@8.57.0)(html-webpack-plugin@5.5.0(webpack@5.98.0))(next@14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))(webpack-cli@5.1.4)(webpack@5.98.0) '@nx/playwright': specifier: 21.0.0-beta.4 version: 21.0.0-beta.4(@babel/traverse@7.26.9)(@playwright/test@1.47.1)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(@zkochan/js-yaml@0.0.7)(eslint@8.57.0)(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) @@ -351,13 +354,13 @@ importers: version: 1.3.0-beta.11 '@nx/react': specifier: 21.0.0-beta.4 - version: 21.0.0-beta.4(@babel/traverse@7.26.9)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/helpers@0.5.11)(@zkochan/js-yaml@0.0.7)(bufferutil@4.0.7)(esbuild@0.25.0)(eslint@8.57.0)(next@14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + version: 21.0.0-beta.4(@babel/traverse@7.26.9)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/helpers@0.5.11)(@zkochan/js-yaml@0.0.7)(bufferutil@4.0.7)(esbuild@0.25.0)(eslint@8.57.0)(next@14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))(webpack-cli@5.1.4)(webpack@5.98.0) '@nx/rsbuild': specifier: 21.0.0-beta.4 version: 21.0.0-beta.4(@babel/traverse@7.26.9)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) '@nx/rspack': specifier: 21.0.0-beta.4 - version: 21.0.0-beta.4(3rkozrjia44o7a5hsza4wqcyli) + version: 21.0.0-beta.4(2mm4hostrwli5jitdy3fuo43oa) '@nx/storybook': specifier: 21.0.0-beta.4 version: 21.0.0-beta.4(@babel/traverse@7.26.9)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(@zkochan/js-yaml@0.0.7)(cypress@14.3.0)(eslint@8.57.0)(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) @@ -369,7 +372,7 @@ importers: version: 21.0.0-beta.4(@babel/traverse@7.26.9)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) '@nx/webpack': specifier: 21.0.0-beta.4 - version: 21.0.0-beta.4(@babel/traverse@7.26.9)(@rspack/core@1.2.6(@swc/helpers@0.5.11))(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(bufferutil@4.0.7)(esbuild@0.25.0)(html-webpack-plugin@5.5.0(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + version: 21.0.0-beta.4(@babel/traverse@7.26.9)(@rspack/core@1.2.6(@swc/helpers@0.5.11))(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(bufferutil@4.0.7)(esbuild@0.25.0)(html-webpack-plugin@5.5.0(webpack@5.98.0))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))(webpack-cli@5.1.4) '@phenomnomnominal/tsquery': specifier: ~5.0.1 version: 5.0.1(typescript@5.7.3) @@ -378,7 +381,7 @@ importers: version: 1.47.1 '@pmmmwh/react-refresh-webpack-plugin': specifier: ^0.5.7 - version: 0.5.15(react-refresh@0.10.0)(type-fest@3.13.1)(webpack-dev-server@5.2.1(bufferutil@4.0.7)(webpack-cli@5.1.4)(webpack@5.98.0))(webpack-hot-middleware@2.26.1)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + version: 0.5.15(react-refresh@0.10.0)(type-fest@3.13.1)(webpack-dev-server@5.2.1)(webpack-hot-middleware@2.26.1)(webpack@5.98.0) '@pnpm/lockfile-types': specifier: ^6.0.0 version: 6.0.0 @@ -417,7 +420,7 @@ importers: version: 1.2.6(@swc/helpers@0.5.11) '@rspack/dev-server': specifier: 1.0.9 - version: 1.0.9(@rspack/core@1.2.6(@swc/helpers@0.5.11))(@types/express@4.17.21)(bufferutil@4.0.7)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + version: 1.0.9(@rspack/core@1.2.6(@swc/helpers@0.5.11))(@types/express@4.17.21)(bufferutil@4.0.7)(webpack-cli@5.1.4)(webpack@5.98.0) '@rspack/plugin-minify': specifier: ^0.7.5 version: 0.7.5 @@ -444,7 +447,7 @@ importers: version: 8.4.6(@storybook/test@8.5.1(storybook@8.4.6(bufferutil@4.0.7)(prettier@2.8.8)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.22.0)(storybook@8.4.6(bufferutil@4.0.7)(prettier@2.8.8))(typescript@5.7.3)(vite@6.2.0(@types/node@20.16.10)(jiti@1.21.6)(less@4.1.3)(sass-embedded@1.85.1)(sass@1.55.0)(stylus@0.64.0)(terser@5.39.0)(yaml@2.6.1))(webpack-sources@3.2.3) '@storybook/react-webpack5': specifier: 8.4.6 - version: 8.4.6(@rspack/core@1.2.6(@swc/helpers@0.5.11))(@storybook/test@8.5.1(storybook@8.4.6(bufferutil@4.0.7)(prettier@2.8.8)))(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.6(bufferutil@4.0.7)(prettier@2.8.8))(typescript@5.7.3)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + version: 8.4.6(@rspack/core@1.2.6(@swc/helpers@0.5.11))(@storybook/test@8.5.1(storybook@8.4.6(bufferutil@4.0.7)(prettier@2.8.8)))(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.6(bufferutil@4.0.7)(prettier@2.8.8))(typescript@5.7.3)(webpack-cli@5.1.4) '@storybook/test': specifier: ^8.5.1 version: 8.5.1(storybook@8.4.6(bufferutil@4.0.7)(prettier@2.8.8)) @@ -612,7 +615,7 @@ importers: version: 29.7.0(@babel/core@7.25.2) babel-loader: specifier: ^9.1.2 - version: 9.2.1(@babel/core@7.25.2)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + version: 9.2.1(@babel/core@7.25.2)(webpack@5.98.0) browserslist: specifier: ^4.21.4 version: 4.23.3 @@ -639,10 +642,10 @@ importers: version: 2.0.0 copy-webpack-plugin: specifier: ^10.2.4 - version: 10.2.4(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + version: 10.2.4(webpack@5.98.0) css-minimizer-webpack-plugin: specifier: ^5.0.0 - version: 5.0.1(esbuild@0.25.0)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + version: 5.0.1(esbuild@0.25.0)(webpack@5.98.0) cypress: specifier: 14.3.0 version: 14.3.0 @@ -732,7 +735,7 @@ importers: version: 5.0.2 fork-ts-checker-webpack-plugin: specifier: 7.2.13 - version: 7.2.13(typescript@5.7.3)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + version: 7.2.13(typescript@5.7.3)(webpack@5.98.0) fs-extra: specifier: ^11.1.0 version: 11.2.0 @@ -750,7 +753,7 @@ importers: version: 4.7.7 html-webpack-plugin: specifier: 5.5.0 - version: 5.5.0(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + version: 5.5.0(webpack@5.98.0) http-proxy-middleware: specifier: ^3.0.3 version: 3.0.3 @@ -831,10 +834,10 @@ importers: version: 4.1.3 less-loader: specifier: 11.1.0 - version: 11.1.0(less@4.1.3)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + version: 11.1.0(less@4.1.3)(webpack@5.98.0) license-webpack-plugin: specifier: ^4.0.2 - version: 4.0.2(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + version: 4.0.2(webpack@5.98.0) lines-and-columns: specifier: 2.0.3 version: 2.0.3 @@ -867,7 +870,7 @@ importers: version: 0.80.12 mini-css-extract-plugin: specifier: ~2.4.7 - version: 2.4.7(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + version: 2.4.7(webpack@5.98.0) minimatch: specifier: 9.0.3 version: 9.0.3 @@ -975,13 +978,13 @@ importers: version: 1.85.1 sass-loader: specifier: 16.0.5 - version: 16.0.5(@rspack/core@1.2.6(@swc/helpers@0.5.11))(sass-embedded@1.85.1)(sass@1.55.0)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + version: 16.0.5(@rspack/core@1.2.6(@swc/helpers@0.5.11))(sass-embedded@1.85.1)(sass@1.55.0)(webpack@5.98.0) semver: specifier: ^7.6.3 version: 7.6.3 source-map-loader: specifier: ^5.0.0 - version: 5.0.0(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + version: 5.0.0(webpack@5.98.0) source-map-support: specifier: 0.5.19 version: 0.5.19 @@ -993,7 +996,7 @@ importers: version: 4.0.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.6(bufferutil@4.0.7)(prettier@2.8.8)) style-loader: specifier: ^3.3.0 - version: 3.3.4(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + version: 3.3.4(webpack@5.98.0) tar-stream: specifier: ~2.2.0 version: 2.2.0 @@ -1002,7 +1005,7 @@ importers: version: 1.0.2 terser-webpack-plugin: specifier: ^5.3.3 - version: 5.3.10(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + version: 5.3.10(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack@5.98.0) tmp: specifier: ~0.2.1 version: 0.2.3 @@ -1014,7 +1017,7 @@ importers: version: 29.1.0(@babel/core@7.25.2)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.25.2))(esbuild@0.25.0)(jest@29.7.0(@types/node@20.16.10)(babel-plugin-macros@3.1.0)(ts-node@10.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@types/node@20.16.10)(typescript@5.7.3)))(typescript@5.7.3) ts-loader: specifier: ^9.3.1 - version: 9.5.1(typescript@5.7.3)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + version: 9.5.1(typescript@5.7.3)(webpack@5.98.0) ts-node: specifier: 10.9.1 version: 10.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@types/node@20.16.10)(typescript@5.7.3) @@ -1053,10 +1056,10 @@ importers: version: 3.0.5(@types/debug@4.1.12)(@types/node@20.16.10)(jiti@1.21.6)(jsdom@20.0.3(bufferutil@4.0.7))(less@4.1.3)(sass-embedded@1.85.1)(sass@1.55.0)(stylus@0.64.0)(terser@5.39.0)(yaml@2.6.1) webpack: specifier: 5.98.0 - version: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + version: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) webpack-dev-server: specifier: 5.2.1 - version: 5.2.1(bufferutil@4.0.7)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + version: 5.2.1(bufferutil@4.0.7)(webpack-cli@5.1.4)(webpack@5.98.0) webpack-merge: specifier: ^5.8.0 version: 5.10.0 @@ -1065,7 +1068,7 @@ importers: version: 3.0.0 webpack-subresource-integrity: specifier: ^5.1.0 - version: 5.1.0(html-webpack-plugin@5.5.0(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + version: 5.1.0(html-webpack-plugin@5.5.0(webpack@5.98.0))(webpack@5.98.0) xstate: specifier: 4.34.0 version: 4.34.0 @@ -4672,33 +4675,15 @@ packages: '@mediapipe/tasks-vision@0.10.8': resolution: {integrity: sha512-Rp7ll8BHrKB3wXaRFKhrltwZl1CiXGdibPxuWXvqGnKTnv8fqa/nvftYNuSbf+pbJWKYCXdBtYTITdAUTGGh0Q==} - '@module-federation/bridge-react-webpack-plugin@0.9.0': - resolution: {integrity: sha512-EaUMMmNVx5IRXB8o39tPU05uWuDN38noQbUjwE2xi8Y5xTx3CFZ9tkgXX+tvzcWc+bu4RnaziaI0RtyBfHhHKw==} - '@module-federation/bridge-react-webpack-plugin@0.9.1': resolution: {integrity: sha512-znN/Qm6M0U1t3iF10gu1hSxDkk18yz78yvk+AMB34UDzpXHiC1zbpIeV2CQNV5GCeafmCICmcn9y1qh7F54KTg==} - '@module-federation/data-prefetch@0.9.0': - resolution: {integrity: sha512-KFC3lOzW/Hwvcgm/tn7075fqC/ONhA+5zPqDz090EsCQqnWQHodzx0XF88/tTvWdfc3mYK9BGYfsnpjlVGT1zA==} - peerDependencies: - react: '>=16.9.0' - react-dom: '>=16.9.0' - '@module-federation/data-prefetch@0.9.1': resolution: {integrity: sha512-rS1AsgRvIMAWK8oMprEBF0YQ3WvsqnumjinvAZU1Dqut5DICmpQMTPEO1OrAKyjO+PQgEhmq13HggzN6ebGLrQ==} peerDependencies: react: '>=16.9.0' react-dom: '>=16.9.0' - '@module-federation/dts-plugin@0.9.0': - resolution: {integrity: sha512-2Uu1sPRT9/uB+pG4vQGkLdpsMVM6FK7howulTdy42u6Dz0c2Ivc//od/noM0KEgWf1p54FAtWzpjkqjO5PyciA==} - peerDependencies: - typescript: ^4.9.0 || ^5.0.0 - vue-tsc: '>=1.0.24' - peerDependenciesMeta: - vue-tsc: - optional: true - '@module-federation/dts-plugin@0.9.1': resolution: {integrity: sha512-DezBrFaIKfDcEY7UhqyO1WbYocERYsR/CDN8AV6OvMnRlQ8u0rgM8qBUJwx0s+K59f+CFQFKEN4C8p7naCiHrw==} peerDependencies: @@ -4708,20 +4693,6 @@ packages: vue-tsc: optional: true - '@module-federation/enhanced@0.9.0': - resolution: {integrity: sha512-/fiIc+lZvP7pEiVWe0/0v2ueVcEumew2UNewguHFj3bxyyU5/+/5rHPRV5QIKcLzydrVLvTiS4/dB2Mqd7CVAg==} - peerDependencies: - typescript: ^4.9.0 || ^5.0.0 - vue-tsc: '>=1.0.24' - webpack: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true - vue-tsc: - optional: true - webpack: - optional: true - '@module-federation/enhanced@0.9.1': resolution: {integrity: sha512-c9siKVjcgT2gtDdOTqEr+GaP2X/PWAS0OV424ljKLstFL1lcS/BIsxWFDmxPPl5hDByAH+1q4YhC1LWY4LNDQw==} peerDependencies: @@ -4739,31 +4710,17 @@ packages: '@module-federation/error-codes@0.8.4': resolution: {integrity: sha512-55LYmrDdKb4jt+qr8qE8U3al62ZANp3FhfVaNPOaAmdTh0jHdD8M3yf5HKFlr5xVkVO4eV/F/J2NCfpbh+pEXQ==} - '@module-federation/error-codes@0.9.0': - resolution: {integrity: sha512-dNqIs5cQfE4p+WIdiZ64cTSRJ5KjGaV+epvZkGttrNjXW9XAAtE7zgpo7cMQ8GWA3wCGaKnFw7Dn48XcU5ZMNw==} - '@module-federation/error-codes@0.9.1': resolution: {integrity: sha512-q8spCvlwUzW42iX1irnlBTcwcZftRNHyGdlaoFO1z/fW4iphnBIfijzkigWQzOMhdPgzqN/up7XN+g5hjBGBtw==} - '@module-federation/inject-external-runtime-core-plugin@0.9.0': - resolution: {integrity: sha512-gDvYmcJyuXy1qzBZ6c+AndQUm50iOXmc56C2GN+F9ILAOQ/dcWFfD+OxyjXr80Pvej6qawW9CTEEWHNF4m4a+w==} - peerDependencies: - '@module-federation/runtime-tools': 0.9.0 - '@module-federation/inject-external-runtime-core-plugin@0.9.1': resolution: {integrity: sha512-BPfzu1cqDU5BhM493enVF1VfxJWmruen0ktlHrWdJJlcddhZzyFBGaLAGoGc+83fS75aEllvJTEthw4kMViMQQ==} peerDependencies: '@module-federation/runtime-tools': 0.9.1 - '@module-federation/managers@0.9.0': - resolution: {integrity: sha512-km8fVdS/r3TRLbSCV8IytKaQVuMbXbHvdZsgK4HRIWqGyBbA2q+gbXfWSC90OhdxNA9hhPEipmx+4hvuXDwaFg==} - '@module-federation/managers@0.9.1': resolution: {integrity: sha512-8hpIrvGfiODxS1qelTd7eaLRVF7jrp17RWgeH1DWoprxELANxm5IVvqUryB+7j+BhoQzamog9DL5q4MuNfGgIA==} - '@module-federation/manifest@0.9.0': - resolution: {integrity: sha512-o6+AyKdznP/Pyd6x/1staafUKNxIuXbmmpZxeL3VDvg8uR+6QM5bd/iXnBUgxaznIGQvUwvW/F1JixdgXwp7ug==} - '@module-federation/manifest@0.9.1': resolution: {integrity: sha512-+GteKBXrAUkq49i2CSyWZXM4vYa+mEVXxR9Du71R55nXXxgbzAIoZj9gxjRunj9pcE8+YpAOyfHxLEdWngxWdg==} @@ -4782,18 +4739,6 @@ packages: react-dom: optional: true - '@module-federation/rspack@0.9.0': - resolution: {integrity: sha512-Cw5/OGknuPwmkWc3jVj+T/uqtQ33cxDVMuaFIA6qGAiy/WfMyElKnOBe0n3JRaigH/A8qkyN/rNvMynYlTczLA==} - peerDependencies: - '@rspack/core': '>=0.7' - typescript: ^4.9.0 || ^5.0.0 - vue-tsc: '>=1.0.24' - peerDependenciesMeta: - typescript: - optional: true - vue-tsc: - optional: true - '@module-federation/rspack@0.9.1': resolution: {integrity: sha512-ZJqG75dWHhyTMa9I0YPJEV2XRt0MFxnDiuMOpI92esdmwWY633CBKyNh1XxcLd629YVeTv03+whr+Fz/f91JEw==} peerDependencies: @@ -4806,9 +4751,6 @@ packages: vue-tsc: optional: true - '@module-federation/runtime-core@0.6.21': - resolution: {integrity: sha512-CLQiPP3kpcPbgPkiu/A1VURI2v4geFnEdizlB1tq0c6eDZqb5aLzvp87ZCGDVSuwY7DCq6jh1k+CM2WGge/2xA==} - '@module-federation/runtime-core@0.9.1': resolution: {integrity: sha512-r61ufhKt5pjl81v7TkmhzeIoSPOaNtLynW6+aCy3KZMa3RfRevFxmygJqv4Nug1L0NhqUeWtdLejh4VIglNy5Q==} @@ -4818,9 +4760,6 @@ packages: '@module-federation/runtime-tools@0.8.4': resolution: {integrity: sha512-fjVOsItJ1u5YY6E9FnS56UDwZgqEQUrWFnouRiPtK123LUuqUI9FH4redZoKWlE1PB0ir1Z3tnqy8eFYzPO38Q==} - '@module-federation/runtime-tools@0.9.0': - resolution: {integrity: sha512-ioYVUsUfQjS7tgRBpZ6KFbz8YET2wD/2KmrO4zVaVHZ3RPyJzwVP9sLlDDdyf/Cn/1sQjNLg57FpyBADmY5M1Q==} - '@module-federation/runtime-tools@0.9.1': resolution: {integrity: sha512-JQZ//ab+lEXoU2DHAH+JtYASGzxEjXB0s4rU+6VJXc8c+oUPxH3kWIwzjdncg2mcWBmC1140DCk+K+kDfOZ5CQ==} @@ -4830,9 +4769,6 @@ packages: '@module-federation/runtime@0.8.4': resolution: {integrity: sha512-yZeZ7z2Rx4gv/0E97oLTF3V6N25vglmwXGgoeju/W2YjsFvWzVtCDI7zRRb0mJhU6+jmSM8jP1DeQGbea/AiZQ==} - '@module-federation/runtime@0.9.0': - resolution: {integrity: sha512-WByDEbJ/9fEUBOQILQRYX9CpAjCEmiU1MBSRoTg0emRKBcE9Ms5vTBN0XVuO+3gZSeyk08SfmaLtnCaeHK8ABA==} - '@module-federation/runtime@0.9.1': resolution: {integrity: sha512-jp7K06weabM5BF5sruHr/VLyalO+cilvRDy7vdEBqq88O9mjc0RserD8J+AP4WTl3ZzU7/GRqwRsiwjjN913dA==} @@ -4848,9 +4784,6 @@ packages: '@module-federation/sdk@0.9.1': resolution: {integrity: sha512-YQonPTImgnCqZjE/A+3N2g3J5ypR6kx1tbBzc9toUANKr/dw/S63qlh/zHKzWQzxjjNNVMdXRtTMp07g3kgEWg==} - '@module-federation/third-party-dts-extractor@0.9.0': - resolution: {integrity: sha512-gNMiFxSAkyy85KmdcdapKOP0RVqfuhzosdj92T9xXxR9juuILNS0TtgKbgYwNwvDs/WjOhTON5gz2lsX0kFKRg==} - '@module-federation/third-party-dts-extractor@0.9.1': resolution: {integrity: sha512-KeIByP718hHyq+Mc53enZ419pZZ1fh9Ns6+/bYLkc3iCoJr/EDBeiLzkbMwh2AS4Qk57WW0yNC82xzf7r0Zrrw==} @@ -4875,9 +4808,6 @@ packages: '@module-federation/webpack-bundler-runtime@0.8.4': resolution: {integrity: sha512-HggROJhvHPUX7uqBD/XlajGygMNM1DG0+4OAkk8MBQe4a18QzrRNzZt6XQbRTSG4OaEoyRWhQHvYD3Yps405tQ==} - '@module-federation/webpack-bundler-runtime@0.9.0': - resolution: {integrity: sha512-banXhVcgNYTqH13C6E9KrpwJ+UHaTvHfkvCRPs1y2EVvB9guPO6MnQ9Fd1DCwVMfpq3zMtJpPHobAqF5AmkCHQ==} - '@module-federation/webpack-bundler-runtime@0.9.1': resolution: {integrity: sha512-CxySX01gT8cBowKl9xZh+voiHvThMZ471icasWnlDIZb14KasZoX1eCh9wpGvwoOdIk9rIRT7h70UvW9nmop6w==} @@ -9184,12 +9114,6 @@ packages: acorn-globals@7.0.1: resolution: {integrity: sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==} - acorn-import-assertions@1.9.0: - resolution: {integrity: sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==} - deprecated: package has been renamed to acorn-import-attributes - peerDependencies: - acorn: ^8 - acorn-import-attributes@1.9.5: resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} peerDependencies: @@ -11440,10 +11364,6 @@ packages: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} - es-set-tostringtag@2.0.3: - resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} - engines: {node: '>= 0.4'} - es-set-tostringtag@2.1.0: resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} @@ -11594,27 +11514,6 @@ packages: eslint-plugin-import-x: optional: true - eslint-module-utils@2.11.0: - resolution: {integrity: sha512-gbBE5Hitek/oG6MUVj6sFuzEjA/ClzNflVrLovHi/JgLdC7fiN5gLAY1WIPW1a0V5I999MnsrvVrCOGmmVqDBQ==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true - eslint-module-utils@2.12.0: resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} engines: {node: '>=4'} @@ -12177,8 +12076,8 @@ packages: resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==} engines: {node: '>= 14.17'} - form-data@4.0.0: - resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + form-data@4.0.2: + resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==} engines: {node: '>= 6'} format@0.2.2: @@ -19956,16 +19855,6 @@ packages: webpack-virtual-modules@0.6.2: resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} - webpack@5.88.0: - resolution: {integrity: sha512-O3jDhG5e44qIBSi/P6KpcCcH7HD+nYIHVBhdWFxcLOcIGN8zGo5nqF3BjyNCxIh4p1vFdNnreZv2h2KkoAw3lw==} - engines: {node: '>=10.13.0'} - hasBin: true - peerDependencies: - webpack-cli: '*' - peerDependenciesMeta: - webpack-cli: - optional: true - webpack@5.94.0: resolution: {integrity: sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==} engines: {node: '>=10.13.0'} @@ -20444,11 +20333,11 @@ snapshots: transitivePeerDependencies: - chokidar - '@angular-devkit/build-angular@19.2.0(stndy3yfcthbju7r3pdqp75gku)': + '@angular-devkit/build-angular@19.2.0(fiob6yppbuzqqpw7bpjs7r5k6m)': dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.1902.0(chokidar@3.6.0) - '@angular-devkit/build-webpack': 0.1902.0(chokidar@3.6.0)(webpack-dev-server@5.2.0(bufferutil@4.0.7)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + '@angular-devkit/build-webpack': 0.1902.0(chokidar@3.6.0)(webpack-dev-server@5.2.0(bufferutil@4.0.7)(webpack-cli@5.1.4)(webpack@5.98.0))(webpack@5.98.0) '@angular-devkit/core': 19.2.0(chokidar@3.6.0) '@angular/build': 19.2.0(cxjrqumqlcnastohrhciqzxvse) '@angular/compiler-cli': 19.2.0(@angular/compiler@19.2.0(@angular/core@19.2.0(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.7.3) @@ -20462,14 +20351,14 @@ snapshots: '@babel/preset-env': 7.26.9(@babel/core@7.26.9) '@babel/runtime': 7.26.9 '@discoveryjs/json-ext': 0.6.3 - '@ngtools/webpack': 19.2.0(@angular/compiler-cli@19.2.0(@angular/compiler@19.2.0(@angular/core@19.2.0(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.7.3))(typescript@5.7.3)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + '@ngtools/webpack': 19.2.0(@angular/compiler-cli@19.2.0(@angular/compiler@19.2.0(@angular/core@19.2.0(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.7.3))(typescript@5.7.3)(webpack@5.98.0) '@vitejs/plugin-basic-ssl': 1.2.0(vite@6.2.0(@types/node@20.16.10)(jiti@1.21.6)(less@4.1.3)(sass-embedded@1.85.1)(sass@1.55.0)(stylus@0.64.0)(terser@5.39.0)(yaml@2.6.1)) ansi-colors: 4.1.3 autoprefixer: 10.4.20(postcss@8.5.2) - babel-loader: 9.2.1(@babel/core@7.26.9)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + babel-loader: 9.2.1(@babel/core@7.26.9)(webpack@5.98.0) browserslist: 4.24.4 - copy-webpack-plugin: 12.0.2(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) - css-loader: 7.1.2(@rspack/core@1.2.6(@swc/helpers@0.5.11))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + copy-webpack-plugin: 12.0.2(webpack@5.98.0) + css-loader: 7.1.2(@rspack/core@1.2.6(@swc/helpers@0.5.11))(webpack@5.98.0) esbuild-wasm: 0.25.0 fast-glob: 3.3.3 http-proxy-middleware: 3.0.3 @@ -20477,32 +20366,32 @@ snapshots: jsonc-parser: 3.3.1 karma-source-map-support: 1.4.0 less: 4.2.2 - less-loader: 12.2.0(@rspack/core@1.2.6(@swc/helpers@0.5.11))(less@4.2.2)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) - license-webpack-plugin: 4.0.2(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + less-loader: 12.2.0(@rspack/core@1.2.6(@swc/helpers@0.5.11))(less@4.2.2)(webpack@5.98.0) + license-webpack-plugin: 4.0.2(webpack@5.98.0) loader-utils: 3.3.1 - mini-css-extract-plugin: 2.9.2(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + mini-css-extract-plugin: 2.9.2(webpack@5.98.0) open: 10.1.0 ora: 5.4.1 picomatch: 4.0.2 piscina: 4.8.0 postcss: 8.5.2 - postcss-loader: 8.1.1(@rspack/core@1.2.6(@swc/helpers@0.5.11))(postcss@8.5.2)(typescript@5.7.3)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + postcss-loader: 8.1.1(@rspack/core@1.2.6(@swc/helpers@0.5.11))(postcss@8.5.2)(typescript@5.7.3)(webpack@5.98.0) resolve-url-loader: 5.0.0 rxjs: 7.8.1 sass: 1.85.0 - sass-loader: 16.0.5(@rspack/core@1.2.6(@swc/helpers@0.5.11))(sass-embedded@1.85.1)(sass@1.85.0)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + sass-loader: 16.0.5(@rspack/core@1.2.6(@swc/helpers@0.5.11))(sass-embedded@1.85.1)(sass@1.85.0)(webpack@5.98.0) semver: 7.7.1 - source-map-loader: 5.0.0(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + source-map-loader: 5.0.0(webpack@5.98.0) source-map-support: 0.5.21 terser: 5.39.0 tree-kill: 1.2.2 tslib: 2.8.1 typescript: 5.7.3 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) - webpack-dev-middleware: 7.4.2(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) - webpack-dev-server: 5.2.0(bufferutil@4.0.7)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) + webpack-dev-middleware: 7.4.2(webpack@5.98.0) + webpack-dev-server: 5.2.0(bufferutil@4.0.7)(webpack-cli@5.1.4)(webpack@5.98.0) webpack-merge: 6.0.1 - webpack-subresource-integrity: 5.1.0(html-webpack-plugin@5.5.0(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + webpack-subresource-integrity: 5.1.0(html-webpack-plugin@5.5.0(webpack@5.98.0))(webpack@5.98.0) optionalDependencies: '@angular/ssr': 19.2.0(@angular/common@19.2.0(@angular/core@19.2.0(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1))(@angular/core@19.2.0(rxjs@7.8.1)(zone.js@0.14.10))(@angular/router@19.2.0(@angular/common@19.2.0(@angular/core@19.2.0(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1))(@angular/core@19.2.0(rxjs@7.8.1)(zone.js@0.14.10))(@angular/platform-browser@18.2.5(@angular/common@19.2.0(@angular/core@19.2.0(rxjs@7.8.1)(zone.js@0.14.10))(rxjs@7.8.1))(@angular/core@19.2.0(rxjs@7.8.1)(zone.js@0.14.10)))(rxjs@7.8.1)) esbuild: 0.25.0 @@ -20533,12 +20422,12 @@ snapshots: - webpack-cli - yaml - '@angular-devkit/build-webpack@0.1902.0(chokidar@3.6.0)(webpack-dev-server@5.2.0(bufferutil@4.0.7)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)))': + '@angular-devkit/build-webpack@0.1902.0(chokidar@3.6.0)(webpack-dev-server@5.2.0(bufferutil@4.0.7)(webpack-cli@5.1.4)(webpack@5.98.0))(webpack@5.98.0)': dependencies: '@angular-devkit/architect': 0.1902.0(chokidar@3.6.0) rxjs: 7.8.1 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) - webpack-dev-server: 5.2.0(bufferutil@4.0.7)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) + webpack-dev-server: 5.2.0(bufferutil@4.0.7)(webpack-cli@5.1.4)(webpack@5.98.0) transitivePeerDependencies: - chokidar @@ -23260,7 +23149,7 @@ snapshots: combined-stream: 1.0.8 extend: 3.0.2 forever-agent: 0.6.1 - form-data: 4.0.0 + form-data: 4.0.2 http-signature: 1.4.0 is-typedarray: 1.0.0 isstream: 0.1.2 @@ -23281,7 +23170,7 @@ snapshots: combined-stream: 1.0.8 extend: 3.0.2 forever-agent: 0.6.1 - form-data: 4.0.0 + form-data: 4.0.2 http-signature: 1.4.0 is-typedarray: 1.0.0 isstream: 0.1.2 @@ -24700,26 +24589,12 @@ snapshots: '@mediapipe/tasks-vision@0.10.8': {} - '@module-federation/bridge-react-webpack-plugin@0.9.0': - dependencies: - '@module-federation/sdk': 0.9.0 - '@types/semver': 7.5.8 - semver: 7.6.3 - '@module-federation/bridge-react-webpack-plugin@0.9.1': dependencies: '@module-federation/sdk': 0.9.1 '@types/semver': 7.5.8 semver: 7.6.3 - '@module-federation/data-prefetch@0.9.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@module-federation/runtime': 0.9.0 - '@module-federation/sdk': 0.9.0 - fs-extra: 9.1.0 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - '@module-federation/data-prefetch@0.9.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@module-federation/runtime': 0.9.1 @@ -24728,31 +24603,6 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@module-federation/dts-plugin@0.9.0(bufferutil@4.0.7)(typescript@5.7.3)': - dependencies: - '@module-federation/error-codes': 0.9.0 - '@module-federation/managers': 0.9.0 - '@module-federation/sdk': 0.9.0 - '@module-federation/third-party-dts-extractor': 0.9.0 - adm-zip: 0.5.16 - ansi-colors: 4.1.3 - axios: 1.8.3 - chalk: 3.0.0 - fs-extra: 9.1.0 - isomorphic-ws: 5.0.0(ws@8.18.0(bufferutil@4.0.7)) - koa: 2.15.4 - lodash.clonedeepwith: 4.5.0 - log4js: 6.9.1 - node-schedule: 2.1.1 - rambda: 9.3.0 - typescript: 5.7.3 - ws: 8.18.0(bufferutil@4.0.7) - transitivePeerDependencies: - - bufferutil - - debug - - supports-color - - utf-8-validate - '@module-federation/dts-plugin@0.9.1(bufferutil@4.0.7)(typescript@5.7.3)': dependencies: '@module-federation/error-codes': 0.9.1 @@ -24778,33 +24628,7 @@ snapshots: - supports-color - utf-8-validate - '@module-federation/enhanced@0.9.0(@rspack/core@1.2.6(@swc/helpers@0.5.11))(bufferutil@4.0.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)))': - dependencies: - '@module-federation/bridge-react-webpack-plugin': 0.9.0 - '@module-federation/data-prefetch': 0.9.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@module-federation/dts-plugin': 0.9.0(bufferutil@4.0.7)(typescript@5.7.3) - '@module-federation/error-codes': 0.9.0 - '@module-federation/inject-external-runtime-core-plugin': 0.9.0(@module-federation/runtime-tools@0.9.0) - '@module-federation/managers': 0.9.0 - '@module-federation/manifest': 0.9.0(bufferutil@4.0.7)(typescript@5.7.3) - '@module-federation/rspack': 0.9.0(@rspack/core@1.2.6(@swc/helpers@0.5.11))(bufferutil@4.0.7)(typescript@5.7.3) - '@module-federation/runtime-tools': 0.9.0 - '@module-federation/sdk': 0.9.0 - btoa: 1.2.1 - upath: 2.0.1 - optionalDependencies: - typescript: 5.7.3 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) - transitivePeerDependencies: - - '@rspack/core' - - bufferutil - - debug - - react - - react-dom - - supports-color - - utf-8-validate - - '@module-federation/enhanced@0.9.1(@rspack/core@1.2.6(@swc/helpers@0.5.11))(bufferutil@4.0.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)))': + '@module-federation/enhanced@0.9.1(@rspack/core@1.2.6(@swc/helpers@0.5.11))(bufferutil@4.0.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(webpack@5.98.0)': dependencies: '@module-federation/bridge-react-webpack-plugin': 0.9.1 '@module-federation/data-prefetch': 0.9.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -24820,7 +24644,7 @@ snapshots: upath: 2.0.1 optionalDependencies: typescript: 5.7.3 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) transitivePeerDependencies: - '@rspack/core' - bufferutil @@ -24832,45 +24656,18 @@ snapshots: '@module-federation/error-codes@0.8.4': {} - '@module-federation/error-codes@0.9.0': {} - '@module-federation/error-codes@0.9.1': {} - '@module-federation/inject-external-runtime-core-plugin@0.9.0(@module-federation/runtime-tools@0.9.0)': - dependencies: - '@module-federation/runtime-tools': 0.9.0 - '@module-federation/inject-external-runtime-core-plugin@0.9.1(@module-federation/runtime-tools@0.9.1)': dependencies: '@module-federation/runtime-tools': 0.9.1 - '@module-federation/managers@0.9.0': - dependencies: - '@module-federation/sdk': 0.9.0 - find-pkg: 2.0.0 - fs-extra: 9.1.0 - '@module-federation/managers@0.9.1': dependencies: '@module-federation/sdk': 0.9.1 find-pkg: 2.0.0 fs-extra: 9.1.0 - '@module-federation/manifest@0.9.0(bufferutil@4.0.7)(typescript@5.7.3)': - dependencies: - '@module-federation/dts-plugin': 0.9.0(bufferutil@4.0.7)(typescript@5.7.3) - '@module-federation/managers': 0.9.0 - '@module-federation/sdk': 0.9.0 - chalk: 3.0.0 - find-pkg: 2.0.0 - transitivePeerDependencies: - - bufferutil - - debug - - supports-color - - typescript - - utf-8-validate - - vue-tsc - '@module-federation/manifest@0.9.1(bufferutil@4.0.7)(typescript@5.7.3)': dependencies: '@module-federation/dts-plugin': 0.9.1(bufferutil@4.0.7)(typescript@5.7.3) @@ -24886,16 +24683,16 @@ snapshots: - utf-8-validate - vue-tsc - '@module-federation/node@2.6.27(@rspack/core@1.2.6(@swc/helpers@0.5.11))(bufferutil@4.0.7)(next@14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)))': + '@module-federation/node@2.6.27(@rspack/core@1.2.6(@swc/helpers@0.5.11))(bufferutil@4.0.7)(next@14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(webpack@5.98.0)': dependencies: - '@module-federation/enhanced': 0.9.1(@rspack/core@1.2.6(@swc/helpers@0.5.11))(bufferutil@4.0.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + '@module-federation/enhanced': 0.9.1(@rspack/core@1.2.6(@swc/helpers@0.5.11))(bufferutil@4.0.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(webpack@5.98.0) '@module-federation/runtime': 0.9.1 '@module-federation/sdk': 0.9.1 - '@module-federation/utilities': 3.1.45(next@14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + '@module-federation/utilities': 3.1.45(next@14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(webpack@5.98.0) btoa: 1.2.1 encoding: 0.1.13 node-fetch: 2.7.0(encoding@0.1.13) - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) optionalDependencies: next: 14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0) react: 18.3.1 @@ -24909,24 +24706,6 @@ snapshots: - utf-8-validate - vue-tsc - '@module-federation/rspack@0.9.0(@rspack/core@1.2.6(@swc/helpers@0.5.11))(bufferutil@4.0.7)(typescript@5.7.3)': - dependencies: - '@module-federation/bridge-react-webpack-plugin': 0.9.0 - '@module-federation/dts-plugin': 0.9.0(bufferutil@4.0.7)(typescript@5.7.3) - '@module-federation/inject-external-runtime-core-plugin': 0.9.0(@module-federation/runtime-tools@0.9.0) - '@module-federation/managers': 0.9.0 - '@module-federation/manifest': 0.9.0(bufferutil@4.0.7)(typescript@5.7.3) - '@module-federation/runtime-tools': 0.9.0 - '@module-federation/sdk': 0.9.0 - '@rspack/core': 1.2.6(@swc/helpers@0.5.11) - optionalDependencies: - typescript: 5.7.3 - transitivePeerDependencies: - - bufferutil - - debug - - supports-color - - utf-8-validate - '@module-federation/rspack@0.9.1(@rspack/core@1.2.6(@swc/helpers@0.5.11))(bufferutil@4.0.7)(typescript@5.7.3)': dependencies: '@module-federation/bridge-react-webpack-plugin': 0.9.1 @@ -24945,11 +24724,6 @@ snapshots: - supports-color - utf-8-validate - '@module-federation/runtime-core@0.6.21': - dependencies: - '@module-federation/error-codes': 0.9.0 - '@module-federation/sdk': 0.9.0 - '@module-federation/runtime-core@0.9.1': dependencies: '@module-federation/error-codes': 0.9.1 @@ -24965,11 +24739,6 @@ snapshots: '@module-federation/runtime': 0.8.4 '@module-federation/webpack-bundler-runtime': 0.8.4 - '@module-federation/runtime-tools@0.9.0': - dependencies: - '@module-federation/runtime': 0.9.0 - '@module-federation/webpack-bundler-runtime': 0.9.0 - '@module-federation/runtime-tools@0.9.1': dependencies: '@module-federation/runtime': 0.9.1 @@ -24984,12 +24753,6 @@ snapshots: '@module-federation/error-codes': 0.8.4 '@module-federation/sdk': 0.8.4 - '@module-federation/runtime@0.9.0': - dependencies: - '@module-federation/error-codes': 0.9.0 - '@module-federation/runtime-core': 0.6.21 - '@module-federation/sdk': 0.9.0 - '@module-federation/runtime@0.9.1': dependencies: '@module-federation/error-codes': 0.9.1 @@ -25008,22 +24771,16 @@ snapshots: '@module-federation/sdk@0.9.1': {} - '@module-federation/third-party-dts-extractor@0.9.0': - dependencies: - find-pkg: 2.0.0 - fs-extra: 9.1.0 - resolve: 1.22.8 - '@module-federation/third-party-dts-extractor@0.9.1': dependencies: find-pkg: 2.0.0 fs-extra: 9.1.0 resolve: 1.22.8 - '@module-federation/utilities@3.1.45(next@14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)))': + '@module-federation/utilities@3.1.45(next@14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(webpack@5.98.0)': dependencies: '@module-federation/sdk': 0.9.1 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) optionalDependencies: next: 14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0) react: 18.3.1 @@ -25039,11 +24796,6 @@ snapshots: '@module-federation/runtime': 0.8.4 '@module-federation/sdk': 0.8.4 - '@module-federation/webpack-bundler-runtime@0.9.0': - dependencies: - '@module-federation/runtime': 0.9.0 - '@module-federation/sdk': 0.9.0 - '@module-federation/webpack-bundler-runtime@0.9.1': dependencies: '@module-federation/runtime': 0.9.1 @@ -25448,7 +25200,7 @@ snapshots: '@napi-rs/wasm-tools-win32-ia32-msvc': 0.0.2 '@napi-rs/wasm-tools-win32-x64-msvc': 0.0.2 - '@nestjs/cli@10.4.5(@swc/cli@0.6.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(chokidar@3.6.0))(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))': + '@nestjs/cli@10.4.5(@swc/cli@0.6.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(chokidar@3.6.0))(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4)': dependencies: '@angular-devkit/core': 17.3.8(chokidar@3.6.0) '@angular-devkit/schematics': 17.3.8(chokidar@3.6.0) @@ -25458,7 +25210,7 @@ snapshots: chokidar: 3.6.0 cli-table3: 0.6.5 commander: 4.1.1 - fork-ts-checker-webpack-plugin: 9.0.2(typescript@5.3.3)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + fork-ts-checker-webpack-plugin: 9.0.2(typescript@5.3.3)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4)) glob: 10.4.2 inquirer: 8.2.6 node-emoji: 1.11.0 @@ -25467,7 +25219,7 @@ snapshots: tsconfig-paths: 4.2.0 tsconfig-paths-webpack-plugin: 4.1.0 typescript: 5.3.3 - webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) webpack-node-externals: 3.0.0 optionalDependencies: '@swc/cli': 0.6.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(chokidar@3.6.0) @@ -25539,7 +25291,7 @@ snapshots: transitivePeerDependencies: - chokidar - '@nestjs/swagger@6.3.0(@nestjs/common@9.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@9.4.3(@nestjs/common@9.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@9.4.3)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1))(reflect-metadata@0.2.2)': + '@nestjs/swagger@6.3.0(@nestjs/common@9.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@9.4.3)(reflect-metadata@0.2.2)': dependencies: '@nestjs/common': 9.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1) '@nestjs/core': 9.4.3(@nestjs/common@9.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@9.4.3)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) @@ -25550,7 +25302,7 @@ snapshots: reflect-metadata: 0.2.2 swagger-ui-dist: 4.18.2 - '@nestjs/testing@9.4.3(@nestjs/common@9.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@9.4.3(@nestjs/common@9.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@9.4.3)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@9.4.3(@nestjs/common@9.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@9.4.3))': + '@nestjs/testing@9.4.3(@nestjs/common@9.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/core@9.4.3)(@nestjs/platform-express@9.4.3)': dependencies: '@nestjs/common': 9.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1) '@nestjs/core': 9.4.3(@nestjs/common@9.4.3(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@9.4.3)(encoding@0.1.13)(reflect-metadata@0.2.2)(rxjs@7.8.1) @@ -25602,11 +25354,11 @@ snapshots: '@next/swc-win32-x64-msvc@14.2.28': optional: true - '@ngtools/webpack@19.2.0(@angular/compiler-cli@19.2.0(@angular/compiler@19.2.0(@angular/core@19.2.0(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.7.3))(typescript@5.7.3)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)))': + '@ngtools/webpack@19.2.0(@angular/compiler-cli@19.2.0(@angular/compiler@19.2.0(@angular/core@19.2.0(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.7.3))(typescript@5.7.3)(webpack@5.98.0)': dependencies: '@angular/compiler-cli': 19.2.0(@angular/compiler@19.2.0(@angular/core@19.2.0(rxjs@7.8.1)(zone.js@0.14.10)))(typescript@5.7.3) typescript: 5.7.3 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) '@nodelib/fs.scandir@2.1.5': dependencies: @@ -25953,18 +25705,18 @@ snapshots: transitivePeerDependencies: - encoding - '@nx/angular@21.0.0-beta.4(m2fpeifx3zewnwiuits4v2eyjm)': + '@nx/angular@21.0.0-beta.4(j4dvvmbta2x4s76qau4q2xjbhy)': dependencies: - '@angular-devkit/build-angular': 19.2.0(stndy3yfcthbju7r3pdqp75gku) + '@angular-devkit/build-angular': 19.2.0(fiob6yppbuzqqpw7bpjs7r5k6m) '@angular-devkit/core': 19.2.0(chokidar@3.6.0) '@angular-devkit/schematics': 19.2.0(chokidar@3.6.0) '@nx/devkit': 21.0.0-beta.4(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))) '@nx/eslint': 21.0.0-beta.4(@babel/traverse@7.26.9)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(@zkochan/js-yaml@0.0.7)(eslint@8.57.0)(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) '@nx/js': 21.0.0-beta.4(@babel/traverse@7.26.9)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) - '@nx/module-federation': 21.0.0-beta.4(@babel/traverse@7.26.9)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/helpers@0.5.11)(bufferutil@4.0.7)(esbuild@0.25.0)(next@14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) - '@nx/rspack': 21.0.0-beta.4(3rkozrjia44o7a5hsza4wqcyli) + '@nx/module-federation': 21.0.0-beta.4(@babel/traverse@7.26.9)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/helpers@0.5.11)(bufferutil@4.0.7)(esbuild@0.25.0)(next@14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))(webpack-cli@5.1.4) + '@nx/rspack': 21.0.0-beta.4(2mm4hostrwli5jitdy3fuo43oa) '@nx/web': 21.0.0-beta.4(@babel/traverse@7.26.9)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) - '@nx/webpack': 21.0.0-beta.4(@babel/traverse@7.26.9)(@rspack/core@1.2.6(@swc/helpers@0.5.11))(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(bufferutil@4.0.7)(esbuild@0.25.0)(html-webpack-plugin@5.5.0(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + '@nx/webpack': 21.0.0-beta.4(@babel/traverse@7.26.9)(@rspack/core@1.2.6(@swc/helpers@0.5.11))(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(bufferutil@4.0.7)(esbuild@0.25.0)(html-webpack-plugin@5.5.0(webpack@5.98.0))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))(webpack-cli@5.1.4) '@nx/workspace': 21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)) '@phenomnomnominal/tsquery': 5.0.1(typescript@5.7.3) '@schematics/angular': 19.2.0(chokidar@3.6.0) @@ -26278,10 +26030,10 @@ snapshots: transitivePeerDependencies: - debug - '@nx/module-federation@21.0.0-beta.4(@babel/traverse@7.26.9)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/helpers@0.5.11)(bufferutil@4.0.7)(esbuild@0.25.0)(next@14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))': + '@nx/module-federation@21.0.0-beta.4(@babel/traverse@7.26.9)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/helpers@0.5.11)(bufferutil@4.0.7)(esbuild@0.25.0)(next@14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))(webpack-cli@5.1.4)': dependencies: - '@module-federation/enhanced': 0.9.1(@rspack/core@1.2.6(@swc/helpers@0.5.11))(bufferutil@4.0.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) - '@module-federation/node': 2.6.27(@rspack/core@1.2.6(@swc/helpers@0.5.11))(bufferutil@4.0.7)(next@14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + '@module-federation/enhanced': 0.9.1(@rspack/core@1.2.6(@swc/helpers@0.5.11))(bufferutil@4.0.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(webpack@5.98.0) + '@module-federation/node': 2.6.27(@rspack/core@1.2.6(@swc/helpers@0.5.11))(bufferutil@4.0.7)(next@14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(webpack@5.98.0) '@module-federation/sdk': 0.9.1 '@nx/devkit': 21.0.0-beta.4(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))) '@nx/js': 21.0.0-beta.4(@babel/traverse@7.26.9)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) @@ -26291,7 +26043,7 @@ snapshots: http-proxy-middleware: 3.0.3 picocolors: 1.1.1 tslib: 2.8.1 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) transitivePeerDependencies: - '@babel/traverse' - '@rspack/tracing' @@ -26313,19 +26065,19 @@ snapshots: - vue-tsc - webpack-cli - '@nx/next@21.0.0-beta.4(m6qvbv3x7azwoqxph4efgoxvje)': + '@nx/next@21.0.0-beta.4(@babel/core@7.25.2)(@babel/traverse@7.26.9)(@rspack/core@1.2.6(@swc/helpers@0.5.11))(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/helpers@0.5.11)(@zkochan/js-yaml@0.0.7)(bufferutil@4.0.7)(esbuild@0.25.0)(eslint@8.57.0)(html-webpack-plugin@5.5.0(webpack@5.98.0))(next@14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))(webpack-cli@5.1.4)(webpack@5.98.0)': dependencies: '@babel/plugin-proposal-decorators': 7.24.7(@babel/core@7.25.2) '@nx/devkit': 21.0.0-beta.4(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))) '@nx/eslint': 21.0.0-beta.4(@babel/traverse@7.26.9)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(@zkochan/js-yaml@0.0.7)(eslint@8.57.0)(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) '@nx/js': 21.0.0-beta.4(@babel/traverse@7.26.9)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) - '@nx/react': 21.0.0-beta.4(@babel/traverse@7.26.9)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/helpers@0.5.11)(@zkochan/js-yaml@0.0.7)(bufferutil@4.0.7)(esbuild@0.25.0)(eslint@8.57.0)(next@14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + '@nx/react': 21.0.0-beta.4(@babel/traverse@7.26.9)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/helpers@0.5.11)(@zkochan/js-yaml@0.0.7)(bufferutil@4.0.7)(esbuild@0.25.0)(eslint@8.57.0)(next@14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))(webpack-cli@5.1.4)(webpack@5.98.0) '@nx/web': 21.0.0-beta.4(@babel/traverse@7.26.9)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) - '@nx/webpack': 21.0.0-beta.4(@babel/traverse@7.26.9)(@rspack/core@1.2.6(@swc/helpers@0.5.11))(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(bufferutil@4.0.7)(esbuild@0.25.0)(html-webpack-plugin@5.5.0(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + '@nx/webpack': 21.0.0-beta.4(@babel/traverse@7.26.9)(@rspack/core@1.2.6(@swc/helpers@0.5.11))(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(bufferutil@4.0.7)(esbuild@0.25.0)(html-webpack-plugin@5.5.0(webpack@5.98.0))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))(webpack-cli@5.1.4) '@phenomnomnominal/tsquery': 5.0.1(typescript@5.7.3) '@svgr/webpack': 8.1.0(typescript@5.7.3) - copy-webpack-plugin: 10.2.4(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) - file-loader: 6.2.0(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + copy-webpack-plugin: 10.2.4(webpack@5.98.0) + file-loader: 6.2.0(webpack@5.98.0) ignore: 5.3.2 next: 14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0) semver: 7.7.1 @@ -26437,17 +26189,17 @@ snapshots: transitivePeerDependencies: - debug - '@nx/react@21.0.0-beta.4(@babel/traverse@7.26.9)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/helpers@0.5.11)(@zkochan/js-yaml@0.0.7)(bufferutil@4.0.7)(esbuild@0.25.0)(eslint@8.57.0)(next@14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)))': + '@nx/react@21.0.0-beta.4(@babel/traverse@7.26.9)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/helpers@0.5.11)(@zkochan/js-yaml@0.0.7)(bufferutil@4.0.7)(esbuild@0.25.0)(eslint@8.57.0)(next@14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))(webpack-cli@5.1.4)(webpack@5.98.0)': dependencies: '@nx/devkit': 21.0.0-beta.4(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))) '@nx/eslint': 21.0.0-beta.4(@babel/traverse@7.26.9)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(@zkochan/js-yaml@0.0.7)(eslint@8.57.0)(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) '@nx/js': 21.0.0-beta.4(@babel/traverse@7.26.9)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) - '@nx/module-federation': 21.0.0-beta.4(@babel/traverse@7.26.9)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/helpers@0.5.11)(bufferutil@4.0.7)(esbuild@0.25.0)(next@14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + '@nx/module-federation': 21.0.0-beta.4(@babel/traverse@7.26.9)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/helpers@0.5.11)(bufferutil@4.0.7)(esbuild@0.25.0)(next@14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))(webpack-cli@5.1.4) '@nx/web': 21.0.0-beta.4(@babel/traverse@7.26.9)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) '@phenomnomnominal/tsquery': 5.0.1(typescript@5.7.3) '@svgr/webpack': 8.1.0(typescript@5.7.3) express: 4.21.2 - file-loader: 6.2.0(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + file-loader: 6.2.0(webpack@5.98.0) http-proxy-middleware: 3.0.3 minimatch: 9.0.3 picocolors: 1.1.1 @@ -26495,39 +26247,39 @@ snapshots: - typescript - verdaccio - '@nx/rspack@21.0.0-beta.4(3rkozrjia44o7a5hsza4wqcyli)': + '@nx/rspack@21.0.0-beta.4(2mm4hostrwli5jitdy3fuo43oa)': dependencies: - '@module-federation/enhanced': 0.9.0(@rspack/core@1.2.6(@swc/helpers@0.5.11))(bufferutil@4.0.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) - '@module-federation/node': 2.6.27(@rspack/core@1.2.6(@swc/helpers@0.5.11))(bufferutil@4.0.7)(next@14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + '@module-federation/enhanced': 0.9.1(@rspack/core@1.2.6(@swc/helpers@0.5.11))(bufferutil@4.0.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(webpack@5.98.0) + '@module-federation/node': 2.6.27(@rspack/core@1.2.6(@swc/helpers@0.5.11))(bufferutil@4.0.7)(next@14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(webpack@5.98.0) '@nx/devkit': 21.0.0-beta.4(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))) '@nx/js': 21.0.0-beta.4(@babel/traverse@7.26.9)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) - '@nx/module-federation': 21.0.0-beta.4(@babel/traverse@7.26.9)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/helpers@0.5.11)(bufferutil@4.0.7)(esbuild@0.25.0)(next@14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + '@nx/module-federation': 21.0.0-beta.4(@babel/traverse@7.26.9)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/helpers@0.5.11)(bufferutil@4.0.7)(esbuild@0.25.0)(next@14.2.28(@babel/core@7.25.2)(@opentelemetry/api@1.9.0)(@playwright/test@1.47.1)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.55.0))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))(webpack-cli@5.1.4) '@nx/web': 21.0.0-beta.4(@babel/traverse@7.26.9)(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0)) '@phenomnomnominal/tsquery': 5.0.1(typescript@5.7.3) '@rspack/core': 1.2.6(@swc/helpers@0.5.11) - '@rspack/dev-server': 1.0.9(@rspack/core@1.2.6(@swc/helpers@0.5.11))(@types/express@4.17.21)(bufferutil@4.0.7)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + '@rspack/dev-server': 1.0.9(@rspack/core@1.2.6(@swc/helpers@0.5.11))(@types/express@4.17.21)(bufferutil@4.0.7)(webpack-cli@5.1.4)(webpack@5.98.0) '@rspack/plugin-react-refresh': 1.0.0(react-refresh@0.10.0) autoprefixer: 10.4.13(postcss@8.4.38) browserslist: 4.24.4 - css-loader: 6.11.0(@rspack/core@1.2.6(@swc/helpers@0.5.11))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + css-loader: 6.11.0(@rspack/core@1.2.6(@swc/helpers@0.5.11))(webpack@5.98.0) enquirer: 2.3.6 express: 4.21.2 http-proxy-middleware: 3.0.3 - less-loader: 11.1.0(less@4.1.3)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) - license-webpack-plugin: 4.0.2(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + less-loader: 11.1.0(less@4.1.3)(webpack@5.98.0) + license-webpack-plugin: 4.0.2(webpack@5.98.0) loader-utils: 2.0.3 picocolors: 1.1.1 postcss: 8.4.38 postcss-import: 14.1.0(postcss@8.4.38) - postcss-loader: 8.1.1(@rspack/core@1.2.6(@swc/helpers@0.5.11))(postcss@8.4.38)(typescript@5.7.3)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + postcss-loader: 8.1.1(@rspack/core@1.2.6(@swc/helpers@0.5.11))(postcss@8.4.38)(typescript@5.7.3)(webpack@5.98.0) sass: 1.85.0 sass-embedded: 1.85.1 - sass-loader: 16.0.5(@rspack/core@1.2.6(@swc/helpers@0.5.11))(sass-embedded@1.85.1)(sass@1.85.0)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) - source-map-loader: 5.0.0(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) - style-loader: 3.3.4(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + sass-loader: 16.0.5(@rspack/core@1.2.6(@swc/helpers@0.5.11))(sass-embedded@1.85.1)(sass@1.85.0)(webpack@5.98.0) + source-map-loader: 5.0.0(webpack@5.98.0) + style-loader: 3.3.4(webpack@5.98.0) ts-checker-rspack-plugin: 1.1.1(@rspack/core@1.2.6(@swc/helpers@0.5.11))(typescript@5.7.3) tslib: 2.8.1 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) webpack-node-externals: 3.0.0 transitivePeerDependencies: - '@babel/traverse' @@ -26615,7 +26367,7 @@ snapshots: - supports-color - verdaccio - '@nx/webpack@21.0.0-beta.4(@babel/traverse@7.26.9)(@rspack/core@1.2.6(@swc/helpers@0.5.11))(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(bufferutil@4.0.7)(esbuild@0.25.0)(html-webpack-plugin@5.5.0(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))': + '@nx/webpack@21.0.0-beta.4(@babel/traverse@7.26.9)(@rspack/core@1.2.6(@swc/helpers@0.5.11))(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))(bufferutil@4.0.7)(esbuild@0.25.0)(html-webpack-plugin@5.5.0(webpack@5.98.0))(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(typescript@5.7.3)(verdaccio@6.0.5(encoding@0.1.13)(typanion@3.14.0))(webpack-cli@5.1.4)': dependencies: '@babel/core': 7.26.9 '@nx/devkit': 21.0.0-beta.4(nx@21.0.0-beta.4(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.21)(typescript@5.7.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))) @@ -26623,38 +26375,38 @@ snapshots: '@phenomnomnominal/tsquery': 5.0.1(typescript@5.7.3) ajv: 8.17.1 autoprefixer: 10.4.13(postcss@8.4.38) - babel-loader: 9.2.1(@babel/core@7.26.9)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + babel-loader: 9.2.1(@babel/core@7.26.9)(webpack@5.98.0) browserslist: 4.24.4 - copy-webpack-plugin: 10.2.4(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) - css-loader: 6.11.0(@rspack/core@1.2.6(@swc/helpers@0.5.11))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) - css-minimizer-webpack-plugin: 5.0.1(esbuild@0.25.0)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) - fork-ts-checker-webpack-plugin: 7.2.13(typescript@5.7.3)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + copy-webpack-plugin: 10.2.4(webpack@5.98.0) + css-loader: 6.11.0(@rspack/core@1.2.6(@swc/helpers@0.5.11))(webpack@5.98.0) + css-minimizer-webpack-plugin: 5.0.1(esbuild@0.25.0)(webpack@5.98.0) + fork-ts-checker-webpack-plugin: 7.2.13(typescript@5.7.3)(webpack@5.98.0) less: 4.1.3 - less-loader: 11.1.0(less@4.1.3)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) - license-webpack-plugin: 4.0.2(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + less-loader: 11.1.0(less@4.1.3)(webpack@5.98.0) + license-webpack-plugin: 4.0.2(webpack@5.98.0) loader-utils: 2.0.3 - mini-css-extract-plugin: 2.4.7(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + mini-css-extract-plugin: 2.4.7(webpack@5.98.0) parse5: 4.0.0 picocolors: 1.1.1 postcss: 8.4.38 postcss-import: 14.1.0(postcss@8.4.38) - postcss-loader: 6.2.1(postcss@8.4.38)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + postcss-loader: 6.2.1(postcss@8.4.38)(webpack@5.98.0) rxjs: 7.8.1 sass: 1.85.0 sass-embedded: 1.85.1 - sass-loader: 16.0.5(@rspack/core@1.2.6(@swc/helpers@0.5.11))(sass-embedded@1.85.1)(sass@1.85.0)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) - source-map-loader: 5.0.0(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) - style-loader: 3.3.4(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + sass-loader: 16.0.5(@rspack/core@1.2.6(@swc/helpers@0.5.11))(sass-embedded@1.85.1)(sass@1.85.0)(webpack@5.98.0) + source-map-loader: 5.0.0(webpack@5.98.0) + style-loader: 3.3.4(webpack@5.98.0) stylus: 0.64.0 - stylus-loader: 7.1.3(stylus@0.64.0)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) - terser-webpack-plugin: 5.3.11(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) - ts-loader: 9.5.1(typescript@5.7.3)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + stylus-loader: 7.1.3(stylus@0.64.0)(webpack@5.98.0) + terser-webpack-plugin: 5.3.11(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack@5.98.0) + ts-loader: 9.5.1(typescript@5.7.3)(webpack@5.98.0) tsconfig-paths-webpack-plugin: 4.0.0 tslib: 2.8.1 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) - webpack-dev-server: 5.2.1(bufferutil@4.0.7)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) + webpack-dev-server: 5.2.1(bufferutil@4.0.7)(webpack-cli@5.1.4)(webpack@5.98.0) webpack-node-externals: 3.0.0 - webpack-subresource-integrity: 5.1.0(html-webpack-plugin@5.5.0(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + webpack-subresource-integrity: 5.1.0(html-webpack-plugin@5.5.0(webpack@5.98.0))(webpack@5.98.0) transitivePeerDependencies: - '@babel/traverse' - '@parcel/css' @@ -27128,7 +26880,7 @@ snapshots: dependencies: playwright: 1.47.1 - '@pmmmwh/react-refresh-webpack-plugin@0.5.15(react-refresh@0.10.0)(type-fest@3.13.1)(webpack-dev-server@5.2.1(bufferutil@4.0.7)(webpack-cli@5.1.4)(webpack@5.98.0))(webpack-hot-middleware@2.26.1)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)))': + '@pmmmwh/react-refresh-webpack-plugin@0.5.15(react-refresh@0.10.0)(type-fest@3.13.1)(webpack-dev-server@5.2.1)(webpack-hot-middleware@2.26.1)(webpack@5.98.0)': dependencies: ansi-html: 0.0.9 core-js-pure: 3.38.1 @@ -27138,10 +26890,10 @@ snapshots: react-refresh: 0.10.0 schema-utils: 4.2.0 source-map: 0.7.3 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) optionalDependencies: type-fest: 3.13.1 - webpack-dev-server: 5.2.1(bufferutil@4.0.7)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + webpack-dev-server: 5.2.1(bufferutil@4.0.7)(webpack-cli@5.1.4)(webpack@5.98.0) webpack-hot-middleware: 2.26.1 '@pnpm/lockfile-types@6.0.0': @@ -28511,7 +28263,7 @@ snapshots: optionalDependencies: '@swc/helpers': 0.5.11 - '@rspack/dev-server@1.0.9(@rspack/core@1.2.6(@swc/helpers@0.5.11))(@types/express@4.17.21)(bufferutil@4.0.7)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)))': + '@rspack/dev-server@1.0.9(@rspack/core@1.2.6(@swc/helpers@0.5.11))(@types/express@4.17.21)(bufferutil@4.0.7)(webpack-cli@5.1.4)(webpack@5.98.0)': dependencies: '@rspack/core': 1.2.6(@swc/helpers@0.5.11) chokidar: 3.6.0 @@ -28520,8 +28272,8 @@ snapshots: http-proxy-middleware: 2.0.7(@types/express@4.17.21) mime-types: 2.1.35 p-retry: 4.6.2 - webpack-dev-middleware: 7.4.2(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) - webpack-dev-server: 5.0.4(bufferutil@4.0.7)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + webpack-dev-middleware: 7.4.2(webpack@5.98.0) + webpack-dev-server: 5.0.4(bufferutil@4.0.7)(webpack-cli@5.1.4)(webpack@5.98.0) ws: 8.18.0(bufferutil@4.0.7) transitivePeerDependencies: - '@types/express' @@ -28753,7 +28505,7 @@ snapshots: transitivePeerDependencies: - webpack-sources - '@storybook/builder-webpack5@8.4.6(@rspack/core@1.2.6(@swc/helpers@0.5.11))(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(storybook@8.4.6(bufferutil@4.0.7)(prettier@2.8.8))(typescript@5.7.3)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))': + '@storybook/builder-webpack5@8.4.6(@rspack/core@1.2.6(@swc/helpers@0.5.11))(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(storybook@8.4.6(bufferutil@4.0.7)(prettier@2.8.8))(typescript@5.7.3)(webpack-cli@5.1.4)': dependencies: '@storybook/core-webpack': 8.4.6(storybook@8.4.6(bufferutil@4.0.7)(prettier@2.8.8)) '@types/node': 22.5.5 @@ -28762,23 +28514,23 @@ snapshots: case-sensitive-paths-webpack-plugin: 2.4.0 cjs-module-lexer: 1.4.1 constants-browserify: 1.0.0 - css-loader: 6.11.0(@rspack/core@1.2.6(@swc/helpers@0.5.11))(webpack@5.88.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + css-loader: 6.11.0(@rspack/core@1.2.6(@swc/helpers@0.5.11))(webpack@5.98.0) es-module-lexer: 1.6.0 - fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.7.3)(webpack@5.88.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) - html-webpack-plugin: 5.5.0(webpack@5.88.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.7.3)(webpack@5.98.0) + html-webpack-plugin: 5.5.0(webpack@5.98.0) magic-string: 0.30.17 path-browserify: 1.0.1 process: 0.11.10 semver: 7.7.1 storybook: 8.4.6(bufferutil@4.0.7)(prettier@2.8.8) - style-loader: 3.3.4(webpack@5.88.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) - terser-webpack-plugin: 5.3.11(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack@5.88.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + style-loader: 3.3.4(webpack@5.98.0) + terser-webpack-plugin: 5.3.11(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack@5.98.0) ts-dedent: 2.2.0 url: 0.11.4 util: 0.12.5 util-deprecate: 1.0.2 - webpack: 5.88.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) - webpack-dev-middleware: 6.1.3(webpack@5.88.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) + webpack-dev-middleware: 6.1.3(webpack@5.98.0) webpack-hot-middleware: 2.26.1 webpack-virtual-modules: 0.6.2 optionalDependencies: @@ -28878,11 +28630,11 @@ snapshots: dependencies: storybook: 8.4.6(bufferutil@4.0.7)(prettier@2.8.8) - '@storybook/preset-react-webpack@8.4.6(@storybook/test@8.5.1(storybook@8.4.6(bufferutil@4.0.7)(prettier@2.8.8)))(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.6(bufferutil@4.0.7)(prettier@2.8.8))(typescript@5.7.3)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))': + '@storybook/preset-react-webpack@8.4.6(@storybook/test@8.5.1(storybook@8.4.6(bufferutil@4.0.7)(prettier@2.8.8)))(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.6(bufferutil@4.0.7)(prettier@2.8.8))(typescript@5.7.3)(webpack-cli@5.1.4)': dependencies: '@storybook/core-webpack': 8.4.6(storybook@8.4.6(bufferutil@4.0.7)(prettier@2.8.8)) '@storybook/react': 8.4.6(@storybook/test@8.5.1(storybook@8.4.6(bufferutil@4.0.7)(prettier@2.8.8)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.6(bufferutil@4.0.7)(prettier@2.8.8))(typescript@5.7.3) - '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.7.3)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.7.3)(webpack@5.98.0) '@types/node': 22.5.5 '@types/semver': 7.5.8 find-up: 5.0.0 @@ -28894,7 +28646,7 @@ snapshots: semver: 7.7.1 storybook: 8.4.6(bufferutil@4.0.7)(prettier@2.8.8) tsconfig-paths: 4.2.0 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) optionalDependencies: typescript: 5.7.3 transitivePeerDependencies: @@ -28909,7 +28661,7 @@ snapshots: dependencies: storybook: 8.4.6(bufferutil@4.0.7)(prettier@2.8.8) - '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.7.3)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)))': + '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.7.3)(webpack@5.98.0)': dependencies: debug: 4.4.0(supports-color@8.1.1) endent: 2.1.0 @@ -28919,7 +28671,7 @@ snapshots: react-docgen-typescript: 2.2.2(typescript@5.7.3) tslib: 2.8.1 typescript: 5.7.3 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) transitivePeerDependencies: - supports-color @@ -28951,10 +28703,10 @@ snapshots: - typescript - webpack-sources - '@storybook/react-webpack5@8.4.6(@rspack/core@1.2.6(@swc/helpers@0.5.11))(@storybook/test@8.5.1(storybook@8.4.6(bufferutil@4.0.7)(prettier@2.8.8)))(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.6(bufferutil@4.0.7)(prettier@2.8.8))(typescript@5.7.3)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))': + '@storybook/react-webpack5@8.4.6(@rspack/core@1.2.6(@swc/helpers@0.5.11))(@storybook/test@8.5.1(storybook@8.4.6(bufferutil@4.0.7)(prettier@2.8.8)))(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.6(bufferutil@4.0.7)(prettier@2.8.8))(typescript@5.7.3)(webpack-cli@5.1.4)': dependencies: - '@storybook/builder-webpack5': 8.4.6(@rspack/core@1.2.6(@swc/helpers@0.5.11))(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(storybook@8.4.6(bufferutil@4.0.7)(prettier@2.8.8))(typescript@5.7.3)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) - '@storybook/preset-react-webpack': 8.4.6(@storybook/test@8.5.1(storybook@8.4.6(bufferutil@4.0.7)(prettier@2.8.8)))(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.6(bufferutil@4.0.7)(prettier@2.8.8))(typescript@5.7.3)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + '@storybook/builder-webpack5': 8.4.6(@rspack/core@1.2.6(@swc/helpers@0.5.11))(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(storybook@8.4.6(bufferutil@4.0.7)(prettier@2.8.8))(typescript@5.7.3)(webpack-cli@5.1.4) + '@storybook/preset-react-webpack': 8.4.6(@storybook/test@8.5.1(storybook@8.4.6(bufferutil@4.0.7)(prettier@2.8.8)))(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.6(bufferutil@4.0.7)(prettier@2.8.8))(typescript@5.7.3)(webpack-cli@5.1.4) '@storybook/react': 8.4.6(@storybook/test@8.5.1(storybook@8.4.6(bufferutil@4.0.7)(prettier@2.8.8)))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(storybook@8.4.6(bufferutil@4.0.7)(prettier@2.8.8))(typescript@5.7.3) '@types/node': 22.5.5 react: 18.3.1 @@ -29786,7 +29538,7 @@ snapshots: '@types/node-fetch@2.6.11': dependencies: '@types/node': 20.16.10 - form-data: 4.0.0 + form-data: 4.0.2 '@types/node-forge@1.3.11': dependencies: @@ -30939,22 +30691,22 @@ snapshots: '@webcontainer/api@1.5.1': {} - '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)))': + '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4)(webpack@5.98.0)': dependencies: - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0) - '@webpack-cli/info@2.0.2(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)))': + '@webpack-cli/info@2.0.2(webpack-cli@5.1.4)(webpack@5.98.0)': dependencies: - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0) - '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))(webpack-dev-server@5.2.1(bufferutil@4.0.7)(webpack-cli@5.1.4)(webpack@5.98.0))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)))': + '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4)(webpack-dev-server@5.2.1)(webpack@5.98.0)': dependencies: - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0) optionalDependencies: - webpack-dev-server: 5.2.1(bufferutil@4.0.7)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + webpack-dev-server: 5.2.1(bufferutil@4.0.7)(webpack-cli@5.1.4)(webpack@5.98.0) '@xhmikosr/archive-type@7.0.0': dependencies: @@ -31100,10 +30852,6 @@ snapshots: acorn: 8.14.0 acorn-walk: 8.3.4 - acorn-import-assertions@1.9.0(acorn@8.12.1): - dependencies: - acorn: 8.12.1 - acorn-import-attributes@1.9.5(acorn@8.14.0): dependencies: acorn: 8.14.0 @@ -31437,7 +31185,7 @@ snapshots: define-properties: 1.2.1 es-abstract: 1.23.3 es-errors: 1.3.0 - get-intrinsic: 1.2.4 + get-intrinsic: 1.3.0 is-array-buffer: 3.0.4 is-shared-array-buffer: 1.0.3 @@ -31636,7 +31384,7 @@ snapshots: axios@1.8.3: dependencies: follow-redirects: 1.15.9(debug@4.3.7) - form-data: 4.0.0 + form-data: 4.0.2 proxy-from-env: 1.1.0 transitivePeerDependencies: - debug @@ -31671,19 +31419,19 @@ snapshots: transitivePeerDependencies: - supports-color - babel-loader@9.2.1(@babel/core@7.25.2)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + babel-loader@9.2.1(@babel/core@7.25.2)(webpack@5.98.0): dependencies: '@babel/core': 7.25.2 find-cache-dir: 4.0.0 schema-utils: 4.2.0 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) - babel-loader@9.2.1(@babel/core@7.26.9)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + babel-loader@9.2.1(@babel/core@7.26.9)(webpack@5.98.0): dependencies: '@babel/core': 7.26.9 find-cache-dir: 4.0.0 schema-utils: 4.2.0 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) babel-plugin-const-enum@1.2.0(@babel/core@7.26.9): dependencies: @@ -32185,14 +31933,14 @@ snapshots: es-define-property: 1.0.0 es-errors: 1.3.0 function-bind: 1.1.2 - get-intrinsic: 1.2.4 + get-intrinsic: 1.3.0 set-function-length: 1.2.2 call-bind@1.0.8: dependencies: call-bind-apply-helpers: 1.0.2 es-define-property: 1.0.0 - get-intrinsic: 1.2.4 + get-intrinsic: 1.3.0 set-function-length: 1.2.2 call-bound@1.0.4: @@ -32776,7 +32524,7 @@ snapshots: dependencies: toggle-selection: 1.0.6 - copy-webpack-plugin@10.2.4(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + copy-webpack-plugin@10.2.4(webpack@5.98.0): dependencies: fast-glob: 3.3.3 glob-parent: 6.0.2 @@ -32784,9 +32532,9 @@ snapshots: normalize-path: 3.0.0 schema-utils: 4.2.0 serialize-javascript: 6.0.2 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) - copy-webpack-plugin@12.0.2(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + copy-webpack-plugin@12.0.2(webpack@5.98.0): dependencies: fast-glob: 3.3.3 glob-parent: 6.0.2 @@ -32794,7 +32542,7 @@ snapshots: normalize-path: 3.0.0 schema-utils: 4.3.0 serialize-javascript: 6.0.2 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) core-js-compat@3.38.1: dependencies: @@ -32935,7 +32683,7 @@ snapshots: postcss: 8.4.38 postcss-selector-parser: 6.1.2 - css-loader@6.11.0(@rspack/core@1.2.6(@swc/helpers@0.5.11))(webpack@5.88.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + css-loader@6.11.0(@rspack/core@1.2.6(@swc/helpers@0.5.11))(webpack@5.98.0): dependencies: icss-utils: 5.1.0(postcss@8.4.38) postcss: 8.4.38 @@ -32947,9 +32695,9 @@ snapshots: semver: 7.7.1 optionalDependencies: '@rspack/core': 1.2.6(@swc/helpers@0.5.11) - webpack: 5.88.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) - css-loader@6.11.0(@rspack/core@1.2.6(@swc/helpers@0.5.11))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + css-loader@7.1.2(@rspack/core@1.2.6(@swc/helpers@0.5.11))(webpack@5.98.0): dependencies: icss-utils: 5.1.0(postcss@8.4.38) postcss: 8.4.38 @@ -32961,23 +32709,9 @@ snapshots: semver: 7.7.1 optionalDependencies: '@rspack/core': 1.2.6(@swc/helpers@0.5.11) - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) - css-loader@7.1.2(@rspack/core@1.2.6(@swc/helpers@0.5.11))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): - dependencies: - icss-utils: 5.1.0(postcss@8.4.38) - postcss: 8.4.38 - postcss-modules-extract-imports: 3.1.0(postcss@8.4.38) - postcss-modules-local-by-default: 4.0.5(postcss@8.4.38) - postcss-modules-scope: 3.2.0(postcss@8.4.38) - postcss-modules-values: 4.0.0(postcss@8.4.38) - postcss-value-parser: 4.2.0 - semver: 7.7.1 - optionalDependencies: - '@rspack/core': 1.2.6(@swc/helpers@0.5.11) - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) - - css-minimizer-webpack-plugin@5.0.1(esbuild@0.25.0)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + css-minimizer-webpack-plugin@5.0.1(esbuild@0.25.0)(webpack@5.98.0): dependencies: '@jridgewell/trace-mapping': 0.3.25 cssnano: 6.1.2(postcss@8.4.38) @@ -32985,7 +32719,7 @@ snapshots: postcss: 8.4.38 schema-utils: 4.2.0 serialize-javascript: 6.0.2 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) optionalDependencies: esbuild: 0.25.0 @@ -33714,10 +33448,10 @@ snapshots: es-define-property: 1.0.0 es-errors: 1.3.0 es-object-atoms: 1.0.0 - es-set-tostringtag: 2.0.3 + es-set-tostringtag: 2.1.0 es-to-primitive: 1.2.1 function.prototype.name: 1.1.6 - get-intrinsic: 1.2.4 + get-intrinsic: 1.3.0 get-symbol-description: 1.0.2 globalthis: 1.0.4 gopd: 1.0.1 @@ -33763,7 +33497,7 @@ snapshots: data-view-byte-offset: 1.0.1 es-define-property: 1.0.1 es-errors: 1.3.0 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 es-set-tostringtag: 2.1.0 es-to-primitive: 1.3.0 function.prototype.name: 1.1.8 @@ -33807,7 +33541,7 @@ snapshots: es-define-property@1.0.0: dependencies: - get-intrinsic: 1.2.4 + get-intrinsic: 1.3.0 es-define-property@1.0.1: {} @@ -33819,7 +33553,7 @@ snapshots: define-properties: 1.2.1 es-abstract: 1.23.3 es-errors: 1.3.0 - es-set-tostringtag: 2.0.3 + es-set-tostringtag: 2.1.0 function-bind: 1.1.2 get-intrinsic: 1.2.4 globalthis: 1.0.4 @@ -33836,7 +33570,7 @@ snapshots: define-properties: 1.2.1 es-abstract: 1.23.3 es-errors: 1.3.0 - es-set-tostringtag: 2.0.3 + es-set-tostringtag: 2.1.0 function-bind: 1.1.2 get-intrinsic: 1.2.4 globalthis: 1.0.4 @@ -33854,7 +33588,7 @@ snapshots: define-properties: 1.2.1 es-abstract: 1.23.9 es-errors: 1.3.0 - es-set-tostringtag: 2.0.3 + es-set-tostringtag: 2.1.0 function-bind: 1.1.2 get-intrinsic: 1.3.0 globalthis: 1.0.4 @@ -33878,12 +33612,6 @@ snapshots: dependencies: es-errors: 1.3.0 - es-set-tostringtag@2.0.3: - dependencies: - get-intrinsic: 1.2.4 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - es-set-tostringtag@2.1.0: dependencies: es-errors: 1.3.0 @@ -34230,7 +33958,7 @@ snapshots: debug: 4.4.0(supports-color@8.1.1) enhanced-resolve: 5.17.1 eslint: 8.57.0 - eslint-module-utils: 2.11.0(@typescript-eslint/parser@8.20.0(eslint@8.57.0)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.20.0(eslint@8.57.0)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.20.0(eslint@8.57.0)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0) fast-glob: 3.3.3 get-tsconfig: 4.8.1 is-bun-module: 1.2.1 @@ -34243,18 +33971,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-module-utils@2.11.0(@typescript-eslint/parser@8.20.0(eslint@8.57.0)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.20.0(eslint@8.57.0)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0): - dependencies: - debug: 3.2.7(supports-color@8.1.1) - optionalDependencies: - '@typescript-eslint/parser': 8.20.0(eslint@8.57.0)(typescript@5.7.3) - eslint: 8.57.0 - eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.20.0(eslint@8.57.0)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.0) - transitivePeerDependencies: - - supports-color - - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.20.0(eslint@8.57.0)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.20.0(eslint@8.57.0)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.20.0(eslint@8.57.0)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0): dependencies: debug: 3.2.7(supports-color@8.1.1) optionalDependencies: @@ -34281,7 +33998,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.20.0(eslint@8.57.0)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.20.0(eslint@8.57.0)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@8.57.0))(eslint@8.57.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.20.0(eslint@8.57.0)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.0) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -34847,11 +34564,11 @@ snapshots: dependencies: flat-cache: 3.2.0 - file-loader@6.2.0(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + file-loader@6.2.0(webpack@5.98.0): dependencies: loader-utils: 2.0.3 schema-utils: 3.3.0 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) file-type@16.5.4: dependencies: @@ -35000,7 +34717,7 @@ snapshots: forever-agent@0.6.1: {} - fork-ts-checker-webpack-plugin@7.2.13(typescript@5.7.3)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + fork-ts-checker-webpack-plugin@7.2.13(typescript@5.7.3)(webpack@5.98.0): dependencies: '@babel/code-frame': 7.24.7 chalk: 4.1.2 @@ -35015,9 +34732,9 @@ snapshots: semver: 7.6.3 tapable: 2.2.1 typescript: 5.7.3 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) - fork-ts-checker-webpack-plugin@8.0.0(typescript@5.7.3)(webpack@5.88.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + fork-ts-checker-webpack-plugin@8.0.0(typescript@5.7.3)(webpack@5.98.0): dependencies: '@babel/code-frame': 7.26.2 chalk: 4.1.2 @@ -35032,9 +34749,9 @@ snapshots: semver: 7.7.1 tapable: 2.2.1 typescript: 5.7.3 - webpack: 5.88.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) - fork-ts-checker-webpack-plugin@9.0.2(typescript@5.3.3)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + fork-ts-checker-webpack-plugin@9.0.2(typescript@5.3.3)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4)): dependencies: '@babel/code-frame': 7.26.2 chalk: 4.1.2 @@ -35049,16 +34766,17 @@ snapshots: semver: 7.7.1 tapable: 2.2.1 typescript: 5.3.3 - webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) form-data-encoder@1.7.2: {} form-data-encoder@2.1.4: {} - form-data@4.0.0: + form-data@4.0.2: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 mime-types: 2.1.35 format@0.2.2: {} @@ -35236,7 +34954,7 @@ snapshots: dependencies: call-bind: 1.0.7 es-errors: 1.3.0 - get-intrinsic: 1.2.4 + get-intrinsic: 1.3.0 get-symbol-description@1.1.0: dependencies: @@ -35442,7 +35160,7 @@ snapshots: gopd@1.0.1: dependencies: - get-intrinsic: 1.2.4 + get-intrinsic: 1.3.0 gopd@1.2.0: {} @@ -35559,7 +35277,7 @@ snapshots: has-tostringtag@1.0.2: dependencies: - has-symbols: 1.0.3 + has-symbols: 1.1.0 has-unicode@2.0.1: {} @@ -35826,23 +35544,14 @@ snapshots: html-void-elements@3.0.0: {} - html-webpack-plugin@5.5.0(webpack@5.88.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + html-webpack-plugin@5.5.0(webpack@5.98.0): dependencies: '@types/html-minifier-terser': 6.1.0 html-minifier-terser: 6.1.0 lodash: 4.17.21 pretty-error: 4.0.0 tapable: 2.2.1 - webpack: 5.88.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) - - html-webpack-plugin@5.5.0(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): - dependencies: - '@types/html-minifier-terser': 6.1.0 - html-minifier-terser: 6.1.0 - lodash: 4.17.21 - pretty-error: 4.0.0 - tapable: 2.2.1 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) htmlparser2@6.1.0: dependencies: @@ -36230,7 +35939,7 @@ snapshots: is-array-buffer@3.0.4: dependencies: call-bind: 1.0.7 - get-intrinsic: 1.2.4 + get-intrinsic: 1.3.0 is-array-buffer@3.0.5: dependencies: @@ -36478,7 +36187,7 @@ snapshots: is-symbol@1.0.4: dependencies: - has-symbols: 1.0.3 + has-symbols: 1.1.0 is-symbol@1.1.1: dependencies: @@ -36613,7 +36322,7 @@ snapshots: iterator.prototype@1.1.2: dependencies: define-properties: 1.2.1 - get-intrinsic: 1.2.4 + get-intrinsic: 1.3.0 has-symbols: 1.0.3 reflect.getprototypeof: 1.0.6 set-function-name: 2.0.2 @@ -36621,7 +36330,7 @@ snapshots: iterator.prototype@1.1.3: dependencies: define-properties: 1.2.1 - get-intrinsic: 1.2.4 + get-intrinsic: 1.3.0 has-symbols: 1.0.3 reflect.getprototypeof: 1.0.6 set-function-name: 2.0.2 @@ -36629,7 +36338,7 @@ snapshots: iterator.prototype@1.1.5: dependencies: define-data-property: 1.1.4 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 get-intrinsic: 1.3.0 get-proto: 1.0.1 has-symbols: 1.1.0 @@ -37025,7 +36734,7 @@ snapshots: decimal.js: 10.4.3 domexception: 4.0.0 escodegen: 2.1.0 - form-data: 4.0.0 + form-data: 4.0.2 html-encoding-sniffer: 3.0.0 http-proxy-agent: 5.0.0 https-proxy-agent: 5.0.1 @@ -37262,18 +36971,18 @@ snapshots: dependencies: readable-stream: 2.3.8 - less-loader@11.1.0(less@4.1.3)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + less-loader@11.1.0(less@4.1.3)(webpack@5.98.0): dependencies: klona: 2.0.6 less: 4.1.3 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) - less-loader@12.2.0(@rspack/core@1.2.6(@swc/helpers@0.5.11))(less@4.2.2)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + less-loader@12.2.0(@rspack/core@1.2.6(@swc/helpers@0.5.11))(less@4.2.2)(webpack@5.98.0): dependencies: less: 4.2.2 optionalDependencies: '@rspack/core': 1.2.6(@swc/helpers@0.5.11) - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) less@4.1.3: dependencies: @@ -37325,11 +37034,11 @@ snapshots: transitivePeerDependencies: - supports-color - license-webpack-plugin@4.0.2(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + license-webpack-plugin@4.0.2(webpack@5.98.0): dependencies: webpack-sources: 3.2.3 optionalDependencies: - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) lie@3.3.0: dependencies: @@ -38787,16 +38496,16 @@ snapshots: min-indent@1.0.1: {} - mini-css-extract-plugin@2.4.7(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + mini-css-extract-plugin@2.4.7(webpack@5.98.0): dependencies: schema-utils: 4.2.0 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) - mini-css-extract-plugin@2.9.2(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + mini-css-extract-plugin@2.9.2(webpack@5.98.0): dependencies: schema-utils: 4.3.0 tapable: 2.2.1 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) mini-svg-data-uri@1.4.4: {} @@ -40415,15 +40124,15 @@ snapshots: postcss: 8.4.38 ts-node: 10.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@types/node@20.16.10)(typescript@5.7.3) - postcss-loader@6.2.1(postcss@8.4.38)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + postcss-loader@6.2.1(postcss@8.4.38)(webpack@5.98.0): dependencies: cosmiconfig: 7.1.0 klona: 2.0.6 postcss: 8.4.38 semver: 7.7.1 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) - postcss-loader@8.1.1(@rspack/core@1.2.6(@swc/helpers@0.5.11))(postcss@8.4.38)(typescript@5.7.3)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + postcss-loader@8.1.1(@rspack/core@1.2.6(@swc/helpers@0.5.11))(postcss@8.4.38)(typescript@5.7.3)(webpack@5.98.0): dependencies: cosmiconfig: 9.0.0(typescript@5.7.3) jiti: 1.21.6 @@ -40431,11 +40140,11 @@ snapshots: semver: 7.7.1 optionalDependencies: '@rspack/core': 1.2.6(@swc/helpers@0.5.11) - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) transitivePeerDependencies: - typescript - postcss-loader@8.1.1(@rspack/core@1.2.6(@swc/helpers@0.5.11))(postcss@8.5.2)(typescript@5.7.3)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + postcss-loader@8.1.1(@rspack/core@1.2.6(@swc/helpers@0.5.11))(postcss@8.5.2)(typescript@5.7.3)(webpack@5.98.0): dependencies: cosmiconfig: 9.0.0(typescript@5.7.3) jiti: 1.21.6 @@ -40443,7 +40152,7 @@ snapshots: semver: 7.7.1 optionalDependencies: '@rspack/core': 1.2.6(@swc/helpers@0.5.11) - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) transitivePeerDependencies: - typescript @@ -41562,7 +41271,7 @@ snapshots: define-properties: 1.2.1 es-abstract: 1.23.3 es-errors: 1.3.0 - get-intrinsic: 1.2.4 + get-intrinsic: 1.3.0 globalthis: 1.0.4 which-builtin-type: 1.1.4 @@ -42074,7 +41783,7 @@ snapshots: safe-array-concat@1.1.2: dependencies: call-bind: 1.0.7 - get-intrinsic: 1.2.4 + get-intrinsic: 1.3.0 has-symbols: 1.0.3 isarray: 2.0.5 @@ -42209,23 +41918,23 @@ snapshots: dependencies: suf-log: 2.5.3 - sass-loader@16.0.5(@rspack/core@1.2.6(@swc/helpers@0.5.11))(sass-embedded@1.85.1)(sass@1.55.0)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + sass-loader@16.0.5(@rspack/core@1.2.6(@swc/helpers@0.5.11))(sass-embedded@1.85.1)(sass@1.55.0)(webpack@5.98.0): dependencies: neo-async: 2.6.2 optionalDependencies: '@rspack/core': 1.2.6(@swc/helpers@0.5.11) sass: 1.55.0 sass-embedded: 1.85.1 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) - sass-loader@16.0.5(@rspack/core@1.2.6(@swc/helpers@0.5.11))(sass-embedded@1.85.1)(sass@1.85.0)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + sass-loader@16.0.5(@rspack/core@1.2.6(@swc/helpers@0.5.11))(sass-embedded@1.85.1)(sass@1.85.0)(webpack@5.98.0): dependencies: neo-async: 2.6.2 optionalDependencies: '@rspack/core': 1.2.6(@swc/helpers@0.5.11) sass: 1.85.0 sass-embedded: 1.85.1 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) sass@1.55.0: dependencies: @@ -42406,8 +42115,8 @@ snapshots: define-data-property: 1.1.4 es-errors: 1.3.0 function-bind: 1.1.2 - get-intrinsic: 1.2.4 - gopd: 1.0.1 + get-intrinsic: 1.3.0 + gopd: 1.2.0 has-property-descriptors: 1.0.2 set-function-name@2.0.2: @@ -42520,7 +42229,7 @@ snapshots: dependencies: call-bind: 1.0.7 es-errors: 1.3.0 - get-intrinsic: 1.2.4 + get-intrinsic: 1.3.0 object-inspect: 1.13.2 side-channel@1.1.0: @@ -42658,11 +42367,11 @@ snapshots: source-map-js@1.2.1: {} - source-map-loader@5.0.0(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + source-map-loader@5.0.0(webpack@5.98.0): dependencies: iconv-lite: 0.6.3 source-map-js: 1.2.1 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) source-map-support@0.5.13: dependencies: @@ -42947,7 +42656,7 @@ snapshots: call-bind: 1.0.7 define-properties: 1.2.1 es-abstract: 1.23.3 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 string.prototype.trimend@1.0.8: dependencies: @@ -42966,7 +42675,7 @@ snapshots: dependencies: call-bind: 1.0.7 define-properties: 1.2.1 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 string_decoder@1.1.1: dependencies: @@ -43032,13 +42741,9 @@ snapshots: style-inject@0.3.0: {} - style-loader@3.3.4(webpack@5.88.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + style-loader@3.3.4(webpack@5.98.0): dependencies: - webpack: 5.88.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) - - style-loader@3.3.4(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): - dependencies: - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) style-mod@4.1.2: {} @@ -43080,12 +42785,12 @@ snapshots: postcss: 8.5.3 postcss-selector-parser: 6.1.2 - stylus-loader@7.1.3(stylus@0.64.0)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + stylus-loader@7.1.3(stylus@0.64.0)(webpack@5.98.0): dependencies: fast-glob: 3.3.3 normalize-path: 3.0.0 stylus: 0.64.0 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) stylus@0.64.0: dependencies: @@ -43291,50 +42996,38 @@ snapshots: temp-dir: 2.0.0 uuid: 3.4.0 - terser-webpack-plugin@5.3.10(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + terser-webpack-plugin@5.3.10(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4)): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.33.0 - webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) optionalDependencies: '@swc/core': 1.5.7(@swc/helpers@0.5.11) esbuild: 0.25.0 - terser-webpack-plugin@5.3.10(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + terser-webpack-plugin@5.3.10(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack@5.98.0): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 3.3.0 serialize-javascript: 6.0.2 terser: 5.33.0 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) optionalDependencies: '@swc/core': 1.5.7(@swc/helpers@0.5.11) esbuild: 0.25.0 - terser-webpack-plugin@5.3.11(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack@5.88.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + terser-webpack-plugin@5.3.11(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack@5.98.0): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 4.3.0 serialize-javascript: 6.0.2 terser: 5.39.0 - webpack: 5.88.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) - optionalDependencies: - '@swc/core': 1.5.7(@swc/helpers@0.5.11) - esbuild: 0.25.0 - - terser-webpack-plugin@5.3.11(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): - dependencies: - '@jridgewell/trace-mapping': 0.3.25 - jest-worker: 27.5.1 - schema-utils: 4.3.0 - serialize-javascript: 6.0.2 - terser: 5.39.0 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) optionalDependencies: '@swc/core': 1.5.7(@swc/helpers@0.5.11) esbuild: 0.25.0 @@ -43573,7 +43266,7 @@ snapshots: babel-jest: 29.7.0(@babel/core@7.25.2) esbuild: 0.25.0 - ts-loader@9.5.1(typescript@5.7.3)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + ts-loader@9.5.1(typescript@5.7.3)(webpack@5.98.0): dependencies: chalk: 4.1.2 enhanced-resolve: 5.17.1 @@ -43581,7 +43274,7 @@ snapshots: semver: 7.6.3 source-map: 0.7.4 typescript: 5.7.3 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) ts-node@10.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@types/node@20.16.10)(typescript@5.7.3): dependencies: @@ -43720,7 +43413,7 @@ snapshots: dependencies: call-bind: 1.0.7 for-each: 0.3.3 - gopd: 1.0.1 + gopd: 1.2.0 has-proto: 1.0.3 is-typed-array: 1.1.13 @@ -43737,7 +43430,7 @@ snapshots: available-typed-arrays: 1.0.7 call-bind: 1.0.7 for-each: 0.3.3 - gopd: 1.0.1 + gopd: 1.2.0 has-proto: 1.0.3 is-typed-array: 1.1.13 @@ -43755,7 +43448,7 @@ snapshots: dependencies: call-bind: 1.0.7 for-each: 0.3.3 - gopd: 1.0.1 + gopd: 1.2.0 has-proto: 1.0.3 is-typed-array: 1.1.13 possible-typed-array-names: 1.0.0 @@ -43825,7 +43518,7 @@ snapshots: dependencies: call-bind: 1.0.7 has-bigints: 1.0.2 - has-symbols: 1.0.3 + has-symbols: 1.1.0 which-boxed-primitive: 1.0.2 unbox-primitive@1.1.0: @@ -44842,9 +44535,9 @@ snapshots: webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0): dependencies: '@discoveryjs/json-ext': 0.5.7 - '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) - '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) - '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))(webpack-dev-server@5.2.1(bufferutil@4.0.7)(webpack-cli@5.1.4)(webpack@5.98.0))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4)(webpack@5.98.0) + '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4)(webpack@5.98.0) + '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4)(webpack-dev-server@5.2.1)(webpack@5.98.0) colorette: 2.0.20 commander: 10.0.1 cross-spawn: 7.0.3 @@ -44853,12 +44546,12 @@ snapshots: import-local: 3.2.0 interpret: 3.1.1 rechoir: 0.8.0 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) webpack-merge: 5.10.0 optionalDependencies: - webpack-dev-server: 5.2.1(bufferutil@4.0.7)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + webpack-dev-server: 5.2.1(bufferutil@4.0.7)(webpack-cli@5.1.4)(webpack@5.98.0) - webpack-dev-middleware@6.1.3(webpack@5.88.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + webpack-dev-middleware@6.1.3(webpack@5.98.0): dependencies: colorette: 2.0.20 memfs: 3.6.0 @@ -44866,9 +44559,9 @@ snapshots: range-parser: 1.2.1 schema-utils: 4.3.0 optionalDependencies: - webpack: 5.88.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) - webpack-dev-middleware@7.4.2(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + webpack-dev-middleware@7.4.2(webpack@5.98.0): dependencies: colorette: 2.0.20 memfs: 4.12.0 @@ -44877,9 +44570,9 @@ snapshots: range-parser: 1.2.1 schema-utils: 4.3.0 optionalDependencies: - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) - webpack-dev-server@5.0.4(bufferutil@4.0.7)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + webpack-dev-server@5.0.4(bufferutil@4.0.7)(webpack-cli@5.1.4)(webpack@5.98.0): dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 @@ -44909,10 +44602,10 @@ snapshots: serve-index: 1.9.1 sockjs: 0.3.24 spdy: 4.0.2 - webpack-dev-middleware: 7.4.2(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + webpack-dev-middleware: 7.4.2(webpack@5.98.0) ws: 8.18.0(bufferutil@4.0.7) optionalDependencies: - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0) transitivePeerDependencies: - bufferutil @@ -44920,7 +44613,7 @@ snapshots: - supports-color - utf-8-validate - webpack-dev-server@5.2.0(bufferutil@4.0.7)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + webpack-dev-server@5.2.0(bufferutil@4.0.7)(webpack-cli@5.1.4)(webpack@5.98.0): dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 @@ -44947,10 +44640,10 @@ snapshots: serve-index: 1.9.1 sockjs: 0.3.24 spdy: 4.0.2 - webpack-dev-middleware: 7.4.2(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + webpack-dev-middleware: 7.4.2(webpack@5.98.0) ws: 8.18.0(bufferutil@4.0.7) optionalDependencies: - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0) transitivePeerDependencies: - bufferutil @@ -44958,7 +44651,7 @@ snapshots: - supports-color - utf-8-validate - webpack-dev-server@5.2.1(bufferutil@4.0.7)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + webpack-dev-server@5.2.1(bufferutil@4.0.7)(webpack-cli@5.1.4)(webpack@5.98.0): dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 @@ -44986,10 +44679,10 @@ snapshots: serve-index: 1.9.1 sockjs: 0.3.24 spdy: 4.0.2 - webpack-dev-middleware: 7.4.2(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + webpack-dev-middleware: 7.4.2(webpack@5.98.0) ws: 8.18.0(bufferutil@4.0.7) optionalDependencies: - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0) transitivePeerDependencies: - bufferutil @@ -45019,49 +44712,16 @@ snapshots: webpack-sources@3.2.3: {} - webpack-subresource-integrity@5.1.0(html-webpack-plugin@5.5.0(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))))(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))): + webpack-subresource-integrity@5.1.0(html-webpack-plugin@5.5.0(webpack@5.98.0))(webpack@5.98.0): dependencies: typed-assert: 1.0.9 - webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)) + webpack: 5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4) optionalDependencies: - html-webpack-plugin: 5.5.0(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + html-webpack-plugin: 5.5.0(webpack@5.98.0) webpack-virtual-modules@0.6.2: {} - webpack@5.88.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)): - dependencies: - '@types/eslint-scope': 3.7.7 - '@types/estree': 1.0.6 - '@webassemblyjs/ast': 1.12.1 - '@webassemblyjs/wasm-edit': 1.12.1 - '@webassemblyjs/wasm-parser': 1.12.1 - acorn: 8.12.1 - acorn-import-assertions: 1.9.0(acorn@8.12.1) - browserslist: 4.24.4 - chrome-trace-event: 1.0.4 - enhanced-resolve: 5.17.1 - es-module-lexer: 1.5.4 - eslint-scope: 5.1.1 - events: 3.3.0 - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - json-parse-even-better-errors: 2.3.1 - loader-runner: 4.3.0 - mime-types: 2.1.35 - neo-async: 2.6.2 - schema-utils: 3.3.0 - tapable: 2.2.1 - terser-webpack-plugin: 5.3.11(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack@5.88.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) - watchpack: 2.4.2 - webpack-sources: 3.2.3 - optionalDependencies: - webpack-cli: 5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0) - transitivePeerDependencies: - - '@swc/core' - - esbuild - - uglify-js - - webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)): + webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4): dependencies: '@types/estree': 1.0.6 '@webassemblyjs/ast': 1.12.1 @@ -45083,7 +44743,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + terser-webpack-plugin: 5.3.10(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack@5.94.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4)) watchpack: 2.4.2 webpack-sources: 3.2.3 optionalDependencies: @@ -45093,7 +44753,7 @@ snapshots: - esbuild - uglify-js - webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0)): + webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.6 @@ -45115,7 +44775,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 4.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.11(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack@5.98.0(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack-cli@5.1.4(webpack-dev-server@5.2.1)(webpack@5.98.0))) + terser-webpack-plugin: 5.3.11(@swc/core@1.5.7(@swc/helpers@0.5.11))(esbuild@0.25.0)(webpack@5.98.0) watchpack: 2.4.2 webpack-sources: 3.2.3 optionalDependencies: diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000000..0c548fd01a --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,18 @@ +/* + * This file was generated by the Gradle 'init' task. + * + * The settings file is used to specify which projects to include in your build. + * For more detailed information on multi-project builds, please refer to https://docs.gradle.org/8.5/userguide/building_swift_projects.html in the Gradle documentation. + */ + + +pluginManagement { + repositories { + mavenLocal() + mavenCentral() + gradlePluginPortal() + } +} + +rootProject.name = "nx" +includeBuild("./packages/gradle/project-graph")