chore(repo): remove v16 migrations (#28220)

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #
This commit is contained in:
Jack Hsu 2024-10-02 10:18:41 -04:00 committed by GitHub
parent 3b278e6755
commit a637f9eef9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
160 changed files with 23 additions and 11897 deletions

View File

@ -1,173 +1,5 @@
{
"generators": {
"install-required-packages": {
"cli": "nx",
"version": "15.7.0-beta.1",
"description": "Install the required angular-devkit packages as we do not directly depend on them anymore",
"factory": "./src/migrations/update-15-7-0/install-required-packages"
},
"remove-show-circular-dependencies-option": {
"cli": "nx",
"version": "14.2.0-beta.0",
"description": "Remove 'showCircularDependencies' option from browser and server executors.",
"factory": "./src/migrations/update-14-2-0/remove-show-circular-dependencies-option"
},
"update-angular-cli-version": {
"cli": "nx",
"version": "14.2.0-beta.0",
"description": "Update the @angular/cli package version.",
"factory": "./src/migrations/update-14-2-0/update-angular-cli"
},
"update-libraries-secondary-entrypoints": {
"cli": "nx",
"version": "14.2.0-beta.0",
"description": "Remove 'package.json' files from library projects secondary entrypoints.",
"factory": "./src/migrations/update-14-2-0/update-libraries-secondary-entrypoints"
},
"update-postinstall-script-ngcc-target": {
"cli": "nx",
"version": "14.2.0-beta.0",
"description": "Update postinstall script running ngcc to use ES2020 target.",
"factory": "./src/migrations/update-14-2-0/update-ngcc-target"
},
"update-tsconfig-target": {
"cli": "nx",
"version": "14.2.0-beta.0",
"description": "Update TypeScript compilation target to 'ES2020'.",
"factory": "./src/migrations/update-14-2-0/update-tsconfig-target"
},
"update-router-initial-navigation": {
"cli": "nx",
"version": "14.2.0-beta.6",
"description": "Update `initialNavigation: 'enabled'` to `initialNavigation: 'enabledBlocking'`.",
"factory": "./src/migrations/update-14-2-0/update-router-initial-navigation"
},
"migrate-mfe-to-mf": {
"cli": "nx",
"version": "14.5.0-beta.0",
"description": "Update any references of MFE to MF.",
"factory": "./src/migrations/update-14-5-0/migrate-mfe-to-mf"
},
"update-angular-cli-version-14-1-0": {
"cli": "nx",
"version": "14.5.2-beta.0",
"requires": {
"@angular/core": ">=14.1.0"
},
"description": "Update the @angular/cli package version to ~14.1.0.",
"factory": "./src/migrations/update-14-5-2/update-angular-cli"
},
"update-angular-cli-version-14-2-0": {
"cli": "nx",
"version": "14.6.0-beta.0",
"requires": {
"@angular/core": ">=14.2.0"
},
"description": "Update the @angular/cli package version to ~14.2.0.",
"factory": "./src/migrations/update-14-6-0/update-angular-cli"
},
"rename-webpack-server-executor": {
"cli": "nx",
"version": "15.0.0-beta.0",
"description": "Rename @nrwl/angular:webpack-server executor to @nrwl/angular:webpack-dev-server",
"factory": "./src/migrations/update-14-8-0/rename-webpack-server"
},
"switch-to-jasmine-marbles": {
"cli": "nx",
"version": "15.0.0-beta.0",
"description": "Update the usages of @nrwl/angular/testing to import jasmine-marbles symbols from jasmine-marbles itself.",
"factory": "./src/migrations/update-15-0-0/switch-to-jasmine-marbles"
},
"add-karma-inputs": {
"cli": "nx",
"version": "15.0.0-beta.1",
"description": "Stop hashing karma spec files and config files for build targets and dependent tasks",
"factory": "./src/migrations/update-15-0-0/add-karma-inputs"
},
"update-angular-cli-version-15-0-0": {
"cli": "nx",
"version": "15.2.0-beta.0",
"requires": {
"@angular/core": ">=15.0.0"
},
"description": "Update the @angular/cli package version to ~15.0.0.",
"factory": "./src/migrations/update-15-2-0/update-angular-cli"
},
"remove-browserlist-config": {
"cli": "nx",
"version": "15.2.0-beta.0",
"requires": {
"@angular/core": ">=15.0.0"
},
"description": "Remove browserslist config as it's handled by build-angular",
"factory": "./src/migrations/update-15-2-0/remove-browserlist-config"
},
"update-typescript-target": {
"cli": "nx",
"version": "15.2.0-beta.0",
"requires": {
"@angular/core": ">=15.0.0"
},
"description": "Update typescript target to ES2022",
"factory": "./src/migrations/update-15-2-0/update-typescript-target"
},
"update-workspace-config": {
"cli": "nx",
"version": "15.2.0-beta.0",
"requires": {
"@angular/core": ">=15.0.0"
},
"description": "Remove bundleDependencies from server targets",
"factory": "./src/migrations/update-15-2-0/update-workspace-config"
},
"update-platform-server-exports": {
"cli": "nx",
"version": "15.2.0-beta.0",
"requires": {
"@angular/core": ">=15.0.0"
},
"description": "Remove exported `@angular/platform-server` `renderModule` method. The `renderModule` method is now exported by the Angular CLI.",
"factory": "./src/migrations/update-15-2-0/remove-platform-server-exports"
},
"update-karma-main-file": {
"cli": "nx",
"version": "15.2.0-beta.0",
"requires": {
"@angular/core": ">=15.0.0"
},
"description": "Remove no longer needed require calls in Karma builder main file.",
"factory": "./src/migrations/update-15-2-0/update-karma-main-file"
},
"update-angular-cli-version-15-1-0": {
"cli": "nx",
"version": "15.5.0-beta.0",
"requires": {
"@angular/core": ">=15.1.0"
},
"description": "Update the @angular/cli package version to ~15.1.0.",
"factory": "./src/migrations/update-15-5-0/update-angular-cli"
},
"update-angular-cli-version-15-2-0": {
"cli": "nx",
"version": "15.8.0-beta.4",
"requires": {
"@angular/core": ">=15.2.0"
},
"description": "Update the @angular/cli package version to ~15.2.0.",
"factory": "./src/migrations/update-15-8-0/update-angular-cli"
},
"update-tsconfig-spec-jest": {
"cli": "nx",
"version": "15.9.0-beta.3",
"description": "Update the tsconfig.spec.json to use target es2016 for jest-preset-angular v13",
"factory": "./src/migrations/update-15-9-0/update-testing-tsconfig"
},
"update-file-server-executor": {
"cli": "nx",
"version": "15.9.0-beta.9",
"description": "Update the file-server executor to use @nrwl/web:file-server",
"factory": "./src/migrations/update-15-9-0/update-file-server-executor"
},
"remove-library-generator-simple-module-name-option": {
"cli": "nx",
"version": "16.0.0-beta.1",
@ -437,819 +269,6 @@
}
},
"packageJsonUpdates": {
"14.1.8": {
"version": "14.1.8-beta.0",
"packages": {
"postcss-import": {
"version": "~14.1.0",
"alwaysAddToPackageJson": false
},
"postcss-preset-env": {
"version": "~7.5.0",
"alwaysAddToPackageJson": false
},
"postcss-url": {
"version": "~10.1.3",
"alwaysAddToPackageJson": false
}
}
},
"14.2.0": {
"version": "14.2.0-beta.6",
"packages": {
"@angular-devkit/architect": {
"version": "~0.1400.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/build-angular": {
"version": "~14.0.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/build-webpack": {
"version": "~0.1400.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/core": {
"version": "~14.0.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/schematics": {
"version": "~14.0.0",
"alwaysAddToPackageJson": false
},
"@schematics/angular": {
"version": "~14.0.0",
"alwaysAddToPackageJson": false
},
"@angular/pwa": {
"version": "~14.0.0",
"alwaysAddToPackageJson": false
},
"@angular/core": {
"version": "~14.0.0",
"alwaysAddToPackageJson": true
},
"@angular/common": {
"version": "~14.0.0",
"alwaysAddToPackageJson": false
},
"@angular/forms": {
"version": "~14.0.0",
"alwaysAddToPackageJson": false
},
"@angular/elements": {
"version": "~14.0.0",
"alwaysAddToPackageJson": false
},
"@angular/compiler": {
"version": "~14.0.0",
"alwaysAddToPackageJson": false
},
"@angular/compiler-cli": {
"version": "~14.0.0",
"alwaysAddToPackageJson": false
},
"@angular/localize": {
"version": "~14.0.0",
"alwaysAddToPackageJson": false
},
"@angular/platform-browser": {
"version": "~14.0.0",
"alwaysAddToPackageJson": false
},
"@angular/platform-browser-dynamic": {
"version": "~14.0.0",
"alwaysAddToPackageJson": false
},
"@angular/platform-server": {
"version": "~14.0.0",
"alwaysAddToPackageJson": false
},
"@angular/router": {
"version": "~14.0.0",
"alwaysAddToPackageJson": false
},
"@angular/upgrade": {
"version": "~14.0.0",
"alwaysAddToPackageJson": false
},
"@angular/language-service": {
"version": "~14.0.0",
"alwaysAddToPackageJson": false
},
"@angular/animations": {
"version": "~14.0.0",
"alwaysAddToPackageJson": false
},
"@angular/service-worker": {
"version": "~14.0.0",
"alwaysAddToPackageJson": false
},
"@angular/material": {
"version": "~14.0.0",
"alwaysAddToPackageJson": false
},
"@angular/cdk": {
"version": "~14.0.0",
"alwaysAddToPackageJson": false
},
"ng-packagr": {
"version": "~14.0.0",
"alwaysAddToPackageJson": false
},
"@angular-eslint/eslint-plugin": {
"version": "~13.2.1",
"alwaysAddToPackageJson": false
},
"@angular-eslint/eslint-plugin-template": {
"version": "~13.2.1",
"alwaysAddToPackageJson": false
},
"@angular-eslint/template-parser": {
"version": "~13.2.1",
"alwaysAddToPackageJson": false
},
"@ngrx/store": {
"version": "~13.2.0",
"alwaysAddToPackageJson": false
},
"@ngrx/effects": {
"version": "~13.2.0",
"alwaysAddToPackageJson": false
},
"@ngrx/entity": {
"version": "~13.2.0",
"alwaysAddToPackageJson": false
},
"@ngrx/router-store": {
"version": "~13.2.0",
"alwaysAddToPackageJson": false
},
"@ngrx/schematics": {
"version": "~13.2.0",
"alwaysAddToPackageJson": false
},
"@ngrx/store-devtools": {
"version": "~13.2.0",
"alwaysAddToPackageJson": false
},
"@ngrx/component-store": {
"version": "~13.2.0",
"alwaysAddToPackageJson": false
},
"jest-preset-angular": {
"version": "~11.1.2",
"alwaysAddToPackageJson": false
},
"karma-jasmine": {
"version": "~5.0.0",
"alwaysAddToPackageJson": false
},
"jasmine-core": {
"version": "~4.1.0",
"alwaysAddToPackageJson": false
},
"jasmine-spec-reporter": {
"version": "~7.0.0",
"alwaysAddToPackageJson": false
},
"@types/jasmine": {
"version": "~4.0.0",
"alwaysAddToPackageJson": false
}
}
},
"14.3.7": {
"version": "14.3.7-beta.0",
"requires": {
"@angular/core": "^14.0.0"
},
"packages": {
"@ngrx/store": {
"version": "~14.0.0",
"alwaysAddToPackageJson": false
},
"@ngrx/effects": {
"version": "~14.0.0",
"alwaysAddToPackageJson": false
},
"@ngrx/entity": {
"version": "~14.0.0",
"alwaysAddToPackageJson": false
},
"@ngrx/router-store": {
"version": "~14.0.0",
"alwaysAddToPackageJson": false
},
"@ngrx/schematics": {
"version": "~14.0.0",
"alwaysAddToPackageJson": false
},
"@ngrx/store-devtools": {
"version": "~14.0.0",
"alwaysAddToPackageJson": false
},
"@ngrx/component-store": {
"version": "~14.0.0"
}
}
},
"14.4.0": {
"version": "14.4.0-beta.1",
"requires": {
"eslint": "^7.0.0 || ^8.0.0",
"@angular/core": ">=14.0.0 <15.0.0"
},
"packages": {
"@angular-eslint/eslint-plugin": {
"version": "~14.0.0",
"alwaysAddToPackageJson": false
},
"@angular-eslint/eslint-plugin-template": {
"version": "~14.0.0",
"alwaysAddToPackageJson": false
},
"@angular-eslint/template-parser": {
"version": "~14.0.0",
"alwaysAddToPackageJson": false
}
}
},
"14.5.2": {
"version": "14.5.2-beta.0",
"x-prompt": "Do you want to update the Angular version to v14.1?",
"requires": {
"@angular/core": ">=14.0.0 <14.1.0"
},
"packages": {
"@angular-devkit/architect": {
"version": "~0.1401.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/build-angular": {
"version": "~14.1.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/build-webpack": {
"version": "~0.1401.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/core": {
"version": "~14.1.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/schematics": {
"version": "~14.1.0",
"alwaysAddToPackageJson": false
},
"@angular/pwa": {
"version": "~14.1.0",
"alwaysAddToPackageJson": false
},
"@schematics/angular": {
"version": "~14.1.0",
"alwaysAddToPackageJson": false
},
"@angular/core": {
"version": "~14.1.0",
"alwaysAddToPackageJson": true
},
"@angular/material": {
"version": "~14.1.0",
"alwaysAddToPackageJson": false
},
"ng-packagr": {
"version": "~14.1.0",
"alwaysAddToPackageJson": false
},
"karma": {
"version": "~6.4.0",
"alwaysAddToPackageJson": false
},
"karma-jasmine": {
"version": "~5.1.0",
"alwaysAddToPackageJson": false
},
"karma-jasmine-html-reporter": {
"version": "~2.0.0",
"alwaysAddToPackageJson": false
},
"jasmine-core": {
"version": "~4.2.0",
"alwaysAddToPackageJson": false
}
}
},
"14.5.3": {
"version": "14.5.3-beta.0",
"requires": {
"@angular/core": "14.1.0"
},
"packages": {
"@angular-devkit/architect": {
"version": "~0.1401.1",
"alwaysAddToPackageJson": false
},
"@angular-devkit/build-angular": {
"version": "~14.1.1",
"alwaysAddToPackageJson": false
},
"@angular-devkit/build-webpack": {
"version": "~0.1401.1",
"alwaysAddToPackageJson": false
},
"@angular-devkit/core": {
"version": "~14.1.1",
"alwaysAddToPackageJson": false
},
"@angular-devkit/schematics": {
"version": "~14.1.1",
"alwaysAddToPackageJson": false
},
"@angular/pwa": {
"version": "~14.1.1",
"alwaysAddToPackageJson": false
},
"@schematics/angular": {
"version": "~14.1.1",
"alwaysAddToPackageJson": false
},
"@angular/core": {
"version": "~14.1.1",
"alwaysAddToPackageJson": true
},
"@angular/material": {
"version": "~14.1.1",
"alwaysAddToPackageJson": false
},
"@angular/cdk": {
"version": "~14.1.1",
"alwaysAddToPackageJson": false
}
}
},
"14.5.5": {
"version": "14.5.5-beta.0",
"packages": {
"ts-node": {
"version": "10.9.1",
"alwaysAddToPackageJson": false
}
}
},
"14.6.0-angular": {
"version": "14.6.0-beta.0",
"x-prompt": "Do you want to update the Angular version to v14.2?",
"requires": {
"@angular/core": ">=14.1.0 <14.2.0"
},
"packages": {
"@angular-devkit/architect": {
"version": "~0.1402.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/build-angular": {
"version": "~14.2.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/build-webpack": {
"version": "~0.1402.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/core": {
"version": "~14.2.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/schematics": {
"version": "~14.2.0",
"alwaysAddToPackageJson": false
},
"@angular/pwa": {
"version": "~14.2.0",
"alwaysAddToPackageJson": false
},
"@schematics/angular": {
"version": "~14.2.0",
"alwaysAddToPackageJson": false
},
"@angular/core": {
"version": "~14.2.0",
"alwaysAddToPackageJson": true
},
"@angular/material": {
"version": "~14.2.0",
"alwaysAddToPackageJson": false
},
"@angular/cdk": {
"version": "~14.2.0",
"alwaysAddToPackageJson": false
},
"ng-packagr": {
"version": "~14.2.0",
"alwaysAddToPackageJson": false
}
}
},
"14.6.0-jest-preset-angular": {
"version": "14.6.0-beta.0",
"requires": {
"@angular-devkit/build-angular": ">=0.1102.19 <15.0.0",
"@angular/compiler-cli": ">=11.2.14 <15.0.0",
"@angular/core": ">=11.2.14 <15.0.0",
"@angular/platform-browser-dynamic": ">=11.2.14 <15.0.0",
"jest": "^28.0.0"
},
"packages": {
"jest-preset-angular": {
"version": "12.2.0",
"alwaysAddToPackageJson": false
}
}
},
"14.6.0-rxjs": {
"version": "14.6.0-beta.0",
"requires": {
"rxjs": ">=7.0.0 <7.5.0"
},
"packages": {
"rxjs": {
"version": "~7.5.0",
"alwaysAddToPackageJson": false
}
}
},
"14.8.0-angular-eslint": {
"version": "14.8.0-beta.0",
"requires": {
"eslint": "^7.0.0 || ^8.0.0",
"@angular/core": ">=14.0.0 <15.0.0"
},
"packages": {
"@angular-eslint/eslint-plugin": {
"version": "~14.0.4",
"alwaysAddToPackageJson": false
},
"@angular-eslint/eslint-plugin-template": {
"version": "~14.0.4",
"alwaysAddToPackageJson": false
},
"@angular-eslint/template-parser": {
"version": "~14.0.4",
"alwaysAddToPackageJson": false
}
}
},
"14.8.0-jest-preset-angular": {
"version": "14.8.0-beta.0",
"requires": {
"@angular-devkit/build-angular": ">=0.1102.19 <15.0.0",
"@angular/compiler-cli": ">=11.2.14 <15.0.0",
"@angular/core": ">=11.2.14 <15.0.0",
"@angular/platform-browser-dynamic": ">=11.2.14 <15.0.0",
"jest": "^28.0.0"
},
"packages": {
"jest-preset-angular": {
"version": "12.2.2",
"alwaysAddToPackageJson": false
}
}
},
"15.2.0": {
"version": "15.2.0-beta.0",
"x-prompt": "Do you want to update the Angular version to v15?",
"requires": {
"@angular/core": "^14.2.0"
},
"packages": {
"@angular-devkit/architect": {
"version": "~0.1500.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/build-angular": {
"version": "~15.0.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/build-webpack": {
"version": "~0.1500.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/core": {
"version": "~15.0.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/schematics": {
"version": "~15.0.0",
"alwaysAddToPackageJson": false
},
"@angular/pwa": {
"version": "~15.0.0",
"alwaysAddToPackageJson": false
},
"@schematics/angular": {
"version": "~15.0.0",
"alwaysAddToPackageJson": false
},
"@angular/core": {
"version": "~15.0.0",
"alwaysAddToPackageJson": true
},
"@angular/material": {
"version": "~15.0.0",
"alwaysAddToPackageJson": false
},
"@angular/cdk": {
"version": "~15.0.0",
"alwaysAddToPackageJson": false
},
"@nguniversal/common": {
"version": "~15.0.0",
"alwaysAddToPackageJson": false
},
"@nguniversal/express-engine": {
"version": "~15.0.0",
"alwaysAddToPackageJson": false
},
"@nguniversal/builders": {
"version": "~15.0.0",
"alwaysAddToPackageJson": false
},
"ng-packagr": {
"version": "~15.0.0",
"alwaysAddToPackageJson": false
}
}
},
"15.2.2-angular-eslint": {
"version": "15.2.2-beta.0",
"requires": {
"eslint": "^7.20.0 || ^8.0.0",
"@angular/core": ">=15.0.0 <16.0.0"
},
"packages": {
"@angular-eslint/eslint-plugin": {
"version": "~15.0.0",
"alwaysAddToPackageJson": false
},
"@angular-eslint/eslint-plugin-template": {
"version": "~15.0.0",
"alwaysAddToPackageJson": false
},
"@angular-eslint/template-parser": {
"version": "~15.0.0",
"alwaysAddToPackageJson": false
}
}
},
"15.2.2-jest": {
"version": "15.2.2-beta.0",
"requires": {
"@angular-devkit/build-angular": ">=12.2.18 <16.0.0",
"@angular/compiler-cli": ">=12.2.16 <16.0.0",
"@angular/core": ">=12.2.16 <16.0.0",
"@angular/platform-browser-dynamic": ">=12.2.16 <16.0.0",
"jest": "^28.0.0"
},
"packages": {
"jest-preset-angular": {
"version": "12.2.3",
"alwaysAddToPackageJson": false
}
}
},
"15.3.1": {
"version": "15.3.1-beta.0",
"requires": {
"@angular/core": "^15.0.0"
},
"packages": {
"@ngrx/store": {
"version": "~15.0.0",
"alwaysAddToPackageJson": false
},
"@ngrx/effects": {
"version": "~15.0.0",
"alwaysAddToPackageJson": false
},
"@ngrx/entity": {
"version": "~15.0.0",
"alwaysAddToPackageJson": false
},
"@ngrx/router-store": {
"version": "~15.0.0",
"alwaysAddToPackageJson": false
},
"@ngrx/schematics": {
"version": "~15.0.0",
"alwaysAddToPackageJson": false
},
"@ngrx/store-devtools": {
"version": "~15.0.0",
"alwaysAddToPackageJson": false
},
"@ngrx/component-store": {
"version": "~15.0.0"
}
}
},
"15.5.0": {
"version": "15.5.0-beta.0",
"x-prompt": "Do you want to update the Angular version to v15.1?",
"requires": {
"@angular/core": ">=15.0.0 <15.1.0"
},
"packages": {
"@angular-devkit/architect": {
"version": "~0.1501.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/build-angular": {
"version": "~15.1.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/build-webpack": {
"version": "~0.1501.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/core": {
"version": "~15.1.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/schematics": {
"version": "~15.1.0",
"alwaysAddToPackageJson": false
},
"@angular/pwa": {
"version": "~15.1.0",
"alwaysAddToPackageJson": false
},
"@angular/core": {
"version": "~15.1.0",
"alwaysAddToPackageJson": true
},
"@angular/material": {
"version": "~15.1.0",
"alwaysAddToPackageJson": false
},
"@angular/cdk": {
"version": "~15.1.0",
"alwaysAddToPackageJson": false
},
"@schematics/angular": {
"version": "~15.1.0",
"alwaysAddToPackageJson": false
},
"ng-packagr": {
"version": "~15.1.0",
"alwaysAddToPackageJson": false
}
}
},
"15.5.2": {
"version": "15.5.2-beta.0",
"requires": {
"@angular-devkit/build-angular": ">=15.0.0 <16.0.0"
},
"packages": {
"@nguniversal/builders": {
"version": "~15.1.0",
"alwaysAddToPackageJson": false
},
"@nguniversal/express-engine": {
"version": "~15.1.0",
"alwaysAddToPackageJson": false
}
}
},
"15.8.0": {
"version": "15.8.0-beta.4",
"x-prompt": "Do you want to update the Angular version to v15.2?",
"requires": {
"@angular/core": ">=15.1.0 <15.2.0"
},
"packages": {
"@angular-devkit/architect": {
"version": "~0.1502.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/build-angular": {
"version": "~15.2.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/build-webpack": {
"version": "~0.1502.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/core": {
"version": "~15.2.0",
"alwaysAddToPackageJson": false
},
"@angular-devkit/schematics": {
"version": "~15.2.0",
"alwaysAddToPackageJson": false
},
"@angular/pwa": {
"version": "~15.2.0",
"alwaysAddToPackageJson": false
},
"@angular/core": {
"version": "~15.2.0",
"alwaysAddToPackageJson": true
},
"@angular/material": {
"version": "~15.2.0",
"alwaysAddToPackageJson": false
},
"@angular/cdk": {
"version": "~15.2.0",
"alwaysAddToPackageJson": false
},
"@schematics/angular": {
"version": "~15.2.0",
"alwaysAddToPackageJson": false
},
"@nguniversal/express-engine": {
"version": "~15.2.0",
"alwaysAddToPackageJson": false
},
"@nguniversal/build-angular": {
"version": "~15.2.0",
"alwaysAddToPackageJson": false
},
"ng-packagr": {
"version": "~15.2.2",
"alwaysAddToPackageJson": false
},
"zone.js": {
"version": "~0.12.0",
"alwaysAddToPackageJson": false
}
}
},
"15.8.0-jest": {
"version": "15.8.0-beta.0",
"requires": {
"@angular-devkit/build-angular": ">=13.0.0 <16.0.0",
"@angular/compiler-cli": ">=13.0.0 <16.0.0",
"@angular/core": ">=13.0.0 <16.0.0",
"@angular/platform-browser-dynamic": ">=13.0.0 <16.0.0",
"jest": "^29.0.0"
},
"packages": {
"jest-preset-angular": {
"version": "13.0.0",
"alwaysAddToPackageJson": false
}
}
},
"15.8.0-ngrx": {
"version": "15.8.0-beta.6",
"requires": {
"@angular/core": "^15.0.0"
},
"packages": {
"@ngrx/store": {
"version": "~15.3.0",
"alwaysAddToPackageJson": false
},
"@ngrx/effects": {
"version": "~15.3.0",
"alwaysAddToPackageJson": false
},
"@ngrx/entity": {
"version": "~15.3.0",
"alwaysAddToPackageJson": false
},
"@ngrx/router-store": {
"version": "~15.3.0",
"alwaysAddToPackageJson": false
},
"@ngrx/schematics": {
"version": "~15.3.0",
"alwaysAddToPackageJson": false
},
"@ngrx/store-devtools": {
"version": "~15.3.0",
"alwaysAddToPackageJson": false
},
"@ngrx/component-store": {
"version": "~15.3.0",
"alwaysAddToPackageJson": false
}
}
},
"15.8.6-rxjs": {
"version": "15.8.6-beta.0",
"requires": {
"rxjs": ">=7.5.0 <7.6.0"
},
"packages": {
"rxjs": {
"version": "~7.8.0",
"alwaysAddToPackageJson": false
}
}
},
"16.1.0": {
"version": "16.1.0-beta.1",
"x-prompt": "Do you want to update the Angular version to v16?",

View File

@ -1,29 +1,5 @@
{
"generators": {
"update-16-0-0-add-nx-packages": {
"cli": "nx",
"version": "16.0.0-beta.1",
"description": "Replace @nrwl/cypress with @nx/cypress",
"implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages"
},
"update-16-2-0-normalize-tsconfigs": {
"cli": "nx",
"version": "16.2.0-beta.0",
"description": "Normalize tsconfig.cy.json files to be located at '<projectRoot>/cypress/tsconfig.json'",
"implementation": "./src/migrations/update-16-2-0/update-cy-tsconfig"
},
"update-16-3-0-remove-old-tsconfigs": {
"cli": "nx",
"version": "16.4.0-beta.10",
"description": "Remove tsconfig.e2e.json and add settings to project tsconfig.json. tsConfigs executor option is now deprecated. The project level tsconfig.json file should be used instead.",
"implementation": "./src/migrations/update-16-4-0/tsconfig-sourcemaps"
},
"update-16-8-0-cypress-13": {
"cli": "nx",
"version": "16.8.0-beta.4",
"description": "Update to Cypress v13. Most noteable change is video recording is off by default. This migration will only update if the workspace is already on Cypress v12. https://docs.cypress.io/guides/references/migration-guide#Migrating-to-Cypress-130",
"implementation": "./src/migrations/update-16-8-0/cypress-13"
},
"update-cypress-version-13-6-6": {
"cli": "nx",
"version": "18.1.0-beta.3",
@ -38,39 +14,6 @@
}
},
"packageJsonUpdates": {
"16.1.0": {
"version": "16.1.0-beta.0",
"requires": {
"cypress": ">=12.0.0 <12.11.0"
},
"packages": {
"cypress": {
"version": "^12.11.0",
"alwaysAddToPackageJson": false
}
}
},
"16.5.0": {
"version": "16.5.0-beta.0",
"requires": {
"cypress": ">=12.0.0 <12.16.0"
},
"packages": {
"cypress": {
"version": "^12.16.0",
"alwaysAddToPackageJson": false
}
}
},
"16.7.0": {
"version": "16.7.0-beta.3",
"packages": {
"eslint-plugin-cypress": {
"version": "^2.13.4",
"alwaysAddToPackageJson": false
}
}
},
"17.2.0-beta.2": {
"version": "17.2.0-beta.2",
"packages": {

View File

@ -1,37 +0,0 @@
import { Tree, readJson, updateJson } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import replacePackage from './update-16-0-0-add-nx-packages';
describe('update-16-0-0-add-nx-packages', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
updateJson(tree, 'package.json', (json) => {
json.devDependencies['@nrwl/cypress'] = '16.0.0';
return json;
});
});
it('should remove the dependency on @nrwl/cypress', async () => {
await replacePackage(tree);
expect(
readJson(tree, 'package.json').dependencies['@nrwl/cypress']
).not.toBeDefined();
expect(
readJson(tree, 'package.json').devDependencies['@nrwl/cypress']
).not.toBeDefined();
});
it('should add a dependency on @nx/cypress', async () => {
await replacePackage(tree);
const packageJson = readJson(tree, 'package.json');
const newDependencyVersion =
packageJson.devDependencies['@nx/cypress'] ??
packageJson.dependencies['@nx/cypress'];
expect(newDependencyVersion).toBeDefined();
});
});

View File

@ -1,8 +0,0 @@
import { Tree, formatFiles } from '@nx/devkit';
import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package';
export default async function replacePackage(tree: Tree): Promise<void> {
await replaceNrwlPackageWithNxPackage(tree, '@nrwl/cypress', '@nx/cypress');
await formatFiles(tree);
}

View File

@ -1,250 +0,0 @@
import 'nx/src/internal-testing-utils/mock-project-graph';
import {
Tree,
readJson,
readProjectConfiguration,
updateJson,
updateProjectConfiguration,
} from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from 'nx/src/devkit-testing-exports';
import { normalizeCyTsConfigNames } from './update-cy-tsconfig';
import { libraryGenerator } from '@nx/js';
describe('Cypress Migration - update-cy-tsconfig', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
});
it('should do nothing if cypress/tsconfig.json exists', async () => {
await libraryGenerator(tree, { directory: 'libs/my-lib' });
addCyExecutor(tree, 'my-lib');
const tsconfig = {
extends: '../tsconfig.json',
compilerOptions: {
sourceMap: false,
outDir: '../../../dist/out-tsc',
allowJs: true,
types: ['cypress', 'node'],
},
include: ['**/*.ts', '**/*.js', '../cypress.config.ts'],
};
tree.write(
'libs/my-lib/cypress/tsconfig.json',
JSON.stringify(tsconfig, null, 2)
);
updateJson(tree, 'libs/my-lib/tsconfig.json', (json) => {
json.references ??= [];
json.references.push({ path: './cypress/tsconfig.json' });
return json;
});
await normalizeCyTsConfigNames(tree);
expect(readJson(tree, 'libs/my-lib/tsconfig.json').references).toEqual(
expect.arrayContaining([{ path: './cypress/tsconfig.json' }])
);
expect(readJson(tree, 'libs/my-lib/cypress/tsconfig.json')).toEqual(
tsconfig
);
});
it('should move cypress/tsconfig.cy.json to cypress/tsconfig.json', async () => {
await libraryGenerator(tree, { directory: 'libs/my-lib' });
addCyExecutor(tree, 'my-lib');
const tsconfig = {
extends: '../tsconfig.json',
compilerOptions: {
outDir: '../../../dist/out-tsc',
module: 'commonjs',
types: ['cypress', 'node'],
sourceMap: false,
},
include: [
'support/**/*.ts',
'../cypress.config.ts',
'../**/*.cy.ts',
'../**/*.cy.tsx',
'../**/*.cy.js',
'../**/*.cy.jsx',
'../**/*.d.ts',
],
};
tree.write(
'libs/my-lib/cypress/tsconfig.cy.json',
JSON.stringify(tsconfig, null, 2)
);
updateJson(tree, 'libs/my-lib/tsconfig.json', (json) => {
json.references ??= [];
json.references.push({ path: './cypress/tsconfig.cy.json' });
return json;
});
await normalizeCyTsConfigNames(tree);
expect(tree.exists('libs/my-lib/cypress/tsconfig.cy.json')).toBeFalsy();
expect(readJson(tree, 'libs/my-lib/tsconfig.json').references).toEqual(
expect.arrayContaining([{ path: './cypress/tsconfig.json' }])
);
expect(readJson(tree, 'libs/my-lib/cypress/tsconfig.json')).toEqual(
tsconfig
);
});
it('should move tsconfig.cy.json to cypress/tsconfig.json', async () => {
await libraryGenerator(tree, { directory: 'libs/my-lib' });
addCyExecutor(tree, 'my-lib');
const tsconfig = {
extends: './tsconfig.json',
compilerOptions: {
outDir: '../../dist/out-tsc',
module: 'commonjs',
types: ['cypress', 'node'],
sourceMap: false,
},
include: [
'cypress/support/**/*.ts',
'cypress.config.ts',
'**/*.cy.ts',
'**/*.cy.tsx',
'**/*.cy.js',
'**/*.cy.jsx',
'**/*.d.ts',
],
};
tree.write(
'libs/my-lib/tsconfig.cy.json',
JSON.stringify(tsconfig, null, 2)
);
updateJson(tree, 'libs/my-lib/tsconfig.json', (json) => {
json.references ??= [];
json.references.push({ path: './tsconfig.cy.json' });
return json;
});
await normalizeCyTsConfigNames(tree);
expect(tree.exists('libs/my-lib/tsconfig.cy.json')).toBeFalsy();
expect(readJson(tree, 'libs/my-lib/tsconfig.json').references).toEqual(
expect.arrayContaining([{ path: './cypress/tsconfig.json' }])
);
expect(readJson(tree, 'libs/my-lib/cypress/tsconfig.json')).toEqual({
extends: '../tsconfig.json',
compilerOptions: {
outDir: '../../../dist/out-tsc',
module: 'commonjs',
types: ['cypress', 'node'],
sourceMap: false,
},
include: [
'support/**/*.ts',
'../cypress.config.ts',
'../**/*.cy.ts',
'../**/*.cy.tsx',
'../**/*.cy.js',
'../**/*.cy.jsx',
'../**/*.d.ts',
],
});
});
it('should be idepotent', async () => {
await libraryGenerator(tree, { directory: 'libs/my-lib' });
addCyExecutor(tree, 'my-lib');
const tsconfig = {
extends: './tsconfig.json',
compilerOptions: {
outDir: '../../dist/out-tsc',
module: 'commonjs',
types: ['cypress', 'node'],
sourceMap: false,
},
include: [
'cypress/support/**/*.ts',
'cypress.config.ts',
'**/*.cy.ts',
'**/*.cy.tsx',
'**/*.cy.js',
'**/*.cy.jsx',
'**/*.d.ts',
],
};
tree.write(
'libs/my-lib/tsconfig.cy.json',
JSON.stringify(tsconfig, null, 2)
);
updateJson(tree, 'libs/my-lib/tsconfig.json', (json) => {
json.references ??= [];
json.references.push({ path: './tsconfig.cy.json' });
return json;
});
await normalizeCyTsConfigNames(tree);
expect(tree.exists('libs/my-lib/tsconfig.cy.json')).toBeFalsy();
expect(readJson(tree, 'libs/my-lib/tsconfig.json').references).toEqual(
expect.arrayContaining([{ path: './cypress/tsconfig.json' }])
);
expect(readJson(tree, 'libs/my-lib/cypress/tsconfig.json')).toEqual({
extends: '../tsconfig.json',
compilerOptions: {
outDir: '../../../dist/out-tsc',
module: 'commonjs',
types: ['cypress', 'node'],
sourceMap: false,
},
include: [
'support/**/*.ts',
'../cypress.config.ts',
'../**/*.cy.ts',
'../**/*.cy.tsx',
'../**/*.cy.js',
'../**/*.cy.jsx',
'../**/*.d.ts',
],
});
await normalizeCyTsConfigNames(tree);
expect(tree.exists('libs/my-lib/tsconfig.cy.json')).toBeFalsy();
expect(readJson(tree, 'libs/my-lib/tsconfig.json').references).toEqual([
{ path: './tsconfig.lib.json' },
{ path: './tsconfig.spec.json' },
{ path: './cypress/tsconfig.json' },
]);
expect(readJson(tree, 'libs/my-lib/cypress/tsconfig.json')).toEqual({
extends: '../tsconfig.json',
compilerOptions: {
outDir: '../../../dist/out-tsc',
module: 'commonjs',
types: ['cypress', 'node'],
sourceMap: false,
},
include: [
'support/**/*.ts',
'../cypress.config.ts',
'../**/*.cy.ts',
'../**/*.cy.tsx',
'../**/*.cy.js',
'../**/*.cy.jsx',
'../**/*.d.ts',
],
});
});
});
function addCyExecutor(tree: Tree, projectName: string) {
const pc = readProjectConfiguration(tree, projectName);
pc.targets['e2e'] = {
executor: '@nx/cypress:cypress',
options: {
testingType: 'e2e',
devServerTarget: `${projectName}:serve`,
cypressConfig: `${projectName}/cypress.config.ts`,
},
};
updateProjectConfiguration(tree, projectName, pc);
}

View File

@ -1,128 +0,0 @@
import {
ProjectConfiguration,
Tree,
formatFiles,
getProjects,
joinPathFragments,
updateJson,
} from '@nx/devkit';
import { forEachExecutorOptions } from '@nx/devkit/src/generators/executor-options-utils';
export async function normalizeCyTsConfigNames(tree: Tree) {
const projects = getProjects(tree);
forEachExecutorOptions(tree, '@nx/cypress:cypress', (_, projectName) => {
const projectConfig = projects.get(projectName);
const newTsConfigPath = joinPathFragments(
projectConfig.root,
'cypress',
'tsconfig.json'
);
// if there is already a tsconfig.json in the cypress folder, then assume things are setup already
if (!tree.exists(newTsConfigPath)) {
moveProjectTsCyConfig(tree, projectConfig, newTsConfigPath);
moveCyDirTsCyConfig(tree, projectConfig, newTsConfigPath);
updateCyDirTsConfigReferences(tree, projectConfig);
}
});
await formatFiles(tree);
}
function moveProjectTsCyConfig(
tree: Tree,
projectConfig: ProjectConfiguration,
newTsConfigPath: string
) {
if (tree.exists(joinPathFragments(projectConfig.root, 'tsconfig.cy.json'))) {
tree.rename(
joinPathFragments(projectConfig.root, 'tsconfig.cy.json'),
newTsConfigPath
);
updateJson(tree, newTsConfigPath, (json) => {
json.extends = '../tsconfig.json';
json.compilerOptions ??= {};
json.compilerOptions = {
...json.compilerOptions,
sourceMap: false,
outDir: '../../../dist/out-tsc',
};
json.include ??= [];
json.include = json.include.map((p) => {
if (p.startsWith('cypress/')) {
return p.replace('cypress/', '');
}
return `../${p}`;
});
return json;
});
}
}
function moveCyDirTsCyConfig(
tree: Tree,
projectConfig: ProjectConfiguration,
newTsConfigPath: string
) {
if (
tree.exists(
joinPathFragments(projectConfig.root, 'cypress', 'tsconfig.cy.json')
)
) {
tree.rename(
joinPathFragments(projectConfig.root, 'cypress', 'tsconfig.cy.json'),
newTsConfigPath
);
updateJson(tree, newTsConfigPath, (json) => {
json.compilerOptions ??= {};
json.compilerOptions = {
...json.compilerOptions,
sourceMap: false,
};
return json;
});
}
}
function updateCyDirTsConfigReferences(
tree: Tree,
projectConfig: ProjectConfiguration
) {
if (
!tree.exists(
joinPathFragments(projectConfig.root, 'cypress', 'tsconfig.json')
)
) {
return;
}
updateJson(
tree,
joinPathFragments(projectConfig.root, 'tsconfig.json'),
(json) => {
json.references ??= [];
if (!json.references) {
return json;
}
const cyFile = json.references.find((p) =>
p.path.includes('tsconfig.cy.json')
);
if (cyFile) {
json.references.splice(json.references.indexOf(cyFile), 1);
}
if (!json.references.some((r) => r.path === './cypress/tsconfig.json')) {
json.references.push({
path: './cypress/tsconfig.json',
});
}
return json;
}
);
}
export default normalizeCyTsConfigNames;

View File

@ -1,175 +0,0 @@
import {
Tree,
addProjectConfiguration,
readJson,
readProjectConfiguration,
updateJson,
updateProjectConfiguration,
} from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from 'nx/src/devkit-testing-exports';
import { fixLegacyCypressTsconfig } from './tsconfig-sourcemaps';
describe('Cypress Migration: tsconfig-sourcemaps', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
});
it('should remove tsconfig.e2e.json and update tsconfig.json', async () => {
addLegacyProject(tree);
await fixLegacyCypressTsconfig(tree);
expect(readProjectConfiguration(tree, 'legacy-e2e').targets.e2e)
.toMatchInlineSnapshot(`
{
"configurations": {
"production": {
"devServerTarget": "legacy-e2e:serve:production",
},
},
"executor": "@nx/cypress:cypress",
"options": {
"cypressConfig": "apps/legacy-e2e/cypress.config.ts",
"devServerTarget": "legacy-e2e:serve",
"testingType": "e2e",
},
}
`);
expect(readJson(tree, 'apps/legacy-e2e/tsconfig.json'))
.toMatchInlineSnapshot(`
{
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"resolveJsonModule": true,
"sourceMap": false,
"strict": true,
"types": [
"cypress",
"node",
],
},
"exclude": [],
"extends": "../../tsconfig.base.json",
"files": [],
"include": [
"cypress.ci.1.config.ts",
"cypress.ci.2.config.ts",
"cypress.ci.3.config.ts",
"cypress.ci.4.config.ts",
"src/**/*.ts",
"cypress.config.ts",
],
"references": [],
}
`);
expect(tree.exists('apps/legacy-e2e/tsconfig.e2e.json')).toBeFalsy();
expect(tree.exists('apps/legacy-e2e/tsconfig.e2e.prod.json')).toBeFalsy();
});
it('should do nothing if tsconfig option is not used', async () => {
addLegacyProject(tree);
tree.delete('apps/legacy-e2e/tsconfig.e2e.json');
tree.delete('apps/legacy-e2e/tsconfig.e2e.prod.json');
const pc = readProjectConfiguration(tree, 'legacy-e2e');
delete pc.targets.e2e.options.tsConfig;
delete pc.targets.e2e.configurations;
const existingProjectConfig = pc.targets.e2e;
updateProjectConfiguration(tree, 'legacy-e2e', pc);
updateJson(tree, 'apps/legacy-e2e/tsconfig.json', (json) => {
json.references = [];
return json;
});
const existingTsConfig = readJson(tree, 'apps/legacy-e2e/tsconfig.json');
await fixLegacyCypressTsconfig(tree);
expect(readProjectConfiguration(tree, 'legacy-e2e').targets.e2e).toEqual(
existingProjectConfig
);
expect(readJson(tree, 'apps/legacy-e2e/tsconfig.json')).toEqual(
existingTsConfig
);
});
});
function addLegacyProject(tree: Tree) {
addProjectConfiguration(tree, 'legacy-e2e', {
root: 'apps/legacy-e2e',
sourceRoot: 'apps/legacy-e2e/src',
targets: {
e2e: {
executor: '@nx/cypress:cypress',
options: {
cypressConfig: 'apps/legacy-e2e/cypress.config.ts',
tsConfig: 'apps/legacy-e2e/tsconfig.e2e.json',
devServerTarget: 'legacy-e2e:serve',
testingType: 'e2e',
},
configurations: {
production: {
devServerTarget: 'legacy-e2e:serve:production',
tsConfig: 'apps/legacy-e2e/tsconfig.e2e.prod.json',
},
},
},
},
});
tree.write(
'apps/legacy-e2e/tsconfig.e2e.json',
JSON.stringify({
extends: './tsconfig.json',
compilerOptions: {
sourceMap: false,
outDir: '../../dist/out-tsc',
types: ['cypress', 'node'],
},
include: ['src/**/*.ts', 'cypress.config.ts'],
})
);
tree.write(
'apps/legacy-e2e/tsconfig.e2e.prod.json',
JSON.stringify({
extends: './tsconfig.e2e.json',
compilerOptions: {
sourceMap: false,
outDir: '../../dist/out-tsc',
types: ['cypress', 'node'],
strict: true,
},
include: ['src/**/*.ts', 'cypress.config.ts'],
})
);
tree.write(
'apps/legacy-e2e/tsconfig.json',
JSON.stringify({
extends: '../../tsconfig.base.json',
compilerOptions: {
types: ['cypress', 'node'],
resolveJsonModule: true,
},
include: [
'cypress.ci.1.config.ts',
'cypress.ci.2.config.ts',
'cypress.ci.3.config.ts',
'cypress.ci.4.config.ts',
],
files: [],
references: [
{
path: './tsconfig.e2e.json',
},
{
path: './tsconfig.e2e.prod.json',
},
],
})
);
}

View File

@ -1,102 +0,0 @@
import { forEachExecutorOptions } from '@nx/devkit/src/generators/executor-options-utils';
import { CypressExecutorOptions } from '../../executors/cypress/cypress.impl';
import {
updateJson,
Tree,
getProjects,
joinPathFragments,
readJson,
updateProjectConfiguration,
formatFiles,
} from '@nx/devkit';
import { posix } from 'path';
export async function fixLegacyCypressTsconfig(tree: Tree) {
const projects = getProjects(tree);
forEachExecutorOptions<CypressExecutorOptions>(
tree,
'@nx/cypress:cypress',
(options, projectName, targetName, configName) => {
const projectConfig = projects.get(projectName);
if (
options.testingType !== 'e2e' &&
projectConfig.targets[targetName]?.options?.testingType !== 'e2e'
) {
return;
}
const tsconfigToRemove =
options.tsConfig ??
joinPathFragments(projectConfig.root, 'tsconfig.e2e.json');
const projectLevelConfigPath = joinPathFragments(
projectConfig.root,
'tsconfig.json'
);
if (
!tree.exists(projectLevelConfigPath) ||
!tree.exists(tsconfigToRemove)
) {
return;
}
if (tsconfigToRemove === projectLevelConfigPath) {
updateJson(tree, projectLevelConfigPath, (json) => {
json.compilerOptions = {
sourceMap: false,
...json.compilerOptions,
};
return json;
});
} else {
const e2eConfig = readJson(tree, tsconfigToRemove);
updateJson(tree, projectLevelConfigPath, (json) => {
json.compilerOptions = {
sourceMap: false,
...json.compilerOptions,
...e2eConfig.compilerOptions,
};
json.files = Array.from(
new Set([...(json.files ?? []), ...(e2eConfig.files ?? [])])
);
json.include = Array.from(
new Set([...(json.include ?? []), ...(e2eConfig.include ?? [])])
);
json.exclude = Array.from(
new Set([...(json.exclude ?? []), ...(e2eConfig.exclude ?? [])])
);
// these paths will always be 'unix style'
// and on windows relative will not work on these paths
const tsConfigFromProjRoot = posix.relative(
projectConfig.root,
tsconfigToRemove
);
json.references = (json.references ?? []).filter(
({ path }) => !path.includes(tsConfigFromProjRoot)
);
return json;
});
tree.delete(tsconfigToRemove);
}
if (configName) {
delete projectConfig.targets[targetName].configurations[configName]
.tsConfig;
} else {
delete projectConfig.targets[targetName].options.tsConfig;
}
updateProjectConfiguration(tree, projectName, projectConfig);
}
);
await formatFiles(tree);
}
export default fixLegacyCypressTsconfig;

View File

@ -1,243 +0,0 @@
import { Tree, addProjectConfiguration, readJson } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from 'nx/src/devkit-testing-exports';
import { updateToCypress13 } from './cypress-13';
describe('Cypress 13', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
});
it('should update deps to cypress v13', async () => {
setup(tree, { name: 'my-app' });
await updateToCypress13(tree);
expect(readJson(tree, 'package.json').devDependencies.cypress).toEqual(
'^13.0.0'
);
});
it('should update videoUploadOnPasses from config w/setupNodeEvents', async () => {
setup(tree, { name: 'my-app-video-upload-on-passes' });
await updateToCypress13(tree);
expect(
tree.read('apps/my-app-video-upload-on-passes/cypress.config.ts', 'utf-8')
).toMatchInlineSnapshot(`
"import fs from 'fs';
import { defineConfig } from 'cypress';
import { nxE2EPreset } from '@nx/cypress/plugins/cypress-preset';
import { nxComponentTestingPreset } from '@nx/react/plugins/component-testing';
export default defineConfig({
something: 'blah',
// nodeVersion: 'system',
// videoUploadOnPasses: false ,
e2e: {
...nxE2EPreset(__filename),
setupNodeEvents(on, config) {
const a = '';
removePassedSpecs(on);
},
},
component: {
...nxComponentTestingPreset(__filename),
setupNodeEvents: (on, config) => {
const b = '';
removePassedSpecs(on);
},
},
});
/**
* Delete videos for specs that do not contain failing or retried tests.
* This function is to be used in the 'setupNodeEvents' configuration option as a replacement to
* 'videoUploadOnPasses' which has been removed.
*
* https://docs.cypress.io/guides/guides/screenshots-and-videos#Delete-videos-for-specs-without-failing-or-retried-tests
**/
function removePassedSpecs(on) {
on('after:spec', (spec, results) => {
if (results && results.vide) {
const hasFailures = results.tests.some((t) =>
t.attempts.some((a) => a.state === 'failed')
);
if (!hasFailures) {
fs.unlinkSync(results.video);
}
}
});
}
"
`);
});
it('should remove nodeVersion from config', async () => {
setup(tree, { name: 'my-app-node-version' });
await updateToCypress13(tree);
expect(tree.read('apps/my-app-node-version/cypress.config.ts', 'utf-8'))
.toMatchInlineSnapshot(`
"import fs from 'fs';
import { defineConfig } from 'cypress';
import { nxE2EPreset } from '@nx/cypress/plugins/cypress-preset';
import { nxComponentTestingPreset } from '@nx/react/plugins/component-testing';
export default defineConfig({
something: 'blah',
// nodeVersion: 'system',
// videoUploadOnPasses: false ,
e2e: {
...nxE2EPreset(__filename),
setupNodeEvents(on, config) {
const a = '';
removePassedSpecs(on);
},
},
component: {
...nxComponentTestingPreset(__filename),
setupNodeEvents: (on, config) => {
const b = '';
removePassedSpecs(on);
},
},
});
/**
* Delete videos for specs that do not contain failing or retried tests.
* This function is to be used in the 'setupNodeEvents' configuration option as a replacement to
* 'videoUploadOnPasses' which has been removed.
*
* https://docs.cypress.io/guides/guides/screenshots-and-videos#Delete-videos-for-specs-without-failing-or-retried-tests
**/
function removePassedSpecs(on) {
on('after:spec', (spec, results) => {
if (results && results.vide) {
const hasFailures = results.tests.some((t) =>
t.attempts.some((a) => a.state === 'failed')
);
if (!hasFailures) {
fs.unlinkSync(results.video);
}
}
});
}
"
`);
});
it('should comment about overriding readFile command', async () => {
setup(tree, { name: 'my-app-read-file' });
const testContent = `describe('something', () => {
it('should do the thing', () => {
cy.readFile('my-data.json').its('name').should('eq', 'Nx');
});
});
`;
tree.write('apps/my-app-read-file/src/something.cy.ts', testContent);
tree.write(
'apps/my-app-read-file/cypress/support/commands.ts',
`declare namespace Cypress {
interface Chainable<Subject> {
login(email: string, password: string): void;
}
}
//
// -- This is a parent command --
Cypress.Commands.add('login', (email, password) => {
console.log('Custom command example: Login', email, password);
});
Cypress.Commands.overwrite('readFile', () => {});
`
);
await updateToCypress13(tree);
expect(
tree.read('apps/my-app-read-file/src/something.cy.ts', 'utf-8')
).toEqual(testContent);
expect(
tree.read('apps/my-app-read-file/cypress/support/commands.ts', 'utf-8')
).toMatchInlineSnapshot(`
"declare namespace Cypress {
interface Chainable<Subject> {
login(email: string, password: string): void;
}
}
//
// -- This is a parent command --
Cypress.Commands.add('login', (email, password) => {
console.log('Custom command example: Login', email, password);
});
/**
* TODO(@nx/cypress): This command can no longer be overridden
* Consider using a different name like 'custom_readFile'
* More info: https://docs.cypress.io/guides/references/migration-guide#readFile-can-no-longer-be-overwritten-with-CypressCommandsoverwrite
**/
Cypress.Commands.overwrite('readFile', () => {});
"
`);
});
});
function setup(tree: Tree, options: { name: string }) {
tree.write(
`apps/${options.name}/cypress.config.ts`,
`
import { defineConfig} from 'cypress';
import { nxE2EPreset } from '@nx/cypress/plugins/cypress-preset';
import { nxComponentTestingPreset } from '@nx/react/plugins/component-testing';
export default defineConfig({
something: 'blah',
nodeVersion: 'system',
videoUploadOnPasses: false,
e2e: {
...nxE2EPreset(__filename),
videoUploadOnPasses: false,
nodeVersion: 'bundled',
setupNodeEvents(on, config) {
const a = '';
},
},
component: {
...nxComponentTestingPreset(__filename),
videoUploadOnPasses: false,
nodeVersion: 'something',
setupNodeEvents: (on, config) => {
const b = '';
}
},
})
`
);
tree.write(
'package.json',
JSON.stringify({ devDependencies: { cypress: '^12.16.0' } })
);
addProjectConfiguration(tree, options.name, {
root: `apps/${options.name}`,
sourceRoot: `apps/${options.name}/src`,
targets: {
e2e: {
executor: '@nx/cypress:cypress',
options: {
testingType: 'e2e',
cypressConfig: `apps/${options.name}/cypress.config.ts`,
devServerTarget: 'app:serve',
},
},
'component-test': {
executor: '@nx/cypress:cypress',
options: {
testingType: 'component',
cypressConfig: `apps/${options.name}/ct-cypress.config.ts`,
skipServe: true,
devServerTarget: 'app:build',
},
},
},
});
}

View File

@ -1,246 +0,0 @@
import {
updateJson,
installPackagesTask,
getProjects,
visitNotIgnoredFiles,
formatFiles,
type Tree,
} from '@nx/devkit';
import { installedCypressVersion } from '../../utils/cypress-version';
import {
isObjectLiteralExpression,
isCallExpression,
type CallExpression,
type MethodDeclaration,
type PropertyAccessExpression,
type PropertyAssignment,
} from 'typescript';
import { tsquery } from '@phenomnomnominal/tsquery';
import { forEachExecutorOptions } from '@nx/devkit/src/generators/executor-options-utils';
import type { CypressExecutorOptions } from '../../executors/cypress/cypress.impl';
const JS_TS_FILE_MATCHER = /\.[jt]sx?$/;
export async function updateToCypress13(tree: Tree) {
if (installedCypressVersion() < 12) {
return;
}
const projects = getProjects(tree);
forEachExecutorOptions<CypressExecutorOptions>(
tree,
'@nx/cypress:cypress',
(options, projectName) => {
if (!options.cypressConfig || !tree.exists(options.cypressConfig)) {
return;
}
const projectConfig = projects.get(projectName);
removeNodeVersionOption(tree, options.cypressConfig);
removeVideoUploadOnPassesOption(tree, options.cypressConfig);
visitNotIgnoredFiles(tree, projectConfig.root, (filePath) => {
if (!JS_TS_FILE_MATCHER.test(filePath)) {
return;
}
shouldNotOverrideReadFile(tree, filePath);
});
}
);
updateJson(tree, 'package.json', (json) => {
json.devDependencies ??= {};
json.devDependencies.cypress = '^13.0.0';
return json;
});
await formatFiles(tree);
}
function removeVideoUploadOnPassesOption(tree: Tree, configPath: string) {
const config = tree.read(configPath, 'utf-8');
const isUsingDeprecatedOption =
tsquery.query(config, getPropertyQuery('videoUploadOnPasses'))?.length > 0;
if (!isUsingDeprecatedOption) {
return;
}
const importStatement = configPath.endsWith('.ts')
? "import fs from 'fs';"
: "const fs = require('fs');";
const replacementFunction = `/**
* Delete videos for specs that do not contain failing or retried tests.
* This function is to be used in the 'setupNodeEvents' configuration option as a replacement to
* 'videoUploadOnPasses' which has been removed.
*
* https://docs.cypress.io/guides/guides/screenshots-and-videos#Delete-videos-for-specs-without-failing-or-retried-tests
**/
function removePassedSpecs(on) {
on('after:spec', (spec, results) => {
if(results && results.vide) {
const hasFailures = results.tests.some(t => t.attempts.some(a => a.state === 'failed'));
if(!hasFailures) {
fs.unlinkSync(results.video);
}
}
})
}`;
const withReplacementFn = `${importStatement}\n${config}\n${replacementFunction}`;
// setupNodeEvents can be a property or method.
const setupNodeEventsQuery =
'ExportAssignment ObjectLiteralExpression > :matches(PropertyAssignment:has(Identifier[name="setupNodeEvents"]), MethodDeclaration:has(Identifier[name="setupNodeEvents"]))';
const hasSetupNodeEvents =
tsquery.query(withReplacementFn, setupNodeEventsQuery)?.length > 0;
let updatedWithSetupNodeEvents = withReplacementFn;
if (hasSetupNodeEvents) {
// if have setupNodeEvents, update existing fn to use removePassedSpecs helper and remove videoUploadOnPasses
const noVideoUploadOption = tsquery.replace(
withReplacementFn,
getPropertyQuery('videoUploadOnPasses'),
(node: PropertyAssignment) => {
if (isObjectLiteralExpression(node.initializer)) {
// is a nested config object
const key = node.name.getText().trim();
const listOfProperties = node.initializer.properties
.map((j) => j.getText())
.filter((j) => !j.includes('videoUploadOnPasses'))
.join(',\n');
return `${key}: {
${listOfProperties}
}
`;
} else {
if (isPropertyTopLevel(node)) {
return `// ${node.getText()} `;
}
}
}
);
updatedWithSetupNodeEvents = tsquery.replace(
noVideoUploadOption,
`${setupNodeEventsQuery} Block`,
(node: PropertyAssignment | MethodDeclaration) => {
const blockWithoutBraces = node
.getFullText()
.trim()
.slice(1, -1)
.trim();
return `{
${blockWithoutBraces}
removePassedSpecs(on);
}
`;
},
{ visitAllChildren: false }
);
} else {
// if don't have setupNodeEvents, replace videoUploadOnPasses with setupNodeEvents method
updatedWithSetupNodeEvents = tsquery.replace(
withReplacementFn,
getPropertyQuery('videoUploadOnPasses'),
() => {
return `setupNodeEvents(on, config) {
removePassedSpecs(on);
}`;
}
);
}
tree.write(configPath, updatedWithSetupNodeEvents);
}
/**
* remove the nodeVersion option from the config file
**/
function removeNodeVersionOption(tree: Tree, configPath: string) {
const config = tree.read(configPath, 'utf-8');
const updated = tsquery.replace(
config,
getPropertyQuery('nodeVersion'),
(node: PropertyAssignment) => {
if (isObjectLiteralExpression(node.initializer)) {
// is a nested config object
const key = node.name.getText().trim();
const listOfProperties = node.initializer.properties
.map((j) => j.getFullText())
.filter((j) => !j.includes('nodeVersion'))
.join(', ');
return `${key}: {
${listOfProperties}
}`;
} else {
if (isPropertyTopLevel(node)) {
return `// ${node.getText()}`;
}
}
}
);
if (updated !== config) {
tree.write(configPath, updated);
}
}
/**
* leave a comment on all usages of overriding built-ins that are now banned
**/
export function shouldNotOverrideReadFile(tree: Tree, filePath: string) {
const content = tree.read(filePath, 'utf-8');
const markedOverrideUsage = tsquery.replace(
content,
'PropertyAccessExpression:has(Identifier[name="overwrite"]):has(Identifier[name="Cypress"])',
(node: PropertyAccessExpression) => {
if (isAlreadyCommented(node)) {
return;
}
const expression = node.expression.getText().trim();
// prevent grabbing other Cypress.<something>.defaults
if (expression === 'Cypress.Commands') {
// get value.
const overwriteExpression = node.parent as CallExpression;
const command = (overwriteExpression.arguments?.[0] as any)?.text; // need string without quotes
if (command === 'readFile') {
// overwrite
return `/**
* TODO(@nx/cypress): This command can no longer be overridden
* Consider using a different name like 'custom_${command}'
* More info: https://docs.cypress.io/guides/references/migration-guide#readFile-can-no-longer-be-overwritten-with-CypressCommandsoverwrite
**/
${node.getText()}`;
}
}
}
);
tree.write(filePath, markedOverrideUsage);
}
function isAlreadyCommented(node: PropertyAccessExpression) {
return node.getFullText().includes('TODO(@nx/cypress)');
}
function isPropertyTopLevel(node: PropertyAssignment) {
return (
node.parent &&
isObjectLiteralExpression(node.parent) &&
node.parent.parent &&
isCallExpression(node.parent.parent)
);
}
const getPropertyQuery = (propertyName: string) =>
`ExportAssignment ObjectLiteralExpression > PropertyAssignment:has(Identifier[name="${propertyName}"])`;
export default updateToCypress13;

View File

@ -1,69 +1,6 @@
{
"generators": {
"update-16-0-0-add-nx-packages": {
"cli": "nx",
"version": "16.0.0-beta.1",
"description": "Replace @nrwl/detox with @nx/detox",
"implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages"
},
"update-16-0-0-update-detoxrc": {
"cli": "nx",
"version": "16.0.0-beta.3",
"description": "Update .detoxrc.json and jest.config.json for detox 20",
"implementation": "./src/migrations/update-16-0-0/update-detoxrc-json"
},
"update-detoxrc-json-expo-16-1-4": {
"cli": "nx",
"version": "16.1.4-beta.0",
"description": "Update .detoxrc.json for expo",
"implementation": "./src/migrations/update-16-1-4/update-detoxrc-json-expo"
}
},
"generators": {},
"packageJsonUpdates": {
"16.0.0": {
"version": "16.0.0-beta.3",
"packages": {
"detox": {
"version": "~20.7.0",
"alwaysAddToPackageJson": false
}
}
},
"16.1.1": {
"version": "16.1.1-beta.0",
"packages": {
"detox": {
"version": "~20.8.0",
"alwaysAddToPackageJson": false
},
"@config-plugins/detox": {
"version": "~5.0.1",
"alwaysAddToPackageJson": false
}
}
},
"16.1.5": {
"version": "16.1.5-beta.0",
"packages": {
"detox": {
"version": "^20.9.0",
"alwaysAddToPackageJson": false
}
}
},
"16.6.0": {
"version": "16.6.0-beta.6",
"packages": {
"detox": {
"version": "^20.11.1",
"alwaysAddToPackageJson": false
},
"@config-plugins/detox": {
"version": "~6.0.0",
"alwaysAddToPackageJson": false
}
}
},
"18.0.0": {
"version": "18.0.0-beta.0",
"packages": {

View File

@ -1,37 +0,0 @@
import { Tree, readJson, updateJson } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import replacePackage from './update-16-0-0-add-nx-packages';
describe('update-16-0-0-add-nx-packages', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
updateJson(tree, 'package.json', (json) => {
json.devDependencies['@nrwl/detox'] = '16.0.0';
return json;
});
});
it('should remove the dependency on @nrwl/detox', async () => {
await replacePackage(tree);
expect(
readJson(tree, 'package.json').dependencies['@nrwl/detox']
).not.toBeDefined();
expect(
readJson(tree, 'package.json').devDependencies['@nrwl/detox']
).not.toBeDefined();
});
it('should add a dependency on @nx/detox', async () => {
await replacePackage(tree);
const packageJson = readJson(tree, 'package.json');
const newDependencyVersion =
packageJson.devDependencies['@nx/detox'] ??
packageJson.dependencies['@nx/detox'];
expect(newDependencyVersion).toBeDefined();
});
});

View File

@ -1,8 +0,0 @@
import { Tree, formatFiles } from '@nx/devkit';
import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package';
export default async function replacePackage(tree: Tree): Promise<void> {
replaceNrwlPackageWithNxPackage(tree, '@nrwl/detox', '@nx/detox');
await formatFiles(tree);
}

View File

@ -1,57 +0,0 @@
import { addProjectConfiguration, readJson, Tree } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import update from './update-detoxrc-json';
describe('Update detoxrc for detox 20', () => {
let tree: Tree;
beforeEach(async () => {
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
addProjectConfiguration(tree, 'products', {
root: 'apps/products',
sourceRoot: 'apps/products/src',
targets: {
'test-ios': {
executor: '@nx/detox:test',
},
},
});
tree.write('apps/products/jest.config.json', `{"transform": {}}`);
tree.write('apps/products/.detoxrc.json', '{}');
});
it(`should update jest.config.json`, async () => {
await update(tree);
const jestConfig = readJson(tree, 'apps/products/jest.config.json');
expect(jestConfig).toEqual({
rootDir: '.',
testMatch: [
'<rootDir>/src/**/*.test.ts?(x)',
'<rootDir>/src/**/*.spec.ts?(x)',
],
globalSetup: 'detox/runners/jest/globalSetup',
globalTeardown: 'detox/runners/jest/globalTeardown',
reporter: ['detox/runners/jest/reporter'],
verbose: true,
});
});
it(`should update .detoxrc.json`, async () => {
await update(tree);
const detoxrcJson = readJson(tree, 'apps/products/.detoxrc.json');
expect(detoxrcJson).toEqual({
testRunner: {
args: {
$0: 'jest',
config: './jest.config.json',
},
jest: {
setupTimeout: 120000,
},
},
});
});
});

View File

@ -1,71 +0,0 @@
import {
Tree,
formatFiles,
getProjects,
updateJson,
ProjectConfiguration,
} from '@nx/devkit';
/**
* Update .detoxrc.json under detox project:
* - remove deprecated keys: testRunner
* - update keys: runnerConfig
* Update jest.config.json under detox project:
* - remove key: transform
* - add key: rootDir, testMatch, reporter, globalSetup, globalTeardown, verbose
*/
export default async function update(tree: Tree) {
const projects = getProjects(tree);
projects.forEach((project) => {
if (project.targets?.['test-ios']?.executor !== '@nx/detox:test') return;
updateDetoxrcJson(tree, project);
updateJestConfigJson(tree, project);
});
await formatFiles(tree);
}
function updateDetoxrcJson(host: Tree, project: ProjectConfiguration) {
const detoxConfigPath = `${project.root}/.detoxrc.json`;
if (!host.exists(detoxConfigPath)) return;
updateJson(host, detoxConfigPath, (json) => {
json.testRunner = {
args: {
$0: 'jest',
config: './jest.config.json',
},
jest: {
setupTimeout: 120000,
},
};
if (json.runnerConfig) {
delete json.runnerConfig;
}
return json;
});
}
function updateJestConfigJson(host: Tree, project: ProjectConfiguration) {
const jestConfigPath = `${project.root}/jest.config.json`;
if (!host.exists(jestConfigPath)) return;
updateJson(host, jestConfigPath, (json) => {
if (json.transform) {
delete json.transform;
}
if (!json.rootDir) {
json.rootDir = '.';
}
if (!json.testMatch) {
json.testMatch = [
'<rootDir>/src/**/*.test.ts?(x)',
'<rootDir>/src/**/*.spec.ts?(x)',
];
}
json.reporter = ['detox/runners/jest/reporter'];
json.globalSetup = 'detox/runners/jest/globalSetup';
json.globalTeardown = 'detox/runners/jest/globalTeardown';
json.verbose = true;
return json;
});
}

View File

@ -1,127 +0,0 @@
import { addProjectConfiguration, readJson, Tree } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import update from './update-detoxrc-json-expo';
describe('Update detoxrc for expo projects', () => {
let tree: Tree;
beforeEach(async () => {
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
addProjectConfiguration(tree, 'products', {
root: 'apps/products',
sourceRoot: 'apps/products/src',
targets: {
'test-ios': {
executor: '@nx/detox:test',
options: {
detoxConfiguration: 'ios.sim.eas',
},
},
'build-ios': {
executor: '@nx/detox:build',
options: {
detoxConfiguration: 'random value',
},
},
'test-android': {
executor: '@nx/detox:test',
options: {
detoxConfiguration: 'android.sim.eas',
},
},
'build-android': {
executor: '@nx/detox:build',
options: {
detoxConfiguration: 'random value',
},
},
},
});
tree.write('apps/products/jest.config.json', `{"transform": {}}`);
tree.write(
'apps/products/.detoxrc.json',
`{"apps": {"ios.eas": {}, "android.eas": {}, "ios.local": {}, "android.local": {}}}`
);
});
it(`should update .detoxrc.json`, async () => {
await update(tree);
const detoxrcJson = readJson(tree, 'apps/products/.detoxrc.json');
expect(detoxrcJson).toEqual({
apps: {
'ios.eas': {
build:
'npx nx run products:download --platform ios --distribution simulator --output=../../apps/products/dist/',
},
'android.eas': {
build:
'npx nx run products:download --platform android --distribution simulator --output=../../apps/products/dist/',
type: 'android.apk',
},
'ios.local': {
build:
'npx nx run products:build --platform ios --profile preview --wait --local --no-interactive --output=../../apps/products/dist/Products.tar.gz',
},
'android.local': {
build:
'npx nx run products:build --platform android --profile preview --wait --local --no-interactive --output=../../apps/products/dist/Products.apk',
type: 'android.apk',
},
},
});
});
it(`should update project.json`, async () => {
await update(tree);
const projectJson = readJson(tree, 'apps/products/project.json');
expect(projectJson).toEqual({
$schema: '../../node_modules/nx/schemas/project-schema.json',
name: 'products',
sourceRoot: 'apps/products/src',
targets: {
'build-android': {
executor: '@nx/detox:build',
options: {
detoxConfiguration: 'android.sim.eas',
},
},
'build-ios': {
executor: '@nx/detox:build',
options: {
detoxConfiguration: 'ios.sim.eas',
},
},
'test-android': {
configurations: {
bare: {
buildTarget: 'products:build-android:bare',
detoxConfiguration: 'android.emu.debug',
},
local: {
buildTarget: 'products:build-android:local',
detoxConfiguration: 'android.emu.local',
},
production: {
buildTarget: 'products:build-android:production',
detoxConfiguration: 'android.emu.release',
},
},
executor: '@nx/detox:test',
options: {
buildTarget: 'products:build-android',
detoxConfiguration: 'android.sim.eas',
},
},
'test-ios': {
executor: '@nx/detox:test',
options: {
detoxConfiguration: 'ios.sim.eas',
},
},
},
});
});
});

View File

@ -1,104 +0,0 @@
import {
Tree,
formatFiles,
getProjects,
updateJson,
ProjectConfiguration,
offsetFromRoot,
detectPackageManager,
getPackageManagerCommand,
names,
updateProjectConfiguration,
} from '@nx/devkit';
/**
* Update .detoxrc.json under detox project for expo:
* - fix the eas build command
* - fix the local build command
* - update project.json targets
*/
export default async function update(tree: Tree) {
const projects = getProjects(tree);
projects.forEach((project) => {
if (project.targets?.['test-ios']?.executor !== '@nx/detox:test') return;
updateDetoxrcJson(tree, project);
updateProjectJson(tree, project);
});
await formatFiles(tree);
}
function updateDetoxrcJson(host: Tree, project: ProjectConfiguration) {
const detoxConfigPath = `${project.root}/.detoxrc.json`;
const projectName = project.name?.endsWith('-e2e')
? project.name.substring(0, project.name.indexOf('-e2e'))
: project.name;
const appRoot = getProjects(host).get(projectName)?.root;
const appName = names(projectName).className;
const offset = offsetFromRoot(project.root);
const exec = getPackageManagerCommand(detectPackageManager(host.root)).exec;
if (!host.exists(detoxConfigPath)) return;
updateJson(host, detoxConfigPath, (json) => {
if (json.apps?.['ios.eas']) {
json.apps[
'ios.eas'
].build = `${exec} nx run ${projectName}:download --platform ios --distribution simulator --output=${offset}${appRoot}/dist/`;
}
if (json.apps?.['android.eas']) {
json.apps[
'android.eas'
].build = `${exec} nx run ${projectName}:download --platform android --distribution simulator --output=${offset}${appRoot}/dist/`;
json.apps['android.eas'].type = 'android.apk';
}
if (json.apps?.['ios.local']) {
json.apps[
'ios.local'
].build = `${exec} nx run ${projectName}:build --platform ios --profile preview --wait --local --no-interactive --output=${offset}${appRoot}/dist/${appName}.tar.gz`;
}
if (json.apps?.['android.local']) {
json.apps[
'android.local'
].build = `${exec} nx run ${projectName}:build --platform android --profile preview --wait --local --no-interactive --output=${offset}${appRoot}/dist/${appName}.apk`;
json.apps['android.local'].type = 'android.apk';
}
return json;
});
}
function updateProjectJson(host: Tree, project: ProjectConfiguration) {
if (
project.targets?.['test-ios']?.options?.detoxConfiguration == 'ios.sim.eas'
) {
project.targets['build-ios'].options.detoxConfiguration = 'ios.sim.eas';
}
if (
project.targets?.['test-android']?.options?.detoxConfiguration ==
'android.sim.eas'
) {
project.targets['build-android'].options.detoxConfiguration =
'android.sim.eas';
project.targets['test-android'] = {
executor: '@nx/detox:test',
options: {
detoxConfiguration: 'android.sim.eas',
buildTarget: `${project.name}:build-android`,
},
configurations: {
local: {
detoxConfiguration: 'android.emu.local',
buildTarget: `${project.name}:build-android:local`,
},
bare: {
detoxConfiguration: 'android.emu.debug',
buildTarget: `${project.name}:build-android:bare`,
},
production: {
detoxConfiguration: 'android.emu.release',
buildTarget: `${project.name}:build-android:production`,
},
},
};
}
updateProjectConfiguration(host, project.name, project);
}

View File

@ -1,18 +1,5 @@
{
"generators": {
"update-16-0-0-add-nx-packages": {
"cli": "nx",
"version": "16.0.0-beta.1",
"description": "Replace @nrwl/devkit with @nx/devkit",
"implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages"
},
"update-16-9-0-migrate-mf-usage-to-webpack": {
"cli": "nx",
"version": "16.9.0-beta.1",
"description": "Replace imports of Module Federation utils frm @nx/devkit to @nx/webpack",
"implementation": "./src/migrations/update-16-9-0/migrate-mf-util-usage"
}
},
"generators": {},
"packageJsonUpdates": {},
"version": "0.1"
}

View File

@ -1,41 +0,0 @@
import { assertRunsAgainstNxRepo } from 'nx/src/internal-testing-utils/run-migration-against-this-workspace';
import { createTreeWithEmptyWorkspace } from 'nx/src/generators/testing-utils/create-tree-with-empty-workspace';
import { Tree } from 'nx/src/generators/tree';
import { readJson, updateJson } from 'nx/src/generators/utils/json';
import replacePackage from './update-16-0-0-add-nx-packages';
describe('update-16-0-0-add-nx-packages', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
updateJson(tree, 'package.json', (json) => {
json.devDependencies['@nrwl/devkit'] = '16.0.0';
return json;
});
});
it('should remove the dependency on @nrwl/devkit', async () => {
await replacePackage(tree);
expect(
readJson(tree, 'package.json').dependencies['@nrwl/devkit']
).not.toBeDefined();
expect(
readJson(tree, 'package.json').devDependencies['@nrwl/devkit']
).not.toBeDefined();
});
it('should add a dependency on @nx/devkit', async () => {
await replacePackage(tree);
const packageJson = readJson(tree, 'package.json');
const newDependencyVersion =
packageJson.devDependencies['@nx/devkit'] ??
packageJson.dependencies['@nx/devkit'];
expect(newDependencyVersion).toBeDefined();
});
assertRunsAgainstNxRepo(replacePackage);
});

View File

@ -1,9 +0,0 @@
import type { Tree } from 'nx/src/devkit-exports';
import { formatFiles } from '../../generators/format-files';
import { replaceNrwlPackageWithNxPackage } from '../../utils/replace-package';
export default async function replacePackage(tree: Tree): Promise<void> {
await replaceNrwlPackageWithNxPackage(tree, '@nrwl/devkit', '@nx/devkit');
await formatFiles(tree);
}

View File

@ -1,231 +0,0 @@
import { createTreeWithEmptyWorkspace } from 'nx/src/generators/testing-utils/create-tree-with-empty-workspace';
import { stripIndents } from 'nx/src/utils/strip-indents';
import { readJson } from 'nx/src/generators/utils/json';
import migrateMfUtilUsage from './migrate-mf-util-usage';
describe('migrate-mf-util-usage', () => {
it('should do nothing if it does not find files using the mf public api', async () => {
// ARRANGE
const testFileContents = `${stripIndents`import { readFileSync } from 'fs';
const file = readFileSync('test.ts');`}\n`;
const tree = createTreeWithEmptyWorkspace();
tree.write('test.ts', testFileContents);
// ACT
await migrateMfUtilUsage(tree);
// ASSERT
expect(tree.read('test.ts', 'utf-8')).toEqual(testFileContents);
});
it('should do nothing if it does not find files using the mf public api even if they use devkit', async () => {
// ARRANGE
const testFileContents = `${stripIndents`import { readJson } from '@nx/devkit';
const file = readJson('test.json');`}\n`;
const tree = createTreeWithEmptyWorkspace();
tree.write('test.ts', testFileContents);
// ACT
await migrateMfUtilUsage(tree);
// ASSERT
expect(tree.read('test.ts', 'utf-8')).toEqual(testFileContents);
});
it('should replace imports to utils from devkit with webpack', async () => {
// ARRANGE
const testFileContents = stripIndents`import {ModuleFederationConfig} from '@nx/devkit';
const config: ModuleFederationConfig = {};
`;
const expectedTestFileContents = `${stripIndents`import { ModuleFederationConfig } from '@nx/webpack';
const config: ModuleFederationConfig = {};`}\n`;
const tree = createTreeWithEmptyWorkspace();
tree.write('test.ts', testFileContents);
// ACT
await migrateMfUtilUsage(tree);
// ASSERT
expect(tree.read('test.ts', 'utf-8')).toEqual(expectedTestFileContents);
expect(
readJson(tree, 'package.json').devDependencies['@nx/webpack']
).toBeDefined();
});
it('should extract imports to utils from devkit and replace with imports from webpack', async () => {
// ARRANGE
const testFileContents = stripIndents`import {joinPathFragments, ModuleFederationConfig} from '@nx/devkit';
const config: ModuleFederationConfig = {};
`;
const expectedTestFileContents = `${stripIndents`import { joinPathFragments } from '@nx/devkit';
import { ModuleFederationConfig } from '@nx/webpack';
const config: ModuleFederationConfig = {};`}\n`;
const tree = createTreeWithEmptyWorkspace();
tree.write('test.ts', testFileContents);
// ACT
await migrateMfUtilUsage(tree);
// ASSERT
expect(tree.read('test.ts', 'utf-8')).toEqual(expectedTestFileContents);
expect(
readJson(tree, 'package.json').devDependencies['@nx/webpack']
).toBeDefined();
});
it('should extract imports to utils from devkit and replace with imports from webpack, even with multiple devkit imports', async () => {
// ARRANGE
const testFileContents = stripIndents`import {joinPathFragments, ModuleFederationConfig} from '@nx/devkit';
import {readJson, WorkspaceLibrary} from '@nx/devkit';
const config: ModuleFederationConfig = {};
`;
const expectedTestFileContents = `${stripIndents`import { joinPathFragments } from '@nx/devkit';
import { readJson } from '@nx/devkit';
import { ModuleFederationConfig, WorkspaceLibrary } from '@nx/webpack';
const config: ModuleFederationConfig = {};`}\n`;
const tree = createTreeWithEmptyWorkspace();
tree.write('test.ts', testFileContents);
// ACT
await migrateMfUtilUsage(tree);
// ASSERT
expect(tree.read('test.ts', 'utf-8')).toEqual(expectedTestFileContents);
expect(
readJson(tree, 'package.json').devDependencies['@nx/webpack']
).toBeDefined();
});
describe('require()', () => {
it('should do nothing if it does not find files using the mf public api', async () => {
// ARRANGE
const testFileContents = `${stripIndents`const { readFileSync } = require('fs');
const file = readFileSync('test.ts');`}\n`;
const tree = createTreeWithEmptyWorkspace();
tree.write('test.ts', testFileContents);
// ACT
await migrateMfUtilUsage(tree);
// ASSERT
expect(tree.read('test.ts', 'utf-8')).toEqual(testFileContents);
});
it('should do nothing if it does not find files using the mf public api even if they use devkit', async () => {
// ARRANGE
const testFileContents = `${stripIndents`const { readJson } = require('@nx/devkit');
const file = readJson('test.json');`}\n`;
const tree = createTreeWithEmptyWorkspace();
tree.write('test.ts', testFileContents);
// ACT
await migrateMfUtilUsage(tree);
// ASSERT
expect(tree.read('test.ts', 'utf-8')).toEqual(testFileContents);
});
it('should replace imports to utils from devkit with webpack', async () => {
// ARRANGE
const testFileContents = stripIndents`const {ModuleFederationConfig} = require('@nx/devkit');
const config: ModuleFederationConfig = {};
`;
const expectedTestFileContents = `${stripIndents`const { ModuleFederationConfig } = require('@nx/webpack');
const config: ModuleFederationConfig = {};`}\n`;
const tree = createTreeWithEmptyWorkspace();
tree.write('test.ts', testFileContents);
// ACT
await migrateMfUtilUsage(tree);
// ASSERT
expect(tree.read('test.ts', 'utf-8')).toEqual(expectedTestFileContents);
expect(
readJson(tree, 'package.json').devDependencies['@nx/webpack']
).toBeDefined();
});
it('should extract imports to utils from devkit and replace with imports from webpack', async () => {
// ARRANGE
const testFileContents = stripIndents`const {joinPathFragments, ModuleFederationConfig} = require("@nx/devkit");
const config: ModuleFederationConfig = {};
`;
const expectedTestFileContents = `${stripIndents`const { joinPathFragments } = require('@nx/devkit');
const { ModuleFederationConfig } = require('@nx/webpack');
const config: ModuleFederationConfig = {};`}\n`;
const tree = createTreeWithEmptyWorkspace();
tree.write('test.ts', testFileContents);
// ACT
await migrateMfUtilUsage(tree);
// ASSERT
expect(tree.read('test.ts', 'utf-8')).toEqual(expectedTestFileContents);
expect(
readJson(tree, 'package.json').devDependencies['@nx/webpack']
).toBeDefined();
});
it('should extract imports to utils from devkit and replace with imports from webpack, even with multiple devkit imports', async () => {
// ARRANGE
const testFileContents = stripIndents`const {joinPathFragments, ModuleFederationConfig} = require('@nx/devkit');
const {readJson, WorkspaceLibrary} = require('@nx/devkit');
const config: ModuleFederationConfig = {};
`;
const expectedTestFileContents = `${stripIndents`const { joinPathFragments } = require('@nx/devkit');
const { readJson } = require('@nx/devkit');
const { ModuleFederationConfig, WorkspaceLibrary } = require('@nx/webpack');
const config: ModuleFederationConfig = {};`}\n`;
const tree = createTreeWithEmptyWorkspace();
tree.write('test.ts', testFileContents);
// ACT
await migrateMfUtilUsage(tree);
// ASSERT
expect(tree.read('test.ts', 'utf-8')).toEqual(expectedTestFileContents);
expect(
readJson(tree, 'package.json').devDependencies['@nx/webpack']
).toBeDefined();
});
});
it('should replace imports to utils from devkit with webpack in JSDoc comments', async () => {
// ARRANGE
const testFileContents = stripIndents`
/**
* @type {import('@nx/devkit').ModuleFederationConfig}
**/
const config = {};
`;
const tree = createTreeWithEmptyWorkspace();
tree.write('test.js', testFileContents);
// ACT
await migrateMfUtilUsage(tree);
// ASSERT
expect(tree.read('test.js', 'utf-8')).toMatchInlineSnapshot(`
"/**
* @type {import('@nx/webpack').ModuleFederationConfig}
**/
const config = {};
"
`);
expect(
readJson(tree, 'package.json').devDependencies['@nx/webpack']
).toBeDefined();
});
});

View File

@ -1,321 +0,0 @@
import type { Node, SyntaxKind } from 'typescript';
import { visitNotIgnoredFiles } from '../../generators/visit-not-ignored-files';
import { formatFiles } from '../../generators/format-files';
import {
addDependenciesToPackageJson,
ensurePackage,
} from '../../utils/package-json';
import { typescriptVersion } from '../../utils/versions';
import { GeneratorCallback, readJson, Tree } from 'nx/src/devkit-exports';
let tsModule: typeof import('typescript');
const MODULE_FEDERATION_PUBLIC_TOKENS = [
'AdditionalSharedConfig',
'ModuleFederationConfig',
'SharedLibraryConfig',
'SharedWorkspaceLibraryConfig',
'WorkspaceLibrary',
'SharedFunction',
'WorkspaceLibrarySecondaryEntryPoint',
'Remotes',
'ModuleFederationLibrary',
'applySharedFunction',
'applyAdditionalShared',
'getNpmPackageSharedConfig',
'shareWorkspaceLibraries',
'sharePackages',
'mapRemotes',
'mapRemotesForSSR',
'getDependentPackagesForProject',
'readRootPackageJson',
];
export default async (tree: Tree): Promise<GeneratorCallback | void> => {
let hasFileToMigrate = false;
visitNotIgnoredFiles(tree, '/', (path) => {
if (!path.endsWith('.ts') && !path.endsWith('.js')) {
return;
}
let fileContents = tree.read(path, 'utf-8');
if (
MODULE_FEDERATION_PUBLIC_TOKENS.every(
(token) => !fileContents.includes(token)
)
) {
return;
}
hasFileToMigrate = true;
fileContents = replaceTSImports(tree, path, fileContents);
fileContents = replaceRequireCalls(tree, path, fileContents);
fileContents = replaceJSDoc(tree, path, fileContents);
tree.write(path, fileContents);
});
if (hasFileToMigrate) {
await formatFiles(tree);
const pkgJson = readJson(tree, 'package.json');
const nxVersion =
pkgJson.devDependencies?.['nx'] ??
pkgJson.dependencies?.['nx'] ??
'17.0.0';
return addDependenciesToPackageJson(tree, {}, { '@nx/webpack': nxVersion });
}
};
function replaceJSDoc(tree: Tree, path: string, fileContents: string) {
let newFileContents = fileContents;
for (const token of MODULE_FEDERATION_PUBLIC_TOKENS) {
newFileContents = newFileContents.replaceAll(
new RegExp(
`(@type)+\\s({)+(\\s)*(import\\(('|")+@nx\/devkit('|")+\\)\.)+(${token})+\\s*(})+`,
'g'
),
`@type {import('@nx/webpack').${token}}`
);
}
return newFileContents;
}
function replaceRequireCalls(
tree: Tree,
path: string,
fileContents: string
): string {
if (!tsModule) {
tsModule = ensurePackage('typescript', typescriptVersion);
}
const sourceFile = tsModule.createSourceFile(
path,
fileContents,
tsModule.ScriptTarget.Latest,
true
);
const allDevkitRequires = findNodes(
sourceFile,
tsModule.SyntaxKind.VariableStatement
)
.filter((node) =>
[`require("@nx/devkit")`, `require('@nx/devkit')`].some((r) =>
node.getText().includes(r)
)
)
.filter(
(node) => findNodes(node, tsModule.SyntaxKind.ObjectBindingPattern).length
);
const mfUtilRequires = allDevkitRequires.filter((node) =>
MODULE_FEDERATION_PUBLIC_TOKENS.some((token) =>
node.getText().includes(token)
)
);
if (!mfUtilRequires.length) {
return fileContents;
}
const mfUtilTokens = mfUtilRequires.map((node) => {
const allTokens = findNodes(node, tsModule.SyntaxKind.BindingElement);
const mfTokens = allTokens.filter((node) =>
MODULE_FEDERATION_PUBLIC_TOKENS.some((token) => node.getText() === token)
);
return {
requireNode: node,
onlyMf: allTokens.length === mfTokens.length,
mfTokens,
};
});
const changes: {
startPosition: number;
endPosition?: number;
content: string;
}[] = [];
for (const mfUtilRequireData of mfUtilTokens) {
if (mfUtilRequireData.onlyMf) {
changes.push({
startPosition: mfUtilRequireData.requireNode.getStart(),
endPosition: mfUtilRequireData.requireNode.getEnd(),
content: '',
});
} else {
for (const mfToken of mfUtilRequireData.mfTokens) {
const replaceTrailingComma =
mfToken.getText().charAt(mfToken.getEnd() + 1) === ',';
changes.push({
startPosition: mfToken.getStart(),
endPosition: replaceTrailingComma
? mfToken.getEnd() + 1
: mfToken.getEnd(),
content: '',
});
}
}
}
changes.push({
startPosition: mfUtilTokens[mfUtilTokens.length - 1].requireNode.getEnd(),
content: `\nconst { ${mfUtilTokens
.map((mfUtilToken) => mfUtilToken.mfTokens.map((node) => node.getText()))
.join(', ')} } = require('@nx/webpack');`,
});
let newFileContents = fileContents;
while (changes.length) {
const change = changes.pop();
newFileContents = `${newFileContents.substring(0, change.startPosition)}${
change.content
}${newFileContents.substring(
change.endPosition ? change.endPosition : change.startPosition
)}`;
}
return newFileContents;
}
function replaceTSImports(
tree: Tree,
path: string,
fileContents: string
): string {
if (!tsModule) {
tsModule = ensurePackage('typescript', typescriptVersion);
}
const sourceFile = tsModule.createSourceFile(
path,
fileContents,
tsModule.ScriptTarget.Latest,
true
);
const allImports = findNodes(
sourceFile,
tsModule.SyntaxKind.ImportDeclaration
);
const devkitImports = allImports.filter((i) =>
i.getText().includes(`'@nx/devkit';`)
);
const mfUtilsImports = devkitImports.filter((i) =>
MODULE_FEDERATION_PUBLIC_TOKENS.some((token) => i.getText().includes(token))
);
if (!mfUtilsImports.length) {
return fileContents;
}
const mfUtilsWithMultipleImports = mfUtilsImports.map((i) => {
const importSpecifierNodes = findNodes(
i,
tsModule.SyntaxKind.ImportSpecifier
);
const mfImportSpecifierNodes = importSpecifierNodes.filter((node) =>
MODULE_FEDERATION_PUBLIC_TOKENS.some((token) =>
node.getText().includes(token)
)
);
return {
importDeclarationNode: i,
onlyMf: mfImportSpecifierNodes.length === importSpecifierNodes.length,
mfImportSpecifierNodes,
};
});
const changes: {
startPosition: number;
endPosition?: number;
content: string;
}[] = [];
for (const importDeclaration of mfUtilsWithMultipleImports) {
if (importDeclaration.onlyMf) {
changes.push({
startPosition: importDeclaration.importDeclarationNode.getStart(),
endPosition: importDeclaration.importDeclarationNode.getEnd(),
content: '',
});
} else {
for (const mfImportSpecifierNodes of importDeclaration.mfImportSpecifierNodes) {
const replaceTrailingComma =
importDeclaration.importDeclarationNode
.getText()
.charAt(mfImportSpecifierNodes.getEnd() + 1) === ',';
changes.push({
startPosition: mfImportSpecifierNodes.getStart(),
endPosition: replaceTrailingComma
? mfImportSpecifierNodes.getEnd() + 1
: mfImportSpecifierNodes.getEnd(),
content: '',
});
}
}
}
changes.push({
startPosition:
mfUtilsWithMultipleImports[
mfUtilsWithMultipleImports.length - 1
].importDeclarationNode.getEnd(),
content: `\nimport { ${mfUtilsWithMultipleImports
.map((importDeclaration) =>
importDeclaration.mfImportSpecifierNodes.map((node) => node.getText())
)
.join(', ')} } from '@nx/webpack';`,
});
let newFileContents = fileContents;
while (changes.length) {
const change = changes.pop();
newFileContents = `${newFileContents.substring(0, change.startPosition)}${
change.content
}${newFileContents.substring(
change.endPosition ? change.endPosition : change.startPosition
)}`;
}
return newFileContents;
}
function findNodes(
node: Node,
kind: SyntaxKind | SyntaxKind[],
max = Infinity
): Node[] {
if (!node || max == 0) {
return [];
}
const arr: Node[] = [];
const hasMatch = Array.isArray(kind)
? kind.includes(node.kind)
: node.kind === kind;
if (hasMatch) {
arr.push(node);
max--;
}
if (max > 0) {
for (const child of node.getChildren()) {
findNodes(child, kind, max).forEach((node) => {
if (max > 0) {
arr.push(node);
}
max--;
});
if (max <= 0) {
break;
}
}
}
return arr;
}

View File

@ -1,36 +1,4 @@
{
"generators": {
"update-16-0-0-add-nx-packages": {
"cli": "nx",
"version": "16.0.0-beta.1",
"description": "Replace @nrwl/esbuild with @nx/esbuild",
"implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages"
},
"update-16-0-1-set-thirdparty-true": {
"version": "16.0.1-beta.0",
"description": "Set thirdParty to true to maintain the existing behavior of bundling dependencies.",
"cli": "nx",
"implementation": "./src/migrations/update-16-0-1-set-thirdparty-true/update-16-0-1-set-thirdparty-true"
}
},
"packageJsonUpdates": {
"16.0.0": {
"version": "16.0.0-beta.5",
"packages": {
"esbuild": {
"version": "0.17.17",
"alwaysAddToPackageJson": false
}
}
},
"16.8.0": {
"version": "16.8.0-beta.2",
"packages": {
"esbuild": {
"version": "^0.19.2",
"alwaysAddToPackageJson": false
}
}
}
}
"generators": {},
"packageJsonUpdates": {}
}

View File

@ -1,37 +0,0 @@
import { Tree, readJson, updateJson } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import replacePackage from './update-16-0-0-add-nx-packages';
describe('update-16-0-0-add-nx-packages', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
updateJson(tree, 'package.json', (json) => {
json.devDependencies['@nrwl/esbuild'] = '16.0.0';
return json;
});
});
it('should remove the dependency on @nrwl/esbuild', async () => {
await replacePackage(tree);
expect(
readJson(tree, 'package.json').dependencies['@nrwl/esbuild']
).not.toBeDefined();
expect(
readJson(tree, 'package.json').devDependencies['@nrwl/esbuild']
).not.toBeDefined();
});
it('should add a dependency on @nx/esbuild', async () => {
await replacePackage(tree);
const packageJson = readJson(tree, 'package.json');
const newDependencyVersion =
packageJson.devDependencies['@nx/esbuild'] ??
packageJson.dependencies['@nx/esbuild'];
expect(newDependencyVersion).toBeDefined();
});
});

View File

@ -1,8 +0,0 @@
import { Tree, formatFiles } from '@nx/devkit';
import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package';
export default async function replacePackage(tree: Tree): Promise<void> {
await replaceNrwlPackageWithNxPackage(tree, '@nrwl/esbuild', '@nx/esbuild');
await formatFiles(tree);
}

View File

@ -1,109 +0,0 @@
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import {
addProjectConfiguration,
readProjectConfiguration,
Tree,
} from '@nx/devkit';
import update from './update-16-0-1-set-thirdparty-true';
describe('update-16-0-1-set-thirdparty-true', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
});
it('should skip migration targets are not set on the project', async () => {
addProjectConfiguration(tree, 'myapp', {
root: 'myapp',
});
await update(tree);
const config = readProjectConfiguration(tree, 'myapp');
expect(config.targets).toBeUndefined();
});
it('should add thirdParty property if bundling is enabled implicitly', async () => {
addProjectConfiguration(tree, 'myapp', {
root: 'myapp',
targets: {
build: {
executor: '@nx/esbuild:esbuild',
},
},
});
await update(tree);
const config = readProjectConfiguration(tree, 'myapp');
expect(config.targets.build.options).toEqual({
thirdParty: true,
});
});
it('should add thirdParty property if bundling is enabled explicitly', async () => {
addProjectConfiguration(tree, 'myapp', {
root: 'myapp',
targets: {
build: {
executor: '@nx/esbuild:esbuild',
options: {
bundle: true,
},
},
},
});
await update(tree);
const config = readProjectConfiguration(tree, 'myapp');
expect(config.targets.build.options).toEqual({
bundle: true,
thirdParty: true,
});
});
it('should not add thirdParty property if bundling is disabled', async () => {
addProjectConfiguration(tree, 'myapp', {
root: 'myapp',
targets: {
build: {
executor: '@nx/esbuild:esbuild',
options: {
bundle: false,
},
},
},
});
await update(tree);
const config = readProjectConfiguration(tree, 'myapp');
expect(config.targets.build.options).toEqual({
bundle: false,
});
});
it('should not set thirdParty property if it was already set', async () => {
addProjectConfiguration(tree, 'myapp', {
root: 'myapp',
targets: {
build: {
executor: '@nx/esbuild:esbuild',
options: {
thirdParty: false,
},
},
},
});
await update(tree);
const config = readProjectConfiguration(tree, 'myapp');
expect(config.targets.build.options).toEqual({
thirdParty: false,
});
});
});

View File

@ -1,39 +0,0 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import {
formatFiles,
getProjects,
Tree,
updateProjectConfiguration,
} from '@nx/devkit';
export default async function update(host: Tree) {
const projects = getProjects(host);
projects.forEach((projectConfig, projectName) => {
if (!projectConfig.targets) return;
let shouldUpdate = false;
Object.entries(projectConfig.targets).forEach(
([targetName, targetConfig]) => {
if (
targetConfig.executor === '@nrwl/esbuild:esbuild' ||
targetConfig.executor === '@nx/esbuild:esbuild'
) {
projectConfig.targets[targetName].options ??= {};
if (projectConfig.targets[targetName].options.bundle !== false) {
shouldUpdate = true;
projectConfig.targets[targetName].options.thirdParty ??= true;
}
}
}
);
if (shouldUpdate) {
updateProjectConfiguration(host, projectName, projectConfig);
}
});
await formatFiles(host);
}

View File

@ -1,11 +1,5 @@
{
"generators": {
"update-16-0-0-add-nx-packages": {
"cli": "nx",
"version": "16.0.0-beta.1",
"description": "Replace @nrwl/eslint-plugin-nx with @nx/eslint-plugin",
"implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages"
},
"update-17-2-6-rename-workspace-rules": {
"cli": "nx",
"version": "17.2.6-beta.1",

View File

@ -1,83 +0,0 @@
import { Tree, readJson, updateJson, writeJson } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import replacePackage from './update-16-0-0-add-nx-packages';
describe('update-16-0-0-add-nx-packages', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
updateJson(tree, 'package.json', (json) => {
json.devDependencies['@nrwl/eslint-plugin-nx'] = '16.0.0';
return json;
});
});
it('should remove the dependency on @nrwl/eslint-plugin-nx', async () => {
await replacePackage(tree);
expect(
readJson(tree, 'package.json').dependencies['@nrwl/eslint-plugin-nx']
).not.toBeDefined();
expect(
readJson(tree, 'package.json').devDependencies['@nrwl/eslint-plugin-nx']
).not.toBeDefined();
});
it('should add a dependency on @nx/eslint-plugin', async () => {
await replacePackage(tree);
const packageJson = readJson(tree, 'package.json');
const newDependencyVersion =
packageJson.devDependencies['@nx/eslint-plugin'] ??
packageJson.dependencies['@nx/eslint-plugin'];
expect(newDependencyVersion).toBeDefined();
});
it('should replace the eslint plugin', async () => {
writeJson(tree, '.eslintrc.json', {
plugins: ['@nrwl/nx'],
rules: {
'@nrwl/nx/enforce-module-boundaries': ['error', {}],
},
});
await replacePackage(tree);
expect(readJson(tree, '.eslintrc.json')).toMatchInlineSnapshot(`
{
"plugins": [
"@nx",
],
"rules": {
"@nx/enforce-module-boundaries": [
"error",
{},
],
},
}
`);
});
it('should replace eslint-ignore comments', async () => {
tree.write(
'ignored-file.ts',
'// eslint-disable-next-line @nrwl/nx/enforce-module-boundaries\n /*\n* eslint-disable @nrwl/nx/enforce-module-boundaries\n*/\n // eslint-disable-line @nrwl/nx/enforce-module-boundaries'
);
tree.write('plugin.ts', `import * as p from '@nrwl/nx-plugin'`);
await replacePackage(tree);
expect(tree.read('ignored-file.ts').toString()).toMatchInlineSnapshot(`
"// eslint-disable-next-line @nx/enforce-module-boundaries
/*
* eslint-disable @nx/enforce-module-boundaries
*/
// eslint-disable-line @nx/enforce-module-boundaries"
`);
expect(tree.read('plugin.ts').toString()).toMatchInlineSnapshot(
`"import * as p from '@nrwl/nx-plugin'"`
);
});
});

View File

@ -1,51 +0,0 @@
import { Tree, formatFiles, visitNotIgnoredFiles } from '@nx/devkit';
import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package';
import { basename } from 'path';
import { isBinaryPath } from '@nx/devkit/src/utils/binary-extensions';
const eslintFileNames = [
'.eslintrc',
'.eslintrc.js',
'.eslintrc.cjs',
'.eslintrc.yaml',
'.eslintrc.yml',
'.eslintrc.json',
'eslint.config.js', // new format that requires `ESLINT_USE_FLAT_CONFIG=true`
];
export default async function replacePackage(tree: Tree): Promise<void> {
await replaceNrwlPackageWithNxPackage(
tree,
'@nrwl/eslint-plugin-nx',
'@nx/eslint-plugin'
);
/**
* Matches:
* * // eslint-disable-next-line @nrwl/nx/...
* * // eslint-disable-line @nrwl/nx/...
* * /* eslint-disable @nrwl/nx/...
*/
const ignoreLineRegex = /(eslint-disable(?:(?:-next)?-line)?\s*)@nrwl\/nx/g;
visitNotIgnoredFiles(tree, '.', (path) => {
if (isBinaryPath(path)) {
return;
}
let contents = tree.read(path).toString();
if (eslintFileNames.includes(basename(path))) {
if (!contents.includes('@nrwl/nx')) {
return;
}
contents = contents.replace(new RegExp('@nrwl/nx', 'g'), '@nx');
}
if (ignoreLineRegex.test(contents)) {
contents = contents.replace(ignoreLineRegex, '$1@nx');
}
tree.write(path, contents);
});
await formatFiles(tree);
}

View File

@ -1,16 +1,5 @@
{
"generators": {
"update-16-0-0-add-nx-packages": {
"cli": "nx",
"version": "16.0.0-beta.1",
"description": "Replace @nrwl/linter with @nx/linter",
"implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages"
},
"update-16-8-0-add-ignored-files": {
"version": "16.8.0",
"description": "update-16-8-0-add-ignored-files",
"implementation": "./src/migrations/update-16-8-0-add-ignored-files/update-16-8-0-add-ignored-files"
},
"update-17-0-0-rename-to-eslint": {
"version": "17.0.0-beta.7",
"description": "update-17-0-0-rename-to-eslint",
@ -33,51 +22,6 @@
}
},
"packageJsonUpdates": {
"16.0.0": {
"version": "16.0.0-beta.0",
"packages": {
"@typescript-eslint/parser": {
"version": "^5.58.0"
},
"@typescript-eslint/eslint-plugin": {
"version": "^5.58.0"
},
"@typescript-eslint/utils": {
"version": "^5.58.0"
}
}
},
"16.5.0": {
"version": "16.5.0-beta.2",
"packages": {
"@typescript-eslint/parser": {
"version": "^5.60.1"
},
"@typescript-eslint/eslint-plugin": {
"version": "^5.60.1"
},
"@typescript-eslint/utils": {
"version": "^5.60.1"
}
}
},
"16.7.0": {
"version": "16.7.0-beta.2",
"packages": {
"eslint": {
"version": "~8.46.0"
},
"@typescript-eslint/parser": {
"version": "^5.60.1"
},
"@typescript-eslint/eslint-plugin": {
"version": "^5.60.1"
},
"@typescript-eslint/utils": {
"version": "^5.60.1"
}
}
},
"17.0.0": {
"version": "17.0.0-rc.2",
"packages": {

View File

@ -1,37 +0,0 @@
import { Tree, readJson, updateJson } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import replacePackage from './update-16-0-0-add-nx-packages';
describe('update-16-0-0-add-nx-packages', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
updateJson(tree, 'package.json', (json) => {
json.devDependencies['@nrwl/linter'] = '16.0.0';
return json;
});
});
it('should remove the dependency on @nrwl/linter', async () => {
await replacePackage(tree);
expect(
readJson(tree, 'package.json').dependencies['@nrwl/linter']
).not.toBeDefined();
expect(
readJson(tree, 'package.json').devDependencies['@nrwl/linter']
).not.toBeDefined();
});
it('should add a dependency on @nx/linter', async () => {
await replacePackage(tree);
const packageJson = readJson(tree, 'package.json');
const newDependencyVersion =
packageJson.devDependencies['@nx/linter'] ??
packageJson.dependencies['@nx/linter'];
expect(newDependencyVersion).toBeDefined();
});
});

View File

@ -1,8 +0,0 @@
import { Tree, formatFiles } from '@nx/devkit';
import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package';
export default async function replacePackage(tree: Tree): Promise<void> {
await replaceNrwlPackageWithNxPackage(tree, '@nrwl/linter', '@nx/linter');
await formatFiles(tree);
}

View File

@ -1,194 +0,0 @@
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import { addProjectConfiguration, readJson, Tree, writeJson } from '@nx/devkit';
import update from './update-16-8-0-add-ignored-files';
describe('update-16-8-0-add-ignored-files migration', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
tree.write('.eslintrc.json', '{}');
});
it('should run successfully when eslint config is not present', async () => {
addProjectConfiguration(tree, 'my-pkg', {
root: 'packages/my-pkg',
sourceRoot: 'packages/my-pkg/src',
projectType: 'library',
targets: {
build: {
executor: '@nx/vite:build',
options: {},
},
},
});
expect(() => update(tree)).not.toThrow();
});
it.each`
executor | expectedPattern
${'@nx/vite:build'} | ${'{projectRoot}/vite.config.{js,ts,mjs,mts}'}
${'@nx/vite:test'} | ${'{projectRoot}/vite.config.{js,ts,mjs,mts}'}
${'@nx/esbuild:esbuild'} | ${'{projectRoot}/esbuild.config.{js,ts,mjs,mts}'}
${'@nx/rollup:rollup'} | ${'{projectRoot}/rollup.config.{js,ts,mjs,mts}'}
`(
'should add ignoredFiles to projects using vite, esbuild, and rollup',
async ({ executor, expectedPattern }) => {
addProjectConfiguration(tree, 'my-pkg', {
root: 'packages/my-pkg',
sourceRoot: 'packages/my-pkg/src',
projectType: 'library',
targets: {
build: {
executor,
options: {},
},
},
});
writeJson(tree, `packages/my-pkg/.eslintrc.json`, {
root: true,
ignorePatterns: ['!**/*'],
plugins: ['@nx'],
overrides: [
{
files: ['*.json'],
parser: 'jsonc-eslint-parser',
rules: {
'@nx/dependency-checks': 'error',
},
},
],
});
update(tree);
expect(readJson(tree, 'packages/my-pkg/.eslintrc.json')).toEqual({
root: true,
ignorePatterns: ['!**/*'],
plugins: ['@nx'],
overrides: [
{
files: ['*.json'],
parser: 'jsonc-eslint-parser',
rules: {
'@nx/dependency-checks': [
'error',
{
ignoredFiles: [expectedPattern],
},
],
},
},
],
});
}
);
it('should retain existing severity', () => {
addProjectConfiguration(tree, 'my-pkg', {
root: 'packages/my-pkg',
sourceRoot: 'packages/my-pkg/src',
projectType: 'library',
targets: {
build: {
executor: '@nx/vite:build',
options: {},
},
},
});
writeJson(tree, `packages/my-pkg/.eslintrc.json`, {
root: true,
ignorePatterns: ['!**/*'],
plugins: ['@nx'],
overrides: [
{
files: ['*.json'],
parser: 'jsonc-eslint-parser',
rules: {
'@nx/dependency-checks': 'warn',
},
},
],
});
update(tree);
expect(readJson(tree, 'packages/my-pkg/.eslintrc.json')).toEqual({
root: true,
ignorePatterns: ['!**/*'],
plugins: ['@nx'],
overrides: [
{
files: ['*.json'],
parser: 'jsonc-eslint-parser',
rules: {
'@nx/dependency-checks': [
'warn',
{
ignoredFiles: ['{projectRoot}/vite.config.{js,ts,mjs,mts}'],
},
],
},
},
],
});
});
it('should retain existing options', () => {
addProjectConfiguration(tree, 'my-pkg', {
root: 'packages/my-pkg',
sourceRoot: 'packages/my-pkg/src',
projectType: 'library',
targets: {
build: {
executor: '@nx/vite:build',
options: {},
},
},
});
writeJson(tree, `packages/my-pkg/.eslintrc.json`, {
root: true,
ignorePatterns: ['!**/*'],
plugins: ['@nx'],
overrides: [
{
files: ['*.json'],
parser: 'jsonc-eslint-parser',
rules: {
'@nx/dependency-checks': [
'error',
{
checkVersionMismatches: false,
},
],
},
},
],
});
update(tree);
expect(readJson(tree, 'packages/my-pkg/.eslintrc.json')).toEqual({
root: true,
ignorePatterns: ['!**/*'],
plugins: ['@nx'],
overrides: [
{
files: ['*.json'],
parser: 'jsonc-eslint-parser',
rules: {
'@nx/dependency-checks': [
'error',
{
checkVersionMismatches: false,
ignoredFiles: ['{projectRoot}/vite.config.{js,ts,mjs,mts}'],
},
],
},
},
],
});
});
});

View File

@ -1,80 +0,0 @@
import { getProjects, Tree } from '@nx/devkit';
import { forEachExecutorOptions } from '@nx/devkit/src/generators/executor-options-utils';
import {
findEslintFile,
isEslintConfigSupported,
lintConfigHasOverride,
updateOverrideInLintConfig,
} from '../../generators/utils/eslint-file';
// Add `ignoredFiles` pattern to projects using vite, esbuild, and rollup.
// This is needed because the @nx/dependency-checks lint rule will complain
// about dependencies used in build config files, even though they are not
// production dependencies.
export default function update(tree: Tree) {
const projects = getProjects(tree);
const addIgnorePattern =
(ignorePattern: string) => (_options: unknown, projectName: string) => {
const project = projects.get(projectName);
if (
!findEslintFile(tree, project.root) ||
!isEslintConfigSupported(tree)
) {
return;
}
if (
lintConfigHasOverride(
tree,
project.root,
(o) =>
Array.isArray(o.files)
? o.files.some((f) => f.match(/\.json$/))
: !!o.files?.match(/\.json$/),
true
)
) {
updateOverrideInLintConfig(
tree,
project.root,
(o) => !!o.rules?.['@nx/dependency-checks'],
(o) => {
const value = o.rules['@nx/dependency-checks'];
let ruleSeverity: 0 | 1 | 2 | 'error' | 'warn' | 'off';
let ruleOptions: any;
if (Array.isArray(value)) {
ruleSeverity = value[0];
ruleOptions = value[1];
} else {
ruleSeverity = value;
ruleOptions = {};
}
ruleOptions.ignoredFiles = [ignorePattern];
o.rules['@nx/dependency-checks'] = [ruleSeverity, ruleOptions];
return o;
}
);
}
};
forEachExecutorOptions(
tree,
'@nx/vite:build',
addIgnorePattern('{projectRoot}/vite.config.{js,ts,mjs,mts}')
);
forEachExecutorOptions(
tree,
'@nx/vite:test',
addIgnorePattern('{projectRoot}/vite.config.{js,ts,mjs,mts}')
);
forEachExecutorOptions(
tree,
'@nx/esbuild:esbuild',
addIgnorePattern('{projectRoot}/esbuild.config.{js,ts,mjs,mts}')
);
forEachExecutorOptions(
tree,
'@nx/rollup:rollup',
addIgnorePattern('{projectRoot}/rollup.config.{js,ts,mjs,mts}')
);
}

View File

@ -1,47 +1,5 @@
{
"generators": {
"remove-deprecated-expo-targets": {
"version": "16.0.0-beta.0",
"cli": "nx",
"description": "Remove deprecated expo targets",
"factory": "./src/migrations/update-16-0-0/remove-deprecated-targets"
},
"update-16-0-0-add-nx-packages": {
"cli": "nx",
"version": "16.0.0-beta.1",
"description": "Replace @nrwl/expo with @nx/expo",
"implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages"
},
"update-eas-scripts-16-1-4": {
"cli": "nx",
"version": "16.1.4-beta.0",
"description": "Update package.json eas build lifecycle scripts",
"implementation": "./src/migrations/update-16-1-4/update-eas-scripts"
},
"update-16-6-0-add-dependsOn": {
"cli": "nx",
"version": "16.6.0-beta.0",
"description": "Add dependsOn like ensure-symlink or sync-deps to targets",
"implementation": "./src/migrations/update-16-6-0/add-depends-on"
},
"update-16-6-0-update-metro-config": {
"cli": "nx",
"version": "16.6.0-beta.0",
"description": "Update metro.config.js to use the new metro config format",
"implementation": "./src/migrations/update-16-6-0/update-metro-config"
},
"update-16-9-0-remove-types-react-native": {
"cli": "nx",
"version": "16.9.0-beta.1",
"description": "Remove @types/react-native from package.json",
"implementation": "./src/migrations/update-16-9-0/remove-types-react-native"
},
"update-16-9-0-update-eas-json-cli-version": {
"cli": "nx",
"version": "16.9.0-beta.1",
"description": "Update eas.json cli version",
"implementation": "./src/migrations/update-16-9-0/update-eas-cli-version"
},
"update-18-0-0-remove-block-list": {
"cli": "nx",
"version": "18.0.0-beta.0",
@ -86,226 +44,6 @@
}
},
"packageJsonUpdates": {
"16.0.0": {
"version": "16.0.0-beta.0",
"packages": {
"expo": {
"version": "48.0.11",
"alwaysAddToPackageJson": false
},
"react-native": {
"version": "0.71.6",
"alwaysAddToPackageJson": false
},
"@types/react-native": {
"version": "0.71.6",
"alwaysAddToPackageJson": false
},
"eas-cli": {
"version": "~3.10.0",
"alwaysAddToPackageJson": false
},
"@expo/cli": {
"version": "~0.7.0",
"alwaysAddToPackageJson": false
},
"@testing-library/react-native": {
"version": "12.0.1",
"alwaysAddToPackageJson": false
},
"jest-expo": {
"version": "~48.0.2",
"alwaysAddToPackageJson": false,
"addToPackageJson": "devDependencies"
}
}
},
"16.0.2": {
"version": "16.0.2-beta.0",
"packages": {
"expo": {
"version": "48.0.15",
"alwaysAddToPackageJson": false
},
"react-native": {
"version": "0.71.7",
"alwaysAddToPackageJson": false
},
"eas-cli": {
"version": "~3.10.2",
"alwaysAddToPackageJson": false
},
"@expo/cli": {
"version": "~0.7.1",
"alwaysAddToPackageJson": false
},
"expo-splash-screen": {
"version": "~0.18.2",
"alwaysAddToPackageJson": false
}
}
},
"16.1.5": {
"version": "16.1.5-beta.0",
"packages": {
"expo": {
"version": "^48.0.16",
"alwaysAddToPackageJson": false
},
"eas-cli": {
"version": "~3.12.0",
"alwaysAddToPackageJson": false
},
"@testing-library/react-native": {
"version": "12.1.2",
"alwaysAddToPackageJson": false
}
}
},
"16.2.2": {
"version": "16.2.2-beta.0",
"packages": {
"expo": {
"version": "^48.0.17",
"alwaysAddToPackageJson": false
},
"eas-cli": {
"version": "~3.13.2",
"alwaysAddToPackageJson": false
},
"react-native": {
"version": "0.71.8",
"alwaysAddToPackageJson": false
},
"@types/react-native": {
"version": "0.71.7",
"alwaysAddToPackageJson": false
}
}
},
"16.4.0": {
"version": "16.4.0-beta.5",
"packages": {
"expo": {
"version": "^48.0.19",
"alwaysAddToPackageJson": false
},
"eas-cli": {
"version": "~3.13.3",
"alwaysAddToPackageJson": false
},
"@expo/cli": {
"version": "~0.7.3",
"alwaysAddToPackageJson": false
}
}
},
"16.6.0": {
"version": "16.6.0-beta.0",
"packages": {
"expo": {
"version": "^49.0.3",
"alwaysAddToPackageJson": false
},
"@expo/metro-config": {
"version": "~0.10.6",
"alwaysAddToPackageJson": false
},
"expo-splash-screen": {
"version": "~0.20.4",
"alwaysAddToPackageJson": false
},
"expo-status-bar": {
"version": "~1.6.0",
"alwaysAddToPackageJson": false
},
"@expo/cli": {
"version": "~0.10.10",
"alwaysAddToPackageJson": false
},
"eas-cli": {
"version": "~3.15.0",
"alwaysAddToPackageJson": false
},
"babel-preset-expo": {
"version": "~9.5.0",
"alwaysAddToPackageJson": false
},
"jest-expo": {
"version": "~49.0.0",
"alwaysAddToPackageJson": false
},
"metro-resolver": {
"version": "0.76.7",
"alwaysAddToPackageJson": false
},
"metro": {
"version": "0.76.7",
"alwaysAddToPackageJson": false
},
"react-native": {
"version": "0.72.3",
"alwaysAddToPackageJson": false
},
"@types/react-native": {
"version": "0.72.2",
"alwaysAddToPackageJson": false
},
"react-native-web": {
"version": "~0.19.6",
"alwaysAddToPackageJson": false
},
"react-native-svg": {
"version": "13.9.0",
"alwaysAddToPackageJson": false
}
}
},
"16.9.0": {
"version": "16.9.0-beta.1",
"packages": {
"expo": {
"version": "49.0.10",
"alwaysAddToPackageJson": false
},
"@expo/metro-config": {
"version": "~0.10.7",
"alwaysAddToPackageJson": false
},
"expo-splash-screen": {
"version": "~0.20.5",
"alwaysAddToPackageJson": false
},
"@expo/cli": {
"version": "~0.10.12",
"alwaysAddToPackageJson": false
},
"eas-cli": {
"version": "~5.2.0",
"alwaysAddToPackageJson": false
},
"babel-preset-expo": {
"version": "~9.5.2",
"alwaysAddToPackageJson": false
},
"react-native": {
"version": "0.72.4",
"alwaysAddToPackageJson": false
},
"react-native-web": {
"version": "~0.19.8",
"alwaysAddToPackageJson": false
},
"@testing-library/react-native": {
"version": "~12.3.0",
"alwaysAddToPackageJson": false
},
"@testing-library/jest-native": {
"version": "~5.4.3",
"alwaysAddToPackageJson": false
}
}
},
"17.1.0": {
"version": "17.1.0-beta.0",
"packages": {

View File

@ -1,37 +0,0 @@
import { Tree, readJson, updateJson } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import replacePackage from './update-16-0-0-add-nx-packages';
describe('update-16-0-0-add-nx-packages', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
updateJson(tree, 'package.json', (json) => {
json.devDependencies['@nrwl/expo'] = '16.0.0';
return json;
});
});
it('should remove the dependency on @nrwl/expo', async () => {
await replacePackage(tree);
expect(
readJson(tree, 'package.json').dependencies['@nrwl/expo']
).not.toBeDefined();
expect(
readJson(tree, 'package.json').devDependencies['@nrwl/expo']
).not.toBeDefined();
});
it('should add a dependency on @nx/expo', async () => {
await replacePackage(tree);
const packageJson = readJson(tree, 'package.json');
const newDependencyVersion =
packageJson.devDependencies['@nx/expo'] ??
packageJson.dependencies['@nx/expo'];
expect(newDependencyVersion).toBeDefined();
});
});

View File

@ -1,8 +0,0 @@
import { Tree, formatFiles } from '@nx/devkit';
import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package';
export default async function replacePackage(tree: Tree): Promise<void> {
await replaceNrwlPackageWithNxPackage(tree, '@nrwl/expo', '@nx/expo');
await formatFiles(tree);
}

View File

@ -1,39 +0,0 @@
import {
Tree,
formatFiles,
getProjects,
updateProjectConfiguration,
} from '@nx/devkit';
/**
* Remove deprecated @expo/cli targets
*/
export default async function update(tree: Tree) {
const projects = getProjects(tree);
for (const [name, config] of projects.entries()) {
if (
config.targets?.['start']?.executor === '@nrwl/expo:start' ||
config.targets?.['start']?.executor === '@nx/expo:start'
) {
const targetsToDelete = [
'build-ios',
'build-android',
'build-web',
'build-status',
'publish',
'publish-set',
'rollback',
'eject',
];
targetsToDelete.forEach((target) => {
if (config.targets[target]) {
delete config.targets[target];
}
});
updateProjectConfiguration(tree, name, config);
}
}
await formatFiles(tree);
}

View File

@ -1,51 +0,0 @@
import {
Tree,
addProjectConfiguration,
readJson,
updateJson,
} from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import update from './update-eas-scripts';
describe('update-eas-scripts', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
addProjectConfiguration(tree, 'products', {
root: 'apps/products',
sourceRoot: 'apps/products/src',
targets: {
start: {
executor: '@nrwl/expo:start',
},
},
});
tree.write('apps/products/package.json', JSON.stringify({}));
});
it('should add scripts', async () => {
update(tree);
expect(
tree.exists('tools/scripts/eas-build-post-install.mjs')
).toBeTruthy();
const packageJson = readJson(tree, 'apps/products/package.json');
expect(packageJson.scripts['eas-build-post-install']).toEqual(
'cd ../../ && node tools/scripts/eas-build-post-install.mjs . apps/products'
);
});
it('should remove postinstall script', async () => {
updateJson(tree, 'apps/products/package.json', (json) => {
json.scripts = {
postinstall: 'some script',
};
return json;
});
update(tree);
const packageJson = readJson(tree, 'apps/products/package.json');
expect(packageJson.scripts['postinstall']).toBeUndefined();
});
});

View File

@ -1,40 +0,0 @@
import {
Tree,
getProjects,
logger,
offsetFromRoot,
updateJson,
} from '@nx/devkit';
import { addEasScripts } from '../../generators/application/lib/add-eas-scripts';
import { join } from 'path';
/**
* Update app's package.json to use eas-build-post-install scripts.
*/
export default function update(tree: Tree) {
const projects = getProjects(tree);
for (const [name, config] of projects.entries()) {
if (
config.targets?.['start']?.executor === '@nrwl/expo:start' ||
config.targets?.['start']?.executor === '@nx/expo:start'
) {
try {
addEasScripts(tree);
updateJson(tree, join(config.root, 'package.json'), (packageJson) => {
if (packageJson.scripts?.['postinstall']) {
delete packageJson.scripts['postinstall'];
}
const offset = offsetFromRoot(config.root);
packageJson.scripts = {
...packageJson.scripts,
'eas-build-post-install': `cd ${offset} && node tools/scripts/eas-build-post-install.mjs . ${config.root}`,
};
return packageJson;
});
} catch {
logger.error(`Unable to update package.json for project ${name}.`);
}
}
}
}

View File

@ -1,29 +0,0 @@
import { Tree, getProjects, updateProjectConfiguration } from '@nx/devkit';
/**
* This migration adds dependsOn to project.json.
*
*/
export default async function update(tree: Tree) {
const projects = getProjects(tree);
for (const [name, config] of projects.entries()) {
if (config.targets?.['start']?.executor === '@nx/expo:start') {
config.targets['start'].dependsOn = ['ensure-symlink', 'sync-deps'];
}
if (config.targets?.['run-ios']?.executor === '@nx/expo:run') {
config.targets['run-ios'].dependsOn = ['ensure-symlink', 'sync-deps'];
}
if (config.targets?.['run-android']?.executor === '@nx/expo:run') {
config.targets['run-android'].dependsOn = ['ensure-symlink', 'sync-deps'];
}
if (config.targets?.['prebuild']?.executor === '@nx/expo:prebuild') {
config.targets['prebuild'].dependsOn = ['ensure-symlink', 'sync-deps'];
}
if (config.targets?.['export']?.executor === '@nx/expo:export') {
config.targets['export'].dependsOn = ['ensure-symlink', 'sync-deps'];
}
updateProjectConfiguration(tree, name, config);
}
}

View File

@ -1,69 +0,0 @@
import { Tree, getProjects } from '@nx/devkit';
import { join } from 'path';
/**
* This migration updates metro.config.js to export config as a default.
*
*/
export default async function update(tree: Tree) {
const projects = getProjects(tree);
for (const [_, config] of projects.entries()) {
if (config.targets?.['start']?.executor === '@nx/expo:start') {
if (tree.exists(join(config.root, 'metro.config.js'))) {
const oldConfig = tree
.read(join(config.root, 'metro.config.js'))
.toString();
tree.write(
join(config.root, 'metro-v71.config.js'),
oldConfigComment + oldConfig
);
tree.write(join(config.root, 'metro.config.js'), content);
}
}
}
}
const oldConfigComment = `/**
* Old custom configuration for React Native v0.71.
* From @react-native/metro-config 0.72.1, it is no longer necessary to use a config function to access the complete default config.
* Please port your custom configuration to metro.config.js.
* Please see https://docs.expo.dev/guides/customizing-metro/ to learn about configuration.
*/
`;
const content = `
const { withNxMetro } = require('@nx/expo');
const { getDefaultConfig } = require('@expo/metro-config');
const { mergeConfig } = require('metro-config');
const defaultConfig = getDefaultConfig(__dirname);
const { assetExts, sourceExts } = defaultConfig.resolver;
/**
* Metro configuration
* https://facebook.github.io/metro/docs/configuration
*
* @type {import('metro-config').MetroConfig}
*/
const customConfig = {
transformer: {
babelTransformerPath: require.resolve('react-native-svg-transformer'),
},
resolver: {
assetExts: assetExts.filter((ext) => ext !== 'svg'),
sourceExts: [...sourceExts, 'cjs', 'mjs', 'svg'],
},
};
module.exports = withNxMetro(mergeConfig(defaultConfig, customConfig), {
// Change this to true to see debugging info.
// Useful if you have issues resolving modules
debug: false,
// all the file extensions used for imports other than 'ts', 'tsx', 'js', 'jsx', 'json'
extensions: [],
// Specify folders to watch, in addition to Nx defaults (workspace libraries and node_modules)
watchFolders: [],
});
`;

View File

@ -1,15 +0,0 @@
import {
formatFiles,
removeDependenciesFromPackageJson,
Tree,
} from '@nx/devkit';
/**
* Remove @types/react-native package since it is no longer required. It would be a part of react native package.
* @param tree
* @returns
*/
export default async function update(tree: Tree) {
removeDependenciesFromPackageJson(tree, [], ['@types/react-native']);
await formatFiles(tree);
}

View File

@ -1,28 +0,0 @@
import { addProjectConfiguration, getProjects, Tree } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import update from './update-eas-cli-version';
describe('update-eas-cli-version', () => {
let tree: Tree;
beforeEach(async () => {
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
addProjectConfiguration(tree, 'product', {
root: 'apps/product',
sourceRoot: 'apps/product/src',
targets: {
start: {
executor: '@nx/expo:start',
},
},
});
tree.write('apps/product/eas.json', '{"cli":{"version": "1.2.3"}}');
});
it(`should update eas.json with greater than version`, async () => {
await update(tree);
const easJson = JSON.parse(tree.read('apps/product/eas.json').toString());
expect(easJson.cli.version).toContain('>=');
});
});

View File

@ -1,16 +0,0 @@
import { Tree, getProjects, updateJson } from '@nx/devkit';
export default async function update(tree: Tree) {
const projects = getProjects(tree);
for (const [name, config] of projects.entries()) {
if (config.targets?.['start']?.executor === '@nx/expo:start') {
updateJson(tree, `${config.root}/eas.json`, (easJson) => {
if (easJson?.cli?.version) {
easJson.cli.version = `>= 5`;
}
return easJson;
});
}
}
}

View File

@ -1,11 +1,4 @@
{
"generators": {
"update-16-0-0-add-nx-packages": {
"cli": "nx",
"version": "16.0.0-beta.1",
"description": "Replace @nrwl/express with @nx/express",
"implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages"
}
},
"generators": {},
"packageJsonUpdates": {}
}

View File

@ -1,37 +0,0 @@
import { Tree, readJson, updateJson } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import replacePackage from './update-16-0-0-add-nx-packages';
describe('update-16-0-0-add-nx-packages', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
updateJson(tree, 'package.json', (json) => {
json.devDependencies['@nrwl/express'] = '16.0.0';
return json;
});
});
it('should remove the dependency on @nrwl/express', async () => {
await replacePackage(tree);
expect(
readJson(tree, 'package.json').dependencies['@nrwl/express']
).not.toBeDefined();
expect(
readJson(tree, 'package.json').devDependencies['@nrwl/express']
).not.toBeDefined();
});
it('should add a dependency on @nx/express', async () => {
await replacePackage(tree);
const packageJson = readJson(tree, 'package.json');
const newDependencyVersion =
packageJson.devDependencies['@nx/express'] ??
packageJson.dependencies['@nx/express'];
expect(newDependencyVersion).toBeDefined();
});
});

View File

@ -1,8 +0,0 @@
import { Tree, formatFiles } from '@nx/devkit';
import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package';
export default async function replacePackage(tree: Tree): Promise<void> {
await replaceNrwlPackageWithNxPackage(tree, '@nrwl/express', '@nx/express');
await formatFiles(tree);
}

View File

@ -1,17 +1,5 @@
{
"generators": {
"update-16-0-0-add-nx-packages": {
"cli": "nx",
"version": "16.0.0-beta.1",
"description": "Replace @nrwl/jest with @nx/jest",
"implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages"
},
"add-test-setup-to-inputs-ignore": {
"cli": "nx",
"version": "16.5.0-beta.2",
"description": "Add test-setup.ts to ignored files in production input",
"implementation": "./src/migrations/update-16-5-0/add-test-setup-to-inputs-ignore"
},
"move-options-to-target-defaults": {
"version": "17.1.0-beta.2",
"description": "Move jest executor options to nx.json targetDefaults",
@ -19,15 +7,6 @@
}
},
"packageJsonUpdates": {
"16.0.0": {
"version": "16.0.0-beta.4",
"packages": {
"ts-jest": {
"version": "~29.1.0",
"alwaysAddToPackageJson": false
}
}
},
"17.2.0": {
"version": "17.2.0-beta.2",
"packages": {

View File

@ -1,37 +0,0 @@
import { Tree, readJson, updateJson } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import replacePackage from './update-16-0-0-add-nx-packages';
describe('update-16-0-0-add-nx-packages', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
updateJson(tree, 'package.json', (json) => {
json.devDependencies['@nrwl/jest'] = '16.0.0';
return json;
});
});
it('should remove the dependency on @nrwl/jest', async () => {
await replacePackage(tree);
expect(
readJson(tree, 'package.json').dependencies['@nrwl/jest']
).not.toBeDefined();
expect(
readJson(tree, 'package.json').devDependencies['@nrwl/jest']
).not.toBeDefined();
});
it('should add a dependency on @nx/jest', async () => {
await replacePackage(tree);
const packageJson = readJson(tree, 'package.json');
const newDependencyVersion =
packageJson.devDependencies['@nx/jest'] ??
packageJson.dependencies['@nx/jest'];
expect(newDependencyVersion).toBeDefined();
});
});

View File

@ -1,8 +0,0 @@
import { Tree, formatFiles } from '@nx/devkit';
import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package';
export default async function replacePackage(tree: Tree): Promise<void> {
await replaceNrwlPackageWithNxPackage(tree, '@nrwl/jest', '@nx/jest');
await formatFiles(tree);
}

View File

@ -1,51 +0,0 @@
import { Tree, readNxJson, updateNxJson } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import addTestSetupToIgnoredInputs from './add-test-setup-to-inputs-ignore';
describe('Jest Migration - jest 29 mocked usage in tests', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
});
it('should add inputs configuration for test-setup if missing', async () => {
updateNxJson(tree, {
namedInputs: {
default: ['{projectRoot}/**/*', 'sharedGlobals'],
sharedGlobals: [],
production: ['default'],
},
});
await addTestSetupToIgnoredInputs(tree);
const updated = readNxJson(tree);
expect(updated.namedInputs.production).toMatchInlineSnapshot(`
[
"default",
"!{projectRoot}/src/test-setup.[jt]s",
]
`);
});
it('should not add inputs configuration for test-setup if existing', async () => {
updateNxJson(tree, {
namedInputs: {
default: ['{projectRoot}/**/*', 'sharedGlobals'],
sharedGlobals: [],
production: ['!{projectRoot}/src/test-setup.[jt]s', 'default'],
},
});
await addTestSetupToIgnoredInputs(tree);
const updated = readNxJson(tree);
expect(updated.namedInputs.production).toMatchInlineSnapshot(`
[
"!{projectRoot}/src/test-setup.[jt]s",
"default",
]
`);
});
});

View File

@ -1,28 +0,0 @@
import {
NxJsonConfiguration,
Tree,
formatFiles,
readNxJson,
updateNxJson,
} from '@nx/devkit';
export async function addTestSetupToIgnoredInputs(tree: Tree) {
const nxJson: NxJsonConfiguration = readNxJson(tree);
if (!nxJson) {
return;
}
if (
nxJson.namedInputs?.production &&
!nxJson.namedInputs.production.includes(
'!{projectRoot}/src/test-setup.[jt]s'
)
) {
nxJson.namedInputs.production.push('!{projectRoot}/src/test-setup.[jt]s');
updateNxJson(tree, nxJson);
}
await formatFiles(tree);
}
export default addTestSetupToIgnoredInputs;

View File

@ -1,23 +1,5 @@
{
"generators": {
"update-16-0-0-add-nx-packages": {
"cli": "nx",
"version": "16.0.0-beta.1",
"description": "Replace @nrwl/js with @nx/js",
"implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages"
},
"explicitly-set-projects-to-update-buildable-deps": {
"cli": "nx",
"version": "16.6.0-beta.0",
"description": "Explicitly set 'updateBuildableProjectDepsInPackageJson' to 'true' in targets that rely on that value as the default.",
"factory": "./src/migrations/update-16-6-0/explicitly-set-projects-to-update-buildable-deps"
},
"16-8-2-update-swcrc": {
"cli": "nx",
"version": "16.8.2-beta.0",
"description": "Remove invalid options (strict, noInterop) for ES6 type modules.",
"factory": "./src/migrations/update-16-8-2/update-swcrc"
},
"update-17-0-0-remove-deprecated-build-options": {
"cli": "nx",
"version": "17.0.2",
@ -26,65 +8,6 @@
}
},
"packageJsonUpdates": {
"16.0.0": {
"version": "16.0.0-beta.3",
"packages": {
"@swc/cli": {
"version": "~0.1.62",
"alwaysAddToPackageJson": false
},
"@swc/helpers": {
"version": "~0.5.0",
"alwaysAddToPackageJson": false
}
}
},
"16.1.0": {
"version": "16.1.0-beta.0",
"x-prompt": "Do you want to update to TypeScript v5.0?",
"requires": {
"typescript": ">=4.9.5 <5.0.0"
},
"packages": {
"typescript": {
"version": "~5.0.2"
}
}
},
"16.4.0": {
"version": "16.4.0-beta.11",
"x-prompt": "Do you want to update to TypeScript v5.1?",
"requires": {
"typescript": ">=5.0.0 <5.1.0"
},
"packages": {
"typescript": {
"version": "~5.1.3"
}
}
},
"16.8.2": {
"version": "16.8.2-beta.0",
"packages": {
"@swc/core": {
"version": "~1.3.85",
"alwaysAddToPackageJson": false
},
"@swc/helpers": {
"version": "~0.5.2",
"alwaysAddToPackageJson": false
}
}
},
"16.9.2": {
"version": "16.9.2-beta.0",
"packages": {
"@swc-node/register": {
"version": "~1.6.7",
"alwaysAddToPackageJson": false
}
}
},
"17.0.0": {
"version": "17.0.0-rc.2",
"packages": {

View File

@ -1,37 +0,0 @@
import { Tree, readJson, updateJson } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import replacePackage from './update-16-0-0-add-nx-packages';
describe('update-16-0-0-add-nx-packages', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
updateJson(tree, 'package.json', (json) => {
json.devDependencies['@nrwl/js'] = '16.0.0';
return json;
});
});
it('should remove the dependency on @nrwl/js', async () => {
await replacePackage(tree);
expect(
readJson(tree, 'package.json').dependencies['@nrwl/js']
).not.toBeDefined();
expect(
readJson(tree, 'package.json').devDependencies['@nrwl/js']
).not.toBeDefined();
});
it('should add a dependency on @nx/js', async () => {
await replacePackage(tree);
const packageJson = readJson(tree, 'package.json');
const newDependencyVersion =
packageJson.devDependencies['@nx/js'] ??
packageJson.dependencies['@nx/js'];
expect(newDependencyVersion).toBeDefined();
});
});

View File

@ -1,8 +0,0 @@
import { Tree, formatFiles } from '@nx/devkit';
import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package';
export default async function replacePackage(tree: Tree): Promise<void> {
await replaceNrwlPackageWithNxPackage(tree, '@nrwl/js', '@nx/js');
await formatFiles(tree);
}

View File

@ -1,119 +0,0 @@
import {
ProjectConfiguration,
ProjectGraph,
Tree,
addProjectConfiguration,
readProjectConfiguration,
} from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import migration from './explicitly-set-projects-to-update-buildable-deps';
let projectGraph: ProjectGraph;
jest.mock('@nx/devkit', () => ({
...jest.requireActual('@nx/devkit'),
createProjectGraphAsync: () => Promise.resolve(projectGraph),
}));
describe('explicitly-set-projects-to-update-buildable-deps migration', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
});
it.each(['@nx/js:swc', '@nrwl/js:swc', '@nx/js:tsc', '@nrwl/js:tsc'])(
'should set updateBuildableProjectDepsInPackageJson option to "true" when not specified in target using "%s"',
async (executor) => {
addProject(tree, 'lib1', {
root: 'lib1',
projectType: 'library',
targets: { build: { executor, options: {} } },
});
await migration(tree);
const project = readProjectConfiguration(tree, 'lib1');
expect(
project.targets.build.options.updateBuildableProjectDepsInPackageJson
).toBe(true);
}
);
it.each(['@nx/js:swc', '@nrwl/js:swc', '@nx/js:tsc', '@nrwl/js:tsc'])(
'should set updateBuildableProjectDepsInPackageJson option to "true" when target has no options object defined using "%s"',
async (executor) => {
addProject(tree, 'lib1', {
root: 'lib1',
projectType: 'library',
targets: { build: { executor } },
});
await migration(tree);
const project = readProjectConfiguration(tree, 'lib1');
expect(
project.targets.build.options.updateBuildableProjectDepsInPackageJson
).toBe(true);
}
);
it.each(['@nx/js:swc', '@nrwl/js:swc', '@nx/js:tsc', '@nrwl/js:tsc'])(
'should not overwrite updateBuildableProjectDepsInPackageJson option when it is specified in target using "%s"',
async (executor) => {
addProject(tree, 'lib1', {
root: 'lib1',
projectType: 'library',
targets: {
build: {
executor,
options: { updateBuildableProjectDepsInPackageJson: false },
},
},
});
await migration(tree);
const project = readProjectConfiguration(tree, 'lib1');
expect(
project.targets.build.options.updateBuildableProjectDepsInPackageJson
).toBe(false);
}
);
it('should not update targets using other executors', async () => {
const originalProjectConfig: ProjectConfiguration = {
root: 'lib1',
projectType: 'library',
targets: {
build: {
executor: 'some-executor',
options: {},
},
},
};
addProject(tree, 'lib1', originalProjectConfig);
await migration(tree);
const project = readProjectConfiguration(tree, 'lib1');
expect(project.targets).toStrictEqual(originalProjectConfig.targets);
});
});
function addProject(
tree: Tree,
projectName: string,
config: ProjectConfiguration
): void {
projectGraph = {
dependencies: {},
nodes: {
[projectName]: {
data: config,
name: projectName,
type: config.projectType === 'application' ? 'app' : 'lib',
},
},
};
addProjectConfiguration(tree, projectName, config);
}

View File

@ -1,51 +0,0 @@
import {
createProjectGraphAsync,
formatFiles,
readProjectConfiguration,
Tree,
updateProjectConfiguration,
} from '@nx/devkit';
const executors = new Set([
'@nx/js:swc',
'@nrwl/js:swc',
'@nx/js:tsc',
'@nrwl/js:tsc',
]);
export default async function (tree: Tree) {
// use project graph to get the expanded target configurations
const projectGraph = await createProjectGraphAsync();
for (const [projectName, { data: projectData }] of Object.entries(
projectGraph.nodes
)) {
if (projectData.projectType !== 'library') {
continue;
}
for (const [targetName, target] of Object.entries(
projectData.targets || {}
)) {
if (!executors.has(target.executor)) {
continue;
}
if (
!target.options ||
target.options.updateBuildableProjectDepsInPackageJson === undefined
) {
// read the project configuration to write the explicit project configuration
// and avoid writing the expanded target configuration
const project = readProjectConfiguration(tree, projectName);
project.targets[targetName].options ??= {};
project.targets[
targetName
].options.updateBuildableProjectDepsInPackageJson = true;
updateProjectConfiguration(tree, projectName, project);
}
}
}
await formatFiles(tree);
}

View File

@ -1,82 +0,0 @@
import { addProjectConfiguration, readJson, Tree, writeJson } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import update from './update-swcrc';
describe('Migration: update .swcrc', () => {
let tree: Tree;
beforeEach(async () => {
tree = createTreeWithEmptyWorkspace();
});
it('should remove invalid options for ES6 modules', async () => {
addProjectConfiguration(tree, 'pkg', {
root: 'pkg',
});
writeJson(tree, 'pkg/.swcrc', {
module: {
type: 'es6',
strict: true,
noInterop: true,
},
});
await update(tree);
expect(readJson(tree, 'pkg/.swcrc')).toEqual({
module: {
type: 'es6',
},
});
});
it('should keep options for CommonJS modules', async () => {
addProjectConfiguration(tree, 'pkg', {
root: 'pkg',
});
writeJson(tree, 'pkg/.swcrc', {
module: {
type: 'commonjs',
strict: true,
noInterop: true,
},
});
await update(tree);
expect(readJson(tree, 'pkg/.swcrc')).toEqual({
module: {
type: 'commonjs',
strict: true,
noInterop: true,
},
});
});
it('should ignore projects without module options in .swcrc', async () => {
addProjectConfiguration(tree, 'pkg', {
root: 'pkg',
});
writeJson(tree, 'pkg/.swcrc', {
jsc: {
target: 'es2017',
},
});
await expect(update(tree)).resolves.not.toThrow();
expect(readJson(tree, 'pkg/.swcrc')).toEqual({
jsc: {
target: 'es2017',
},
});
});
it('should ignore projects without .swcrc', async () => {
addProjectConfiguration(tree, 'pkg', {
root: 'pkg',
});
await expect(update(tree)).resolves.not.toThrow();
});
});

View File

@ -1,30 +0,0 @@
import {
formatFiles,
getProjects,
readJson,
Tree,
writeJson,
} from '@nx/devkit';
import { join } from 'path';
export default async function update(tree: Tree) {
const projects = getProjects(tree);
for (const config of projects.values()) {
const swcrcPath = join(config.root, '.swcrc');
if (!tree.exists(swcrcPath)) continue;
const json = readJson(tree, swcrcPath);
// No longer need strict or noInterop for es6 modules
// See: https://github.com/swc-project/swc/commit/7e8d72d
if (
json.module?.type === 'es6' &&
(json.module?.strict || json.module?.noInterop)
) {
delete json.module.noInterop;
delete json.module.strict;
writeJson(tree, swcrcPath, json);
}
}
await formatFiles(tree);
}

View File

@ -1,76 +1,4 @@
{
"generators": {
"update-16-0-0-add-nx-packages": {
"cli": "nx",
"version": "16.0.0-beta.1",
"description": "Replace @nrwl/nest with @nx/nest",
"implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages"
},
"update-16-4-0-support-nestjs-10": {
"cli": "nx",
"version": "16.4.0-beta.16",
"description": "Update TsConfig target to es2021 and CacheModule if being used. Read more at https://docs.nestjs.com/migration-guide",
"implementation": "./src/migrations/update-16-4-0-cache-manager/nestjs-10-updates"
}
},
"packageJsonUpdates": {
"16.1.0": {
"version": "16.1.0-beta.0",
"packages": {
"@nestjs/common": {
"version": "^9.1.1",
"alwaysAddToPackageJson": false
},
"@nestjs/core": {
"version": "^9.1.1",
"alwaysAddToPackageJson": false
},
"@nestjs/platform-express": {
"version": "^9.1.1",
"alwaysAddToPackageJson": false
},
"@nestjs/schematics": {
"version": "^9.1.0",
"alwaysAddToPackageJson": false
},
"@nestjs/swagger": {
"version": "^6.3.0",
"alwaysAddToPackageJson": false
},
"@nestjs/testing": {
"version": "^9.1.1",
"alwaysAddToPackageJson": false
}
}
},
"16.4.0": {
"version": "16.4.0-beta.11",
"packages": {
"@nestjs/common": {
"version": "^10.0.2",
"alwaysAddToPackageJson": false
},
"@nestjs/core": {
"version": "^10.0.2",
"alwaysAddToPackageJson": false
},
"@nestjs/platform-express": {
"version": "^10.0.2",
"alwaysAddToPackageJson": false
},
"@nestjs/schematics": {
"version": "^10.0.1",
"alwaysAddToPackageJson": false
},
"@nestjs/swagger": {
"version": "^7.0.2",
"alwaysAddToPackageJson": false
},
"@nestjs/testing": {
"version": "^10.0.2",
"alwaysAddToPackageJson": false
}
}
}
}
"generators": {},
"packageJsonUpdates": {}
}

View File

@ -36,7 +36,6 @@
"@nx/js": "file:../js",
"@nx/eslint": "file:../eslint",
"@nx/node": "file:../node",
"@phenomnomnominal/tsquery": "~5.0.1",
"tslib": "^2.3.0"
},
"publishConfig": {

View File

@ -1,37 +0,0 @@
import { Tree, readJson, updateJson } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import replacePackage from './update-16-0-0-add-nx-packages';
describe('update-16-0-0-add-nx-packages', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
updateJson(tree, 'package.json', (json) => {
json.devDependencies['@nrwl/nest'] = '16.0.0';
return json;
});
});
it('should remove the dependency on @nrwl/nest', async () => {
await replacePackage(tree);
expect(
readJson(tree, 'package.json').dependencies['@nrwl/nest']
).not.toBeDefined();
expect(
readJson(tree, 'package.json').devDependencies['@nrwl/nest']
).not.toBeDefined();
});
it('should add a dependency on @nx/nest', async () => {
await replacePackage(tree);
const packageJson = readJson(tree, 'package.json');
const newDependencyVersion =
packageJson.devDependencies['@nx/nest'] ??
packageJson.dependencies['@nx/nest'];
expect(newDependencyVersion).toBeDefined();
});
});

View File

@ -1,8 +0,0 @@
import { Tree, formatFiles } from '@nx/devkit';
import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package';
export default async function replacePackage(tree: Tree): Promise<void> {
await replaceNrwlPackageWithNxPackage(tree, '@nrwl/nest', '@nx/nest');
await formatFiles(tree);
}

View File

@ -1,134 +0,0 @@
import {
Tree,
addDependenciesToPackageJson,
createProjectGraphAsync,
formatFiles,
getProjects,
joinPathFragments,
updateJson,
visitNotIgnoredFiles,
} from '@nx/devkit';
import { tsquery } from '@phenomnomnominal/tsquery';
import {
ImportDeclaration,
VariableStatement,
ScriptTarget,
isVariableStatement,
} from 'typescript';
const JS_TS_FILE_MATCHER = /\.[jt]sx?$/;
const importMatch =
':matches(ImportDeclaration, VariableStatement):has(Identifier[name="CacheModule"], Identifier[name="CacheModule"]):has(StringLiteral[value="@nestjs/common"])';
export async function updateNestJs10(tree: Tree) {
const nestProjects = await getNestProejcts();
if (nestProjects.length === 0) {
return;
}
let installCacheModuleDeps = false;
const projects = getProjects(tree);
for (const projectName of nestProjects) {
const projectConfig = projects.get(projectName);
const tsConfig =
projectConfig.targets?.build?.options?.tsConfig ??
joinPathFragments(
projectConfig.root,
projectConfig.projectType === 'application'
? 'tsconfig.app.json'
: 'tsconfig.lib.json'
);
if (tree.exists(tsConfig)) {
updateTsConfigTarget(tree, tsConfig);
}
visitNotIgnoredFiles(tree, projectConfig.root, (filePath) => {
if (!JS_TS_FILE_MATCHER.test(filePath)) {
return;
}
installCacheModuleDeps =
updateCacheManagerImport(tree, filePath) || installCacheModuleDeps;
});
}
await formatFiles(tree);
return installCacheModuleDeps
? addDependenciesToPackageJson(
tree,
{
'@nestjs/cache-manager': '^2.0.0',
'cache-manager': '^5.2.3',
},
{}
)
: () => {};
}
async function getNestProejcts(): Promise<string[]> {
const projectGraph = await createProjectGraphAsync();
return Object.entries(projectGraph.dependencies)
.filter(([node, dep]) =>
dep.some(
({ target }) =>
!projectGraph.externalNodes?.[node] && target === 'npm:@nestjs/common'
)
)
.map(([projectName]) => projectName);
}
// change import { CacheModule } from '@nestjs/common';
// to import { CacheModule } from '@nestjs/cache-manager';
export function updateCacheManagerImport(
tree: Tree,
filePath: string
): boolean {
const content = tree.read(filePath, 'utf-8');
const updated = tsquery.replace(
content,
importMatch,
(node: ImportDeclaration | VariableStatement) => {
const text = node.getText();
return `${text.replace('CacheModule', '')}\n${
isVariableStatement(node)
? "const { CacheModule } = require('@nestjs/cache-manager')"
: "import { CacheModule } from '@nestjs/cache-manager';"
}`;
}
);
if (updated !== content) {
tree.write(filePath, updated);
return true;
}
}
export function updateTsConfigTarget(tree: Tree, tsConfigPath: string) {
updateJson(tree, tsConfigPath, (json) => {
if (!json.compilerOptions.target) {
return json;
}
const normalizedTargetName = json.compilerOptions.target.toUpperCase();
// es6 isn't apart of the ScriptTarget enum but is a valid tsconfig target in json file
const existingTarget =
normalizedTargetName === 'ES6'
? ScriptTarget.ES2015
: (ScriptTarget[normalizedTargetName] as unknown as ScriptTarget);
if (existingTarget < ScriptTarget.ES2021) {
json.compilerOptions.target = 'es2021';
}
return json;
});
}
export default updateNestJs10;

View File

@ -1,242 +0,0 @@
import {
ProjectConfiguration,
ProjectGraph,
Tree,
addProjectConfiguration,
readJson,
} from '@nx/devkit';
import {
updateNestJs10,
updateCacheManagerImport,
updateTsConfigTarget,
} from './nestjs-10-updates';
import { createTreeWithEmptyWorkspace } from 'nx/src/devkit-testing-exports';
let projectGraph: ProjectGraph;
jest.mock('@nx/devkit', () => ({
...jest.requireActual('@nx/devkit'),
createProjectGraphAsync: () => Promise.resolve(projectGraph),
}));
describe('nestjs 10 migration changes', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
jest.resetAllMocks();
});
it('should update nestjs project', async () => {
tree.write(
'apps/app1/main.ts',
`
/**
* This is not a production server yet!
* This is only a minimal backend to get started.
*/
import { Logger } from '@nestjs/common';
import { NestFactory } from '@nestjs/core';
import { CacheModule } from '@nestjs/common';
import { AppModule } from './app/app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const globalPrefix = 'api';
app.setGlobalPrefix(globalPrefix);
const port = process.env.PORT || 3000;
await app.listen(port);
Logger.log('🚀 Application is running on: http://localhost:' + port + '/' + globalPrefix);
}
bootstrap();
`
);
tree.write(
'apps/app1/tsconfig.app.json',
JSON.stringify({
extends: './tsconfig.json',
compilerOptions: {
outDir: '../../dist/out-tsc',
module: 'commonjs',
types: ['node'],
emitDecoratorMetadata: true,
target: 'es2015',
},
exclude: ['jest.config.ts', 'src/**/*.spec.ts', 'src/**/*.test.ts'],
include: ['src/**/*.ts'],
})
);
addProject(
tree,
'app1',
{
root: 'apps/app1',
targets: {
build: {
executor: '@nx/webpack:webpack',
options: {
tsConfig: 'apps/app1/tsconfig.app.json',
},
},
},
},
['npm:@nestjs/common']
);
await updateNestJs10(tree);
expect(readJson(tree, 'package.json').dependencies).toMatchInlineSnapshot(`
{
"@nestjs/cache-manager": "^2.0.0",
"cache-manager": "^5.2.3",
}
`);
expect(
readJson(tree, 'apps/app1/tsconfig.app.json').compilerOptions.target
).toEqual('es2021');
expect(tree.read('apps/app1/main.ts', 'utf-8')).toContain(
"import { CacheModule } from '@nestjs/cache-manager';"
);
});
it('should work with non buildable lib', async () => {
tree.write(
'libs/lib1/src/lib/lib1.module.ts',
`
import { Module, CacheModule } from '@nestjs/common';
@Module({
controllers: [],
providers: [],
exports: [],
imports: [CacheModule.register()],
})
export class LibOneModule {}
`
);
tree.write(
'libs/lib1/tsconfig.lib.json',
JSON.stringify({
extends: './tsconfig.json',
compilerOptions: {
outDir: '../../dist/out-tsc',
module: 'commonjs',
types: ['node'],
emitDecoratorMetadata: true,
target: 'es6',
},
exclude: ['jest.config.ts', 'src/**/*.spec.ts', 'src/**/*.test.ts'],
include: ['src/**/*.ts'],
})
);
addProject(
tree,
'app1',
{
root: 'libs/lib1',
targets: {},
},
['npm:@nestjs/common']
);
await updateNestJs10(tree);
expect(readJson(tree, 'package.json').dependencies).toMatchInlineSnapshot(`
{
"@nestjs/cache-manager": "^2.0.0",
"cache-manager": "^5.2.3",
}
`);
expect(
readJson(tree, 'libs/lib1/tsconfig.lib.json').compilerOptions.target
).toEqual('es2021');
expect(tree.read('libs/lib1/src/lib/lib1.module.ts', 'utf-8')).toContain(
"import { CacheModule } from '@nestjs/cache-manager';"
);
});
it('should update cache module import', () => {
tree.write(
'main.ts',
`
import { Module, CacheModule } from '@nestjs/common';
const { Module, CacheModule } = require('@nestjs/common');
`
);
const actual = updateCacheManagerImport(tree, 'main.ts');
expect(tree.read('main.ts', 'utf-8')).toMatchInlineSnapshot(`
"
import { Module, } from '@nestjs/common';
import { CacheModule } from '@nestjs/cache-manager';
const { Module, } = require('@nestjs/common');
const { CacheModule } = require('@nestjs/cache-manager')
"
`);
expect(actual).toBe(true);
});
it('should NOT update cache module imports', () => {
tree.write(
'main.ts',
`
import { AnotherModule } from '@nestjs/common';
const { AnotherModule } = require('@nestjs/common');
`
);
const actual = updateCacheManagerImport(tree, 'main.ts');
expect(tree.read('main.ts', 'utf-8')).toMatchInlineSnapshot(`
"
import { AnotherModule } from '@nestjs/common';
const { AnotherModule } = require('@nestjs/common');
"
`);
expect(actual).toBeUndefined();
});
it('should update script target', () => {
tree.write(
'tsconfig.json',
JSON.stringify({ compilerOptions: { target: 'es6' } })
);
updateTsConfigTarget(tree, 'tsconfig.json');
expect(readJson(tree, 'tsconfig.json').compilerOptions.target).toBe(
'es2021'
);
});
it('should NOT update script if over es2021', () => {
tree.write(
'tsconfig.json',
JSON.stringify({ compilerOptions: { target: 'es2022' } })
);
updateTsConfigTarget(tree, 'tsconfig.json');
expect(readJson(tree, 'tsconfig.json').compilerOptions.target).toBe(
'es2022'
);
});
});
function addProject(
tree: Tree,
projectName: string,
config: ProjectConfiguration,
dependencies: string[]
): void {
projectGraph = {
dependencies: {
[projectName]: dependencies.map((d) => ({
source: projectName,
target: d,
type: 'static',
})),
},
nodes: {
[projectName]: { data: config, name: projectName, type: 'app' },
},
};
addProjectConfiguration(tree, projectName, config);
}

View File

@ -1,23 +1,5 @@
{
"generators": {
"update-16-0-0-add-nx-packages": {
"cli": "nx",
"version": "16.0.0-beta.1",
"description": "Replace @nrwl/next with @nx/next",
"implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages"
},
"update-16-3-0-remove-root-build-option": {
"cli": "nx",
"version": "16.3.0-beta.9",
"description": "Remove root build option from project configurations since it is not needed.",
"implementation": "./src/migrations/update-16-3-0/remove-root-build-option"
},
"update-16-4-0-update-next-dependency": {
"cli": "nx",
"version": "16.4.0-beta.3",
"description": "Update package.json moving @nx/next from dependency to devDependency",
"implementation": "./src/migrations/update-16-4-0/update-nx-next-dependency"
},
"update-17-2-7": {
"cli": "nx",
"version": "17.2.7",
@ -26,24 +8,6 @@
}
},
"packageJsonUpdates": {
"16.0.0": {
"version": "16.0.0-beta.0",
"packages": {
"next": {
"version": "13.3.0",
"alwaysAddToPackageJson": false
}
}
},
"16.4.0-beta.4": {
"version": "16.4.0-beta.4",
"packages": {
"stylus": {
"version": "^0.59.0",
"alwaysAddToPackageJson": false
}
}
},
"17.3.1-beta.0": {
"version": "17.3.1-beta.0",
"packages": {

View File

@ -1,37 +0,0 @@
import { Tree, readJson, updateJson } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import replacePackage from './update-16-0-0-add-nx-packages';
describe('update-16-0-0-add-nx-packages', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
updateJson(tree, 'package.json', (json) => {
json.devDependencies['@nrwl/next'] = '16.0.0';
return json;
});
});
it('should remove the dependency on @nrwl/next', async () => {
await replacePackage(tree);
expect(
readJson(tree, 'package.json').dependencies['@nrwl/next']
).not.toBeDefined();
expect(
readJson(tree, 'package.json').devDependencies['@nrwl/next']
).not.toBeDefined();
});
it('should add a dependency on @nx/next', async () => {
await replacePackage(tree);
const packageJson = readJson(tree, 'package.json');
const newDependencyVersion =
packageJson.devDependencies['@nx/next'] ??
packageJson.dependencies['@nx/next'];
expect(newDependencyVersion).toBeDefined();
});
});

View File

@ -1,8 +0,0 @@
import { Tree, formatFiles } from '@nx/devkit';
import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package';
export default async function replacePackage(tree: Tree): Promise<void> {
await replaceNrwlPackageWithNxPackage(tree, '@nrwl/next', '@nx/next');
await formatFiles(tree);
}

View File

@ -1,72 +0,0 @@
import update from './remove-root-build-option';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import {
addProjectConfiguration,
readProjectConfiguration,
Tree,
} from '@nx/devkit';
describe('remove-root-build-option', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
});
it('should remove the root option from the build target for @nx/next:build executor', async () => {
addProjectConfiguration(tree, 'my-app', {
root: 'my-app',
targets: {
build: {
executor: '@nx/next:build',
options: {
root: 'my-app',
},
},
},
});
await update(tree);
const updatedConfig = readProjectConfiguration(tree, 'my-app');
expect(updatedConfig.targets.build.options.root).toBeUndefined();
});
it('should remove the root option from the build target for @nrwl/next:build executor', async () => {
addProjectConfiguration(tree, 'my-app', {
root: 'my-app',
targets: {
build: {
executor: '@nrwl/next:build',
options: {
root: 'my-app',
},
},
},
});
await update(tree);
const updatedConfig = readProjectConfiguration(tree, 'my-app');
expect(updatedConfig.targets.build.options.root).toBeUndefined();
});
it('should leave other executors alone', async () => {
addProjectConfiguration(tree, 'my-app', {
root: 'my-app',
targets: {
build: {
executor: '@acme/foo:bar',
options: {
root: 'my-app',
},
},
},
});
await update(tree);
const updatedConfig = readProjectConfiguration(tree, 'my-app');
expect(updatedConfig.targets.build.options.root).toEqual('my-app');
});
});

View File

@ -1,27 +0,0 @@
import {
readProjectConfiguration,
Tree,
updateProjectConfiguration,
} from '@nx/devkit';
import { forEachExecutorOptions } from '@nx/devkit/src/generators/executor-options-utils';
export default async function update(tree: Tree) {
forEachExecutorOptions(
tree,
'@nx/next:build',
(options, projectName, targetName) => {
const projectConfig = readProjectConfiguration(tree, projectName);
delete projectConfig.targets[targetName].options.root;
updateProjectConfiguration(tree, projectName, projectConfig);
}
);
forEachExecutorOptions(
tree,
'@nrwl/next:build',
(options, projectName, targetName) => {
const projectConfig = readProjectConfiguration(tree, projectName);
delete projectConfig.targets[targetName].options.root;
updateProjectConfiguration(tree, projectName, projectConfig);
}
);
}

View File

@ -1,26 +0,0 @@
import { Tree, readJson, updateJson } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from 'nx/src/devkit-testing-exports';
import update from './update-nx-next-dependency';
describe('update-nx-next-dependency', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
updateJson(tree, 'package.json', (json) => {
json.dependencies['@nx/next'] = '16.0.0';
return json;
});
});
it('should move @nx/next from dependencies to devDependencies', async () => {
await update(tree);
expect(
readJson(tree, 'package.json').dependencies['@nx/next']
).not.toBeDefined();
expect(
readJson(tree, 'package.json').devDependencies['@nx/next']
).toBeDefined();
});
});

View File

@ -1,16 +0,0 @@
import { Tree, formatFiles, updateJson } from '@nx/devkit';
import type { PackageJson } from 'nx/src/utils/package-json';
export default async function update(tree: Tree) {
if (tree.exists('./package.json')) {
updateJson<PackageJson>(tree, 'package.json', (packageJson) => {
if (packageJson.dependencies['@nx/next']) {
packageJson.devDependencies['@nx/next'] =
packageJson.dependencies['@nx/next'];
delete packageJson.dependencies['@nx/next'];
}
return packageJson;
});
}
await formatFiles(tree);
}

View File

@ -1,30 +1,5 @@
{
"generators": {
"update-16-0-0-add-nx-packages": {
"cli": "nx",
"version": "16.0.0-beta.1",
"description": "Replace @nrwl/node with @nx/node",
"implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages"
},
"update-16-0-0-update-executor": {
"cli": "nx",
"version": "16.0.0-beta.5",
"description": "Replace @nrwl/node:webpack with @nx/node:webpack",
"implementation": "./src/migrations/update-16-0-0/update-webpack-executor"
},
"update-16-3-1-update-executor": {
"cli": "nx",
"version": "16.3.1-beta.0",
"description": "Replace @nrwl/node:webpack and @nx/node:webpack with @nx/webpack:webpack for all project targets",
"implementation": "./src/migrations/update-16-3-1/update-webpack-executor"
},
"update-16-4-0-replace-node-executor": {
"cli": "nx",
"version": "16.4.0-beta.8",
"description": "Replace @nx/node:node with @nx/js:node for all project targets",
"implementation": "./src/migrations/update-16-4-0/replace-node-executor"
}
},
"generators": {},
"packageJsonUpdates": {
"17.3.0": {
"version": "17.3.0-beta.3",

View File

@ -1,37 +0,0 @@
import { Tree, readJson, updateJson } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import replacePackage from './update-16-0-0-add-nx-packages';
describe('update-16-0-0-add-nx-packages', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
updateJson(tree, 'package.json', (json) => {
json.devDependencies['@nrwl/node'] = '16.0.0';
return json;
});
});
it('should remove the dependency on @nrwl/node', async () => {
await replacePackage(tree);
expect(
readJson(tree, 'package.json').dependencies['@nrwl/node']
).not.toBeDefined();
expect(
readJson(tree, 'package.json').devDependencies['@nrwl/node']
).not.toBeDefined();
});
it('should add a dependency on @nx/node', async () => {
await replacePackage(tree);
const packageJson = readJson(tree, 'package.json');
const newDependencyVersion =
packageJson.devDependencies['@nx/node'] ??
packageJson.dependencies['@nx/node'];
expect(newDependencyVersion).toBeDefined();
});
});

View File

@ -1,8 +0,0 @@
import { Tree, formatFiles } from '@nx/devkit';
import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package';
export default async function replacePackage(tree: Tree): Promise<void> {
await replaceNrwlPackageWithNxPackage(tree, '@nrwl/node', '@nx/node');
await formatFiles(tree);
}

View File

@ -1,52 +0,0 @@
import { addProjectConfiguration, readProjectConfiguration } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import update from './update-webpack-executor';
describe('Migration: @nrwl/webpack', () => {
it(`should update usage of webpack executor`, async () => {
let tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
addProjectConfiguration(tree, 'myapp', {
root: 'apps/myapp',
sourceRoot: 'apps/myapp/src',
projectType: 'application',
targets: {
foo: {
executor: '@nrwl/node:webpack',
options: {},
},
bar: {
executor: '@nx/node:webpack',
options: {},
},
},
});
await update(tree);
expect(readProjectConfiguration(tree, 'myapp')).toEqual({
$schema: '../../node_modules/nx/schemas/project-schema.json',
name: 'myapp',
root: 'apps/myapp',
sourceRoot: 'apps/myapp/src',
projectType: 'application',
targets: {
foo: {
executor: '@nx/webpack:webpack',
options: {
compiler: 'tsc',
target: 'node',
},
},
bar: {
executor: '@nx/webpack:webpack',
options: {
compiler: 'tsc',
target: 'node',
},
},
},
});
});
});

View File

@ -1,22 +0,0 @@
import {
formatFiles,
readProjectConfiguration,
Tree,
updateProjectConfiguration,
} from '@nx/devkit';
import { forEachExecutorOptions } from '@nx/devkit/src/generators/executor-options-utils';
export default async function update(tree: Tree) {
const migrateProject = (options, projectName, targetName) => {
const projectConfig = readProjectConfiguration(tree, projectName);
projectConfig.targets[targetName].executor = '@nx/webpack:webpack';
projectConfig.targets[targetName].options.compiler = 'tsc';
projectConfig.targets[targetName].options.target = 'node';
updateProjectConfiguration(tree, projectName, projectConfig);
};
forEachExecutorOptions(tree, '@nx/node:webpack', migrateProject);
forEachExecutorOptions(tree, '@nrwl/node:webpack', migrateProject);
await formatFiles(tree);
}

View File

@ -1,52 +0,0 @@
import { addProjectConfiguration, readProjectConfiguration } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import update from './update-webpack-executor';
describe('Migration: @nrwl/webpack', () => {
it(`should update usage of webpack executor`, async () => {
let tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
addProjectConfiguration(tree, 'myapp', {
root: 'apps/myapp',
sourceRoot: 'apps/myapp/src',
projectType: 'application',
targets: {
foo: {
executor: '@nrwl/node:webpack',
options: {},
},
bar: {
executor: '@nx/node:webpack',
options: {},
},
},
});
await update(tree);
expect(readProjectConfiguration(tree, 'myapp')).toEqual({
$schema: '../../node_modules/nx/schemas/project-schema.json',
name: 'myapp',
root: 'apps/myapp',
sourceRoot: 'apps/myapp/src',
projectType: 'application',
targets: {
foo: {
executor: '@nx/webpack:webpack',
options: {
compiler: 'tsc',
target: 'node',
},
},
bar: {
executor: '@nx/webpack:webpack',
options: {
compiler: 'tsc',
target: 'node',
},
},
},
});
});
});

View File

@ -1,22 +0,0 @@
import {
formatFiles,
readProjectConfiguration,
Tree,
updateProjectConfiguration,
} from '@nx/devkit';
import { forEachExecutorOptions } from '@nx/devkit/src/generators/executor-options-utils';
export default async function update(tree: Tree) {
const migrateProject = (options, projectName, targetName) => {
const projectConfig = readProjectConfiguration(tree, projectName);
projectConfig.targets[targetName].executor = '@nx/webpack:webpack';
projectConfig.targets[targetName].options.compiler = 'tsc';
projectConfig.targets[targetName].options.target = 'node';
updateProjectConfiguration(tree, projectName, projectConfig);
};
forEachExecutorOptions(tree, '@nx/node:webpack', migrateProject);
forEachExecutorOptions(tree, '@nrwl/node:webpack', migrateProject);
await formatFiles(tree);
}

View File

@ -1,79 +0,0 @@
import { addProjectConfiguration, readProjectConfiguration } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import update from './replace-node-executor';
describe('Migration: replace @nx/node:node executor', () => {
it(`should replace @nx/node:node executor with @nx/js:node`, async () => {
let tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
addProjectConfiguration(tree, 'myapp', {
root: 'apps/myapp',
sourceRoot: 'apps/myapp/src',
projectType: 'application',
targets: {
foo: {
executor: '@nx/node:node',
options: {},
},
bar: {
executor: '@nx/node:node',
options: {},
},
},
});
addProjectConfiguration(tree, 'myapp2', {
root: 'apps/myapp2',
sourceRoot: 'apps/myapp2/src',
projectType: 'application',
targets: {
foo: {
executor: '@nx/node:node',
options: {},
},
bar: {
executor: '@nx/node:node',
options: {},
},
},
});
await update(tree);
expect(readProjectConfiguration(tree, 'myapp')).toEqual({
$schema: '../../node_modules/nx/schemas/project-schema.json',
name: 'myapp',
root: 'apps/myapp',
sourceRoot: 'apps/myapp/src',
projectType: 'application',
targets: {
foo: {
executor: '@nx/js:node',
options: {},
},
bar: {
executor: '@nx/js:node',
options: {},
},
},
});
expect(readProjectConfiguration(tree, 'myapp2')).toEqual({
$schema: '../../node_modules/nx/schemas/project-schema.json',
name: 'myapp2',
root: 'apps/myapp2',
sourceRoot: 'apps/myapp2/src',
projectType: 'application',
targets: {
foo: {
executor: '@nx/js:node',
options: {},
},
bar: {
executor: '@nx/js:node',
options: {},
},
},
});
});
});

View File

@ -1,19 +0,0 @@
import {
formatFiles,
readProjectConfiguration,
Tree,
updateProjectConfiguration,
} from '@nx/devkit';
import { forEachExecutorOptions } from '@nx/devkit/src/generators/executor-options-utils';
export default async function update(tree: Tree) {
const migrateProject = (_options, projectName, targetName) => {
const projectConfig = readProjectConfiguration(tree, projectName);
projectConfig.targets[targetName].executor = '@nx/js:node';
updateProjectConfiguration(tree, projectName, projectConfig);
};
forEachExecutorOptions(tree, '@nx/node:node', migrateProject);
await formatFiles(tree);
}

View File

@ -1,42 +1,5 @@
{
"generators": {
"16.0.0-remove-nrwl-cli": {
"cli": "nx",
"version": "16.0.0-beta.0",
"description": "Remove @nrwl/cli.",
"implementation": "./src/migrations/update-16-0-0/remove-nrwl-cli"
},
"16.0.0-tokens-for-depends-on": {
"cli": "nx",
"version": "16.0.0-beta.9",
"description": "Replace `dependsOn.projects` and `inputs` definitions with new configuration format.",
"implementation": "./src/migrations/update-16-0-0/update-depends-on-to-tokens"
},
"16.0.0-update-nx-cloud-runner": {
"cli": "nx",
"version": "16.0.0-beta.0",
"description": "Replace @nrwl/nx-cloud with nx-cloud",
"implementation": "./src/migrations/update-16-0-0/update-nx-cloud-runner"
},
"16.2.0-remove-output-path-from-run-commands": {
"cli": "nx",
"version": "16.2.0-beta.0",
"description": "Remove outputPath from run commands",
"implementation": "./src/migrations/update-16-2-0/remove-run-commands-output-path"
},
"16.6.0-prefix-outputs": {
"cli": "nx",
"version": "16.6.0-beta.6",
"description": "Prefix outputs with {workspaceRoot}/{projectRoot} if needed",
"implementation": "./src/migrations/update-15-0-0/prefix-outputs"
},
"16.8.0-escape-dollar-sign-env": {
"cli": "nx",
"version": "16.8.0-beta.3",
"description": "Escape $ in env variables",
"implementation": "./src/migrations/update-16-8-0/escape-dollar-sign-env-variables",
"x-repair-skip": true
},
"17.0.0-move-cache-directory": {
"cli": "nx",
"version": "17.0.0-beta.1",

View File

@ -2,17 +2,26 @@ import { MigrationsJson, MigrationsJsonEntry } from '../config/misc-interfaces';
import * as path from 'path';
export function assertValidMigrationPaths(json: MigrationsJson, root: string) {
let hasTests = false;
Object.entries(json.generators).forEach(([generator, m]) => {
hasTests = true;
it(`should have valid path generator: ${generator}`, () => {
validateMigration(m, root);
});
});
Object.entries(json.schematics ?? {}).forEach(([schematic, m]) => {
hasTests = true;
it(`should have valid path schematic: ${schematic}`, () => {
validateMigration(m, root);
});
});
if (!hasTests) {
it('should pass without migrations', () => {
// no-op
});
}
}
function validateMigration(m: MigrationsJsonEntry, root: string) {

View File

@ -1,192 +0,0 @@
import { createTreeWithEmptyWorkspace } from '../../generators/testing-utils/create-tree-with-empty-workspace';
import type { Tree } from '../../generators/tree';
import {
addProjectConfiguration,
readNxJson,
readProjectConfiguration,
updateNxJson,
} from '../../generators/utils/project-configuration';
import { readJson, writeJson } from '../../generators/utils/json';
import prefixOutputs from './prefix-outputs';
import { validateOutputs } from '../../tasks-runner/utils';
describe('15.0.0 migration (prefix-outputs)', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
});
it('should prefix project outputs', async () => {
addProjectConfiguration(tree, 'proj', {
root: 'proj',
targets: {
build: {
executor: 'nx:run-commands',
outputs: [
'dist',
'dist/{projectRoot}',
'dist/{projectRoot}/**/*.js',
'proj/coverage',
'./test-results',
'{projectRoot}/build',
'{options.outputDirectory}',
],
options: {},
},
},
});
await prefixOutputs(tree);
const updated = readProjectConfiguration(tree, 'proj');
expect(updated.targets.build.outputs).toEqual([
'{workspaceRoot}/dist',
'{workspaceRoot}/dist/{projectRoot}',
'{workspaceRoot}/dist/{projectRoot}/**/*.js',
'{projectRoot}/coverage',
'{projectRoot}/test-results',
'{projectRoot}/build',
'{options.outputDirectory}',
]);
expect(() => validateOutputs(updated.targets.build.outputs)).not.toThrow();
});
it('should prefix target default outputs', async () => {
const nxJson = readNxJson(tree);
updateNxJson(tree, {
...nxJson,
targetDefaults: {
build: {
outputs: ['dist', '{projectRoot}/build', '{options.outputPath}'],
},
},
});
await prefixOutputs(tree);
const updated = readNxJson(tree);
expect(updated.targetDefaults).toMatchInlineSnapshot(`
{
"build": {
"outputs": [
"{workspaceRoot}/dist",
"{projectRoot}/build",
"{options.outputPath}",
],
},
}
`);
});
it('should migrate package.json projects', async () => {
writeJson(tree, 'proj/package.json', {
name: 'proj',
scripts: {
build: 'echo',
},
nx: {
targets: {
build: {
outputs: ['dist/proj', 'proj/build'],
},
},
},
});
tree.delete('workspace.json');
await prefixOutputs(tree);
expect(readJson(tree, 'proj/package.json').nx.targets.build).toEqual({
outputs: ['{workspaceRoot}/dist/proj', '{projectRoot}/build'],
});
});
it('should not error for package.json projects', async () => {
writeJson(tree, 'proj/package.json', {
name: 'proj',
scripts: {
build: 'echo',
},
});
tree.delete('workspace.json');
await prefixOutputs(tree);
});
it('should handle negated outputs', async () => {
const nxJson = readNxJson(tree);
updateNxJson(tree, {
...nxJson,
targetDefaults: {
build: {
outputs: ['!dist', '{projectRoot}/build', '{options.outputPath}'],
},
},
});
await prefixOutputs(tree);
const updated = readNxJson(tree);
expect(updated.targetDefaults).toMatchInlineSnapshot(`
{
"build": {
"outputs": [
"!{workspaceRoot}/dist",
"{projectRoot}/build",
"{options.outputPath}",
],
},
}
`);
});
});
describe('15.0.0 migration (prefix-outputs) (v1)', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
});
it('should prefix project outputs', async () => {
addProjectConfiguration(tree, 'proj', {
root: 'proj',
targets: {
build: {
executor: 'nx:run-commands',
outputs: [
'dist',
'dist/{projectRoot}',
'dist/{projectRoot}/**/*.js',
'proj/coverage',
'./test-results',
'{projectRoot}/build',
'{options.outputDirectory}',
],
options: {},
},
},
});
await prefixOutputs(tree);
const updated = readProjectConfiguration(tree, 'proj');
expect(updated.targets.build.outputs).toEqual([
'{workspaceRoot}/dist',
'{workspaceRoot}/dist/{projectRoot}',
'{workspaceRoot}/dist/{projectRoot}/**/*.js',
'{projectRoot}/coverage',
'{projectRoot}/test-results',
'{projectRoot}/build',
'{options.outputDirectory}',
]);
expect(() => validateOutputs(updated.targets.build.outputs)).not.toThrow();
});
});

View File

@ -1,69 +0,0 @@
import { Tree } from '../../generators/tree';
import { formatChangedFilesWithPrettierIfAvailable } from '../../generators/internal-utils/format-changed-files-with-prettier-if-available';
import {
getProjects,
updateProjectConfiguration,
} from '../../generators/utils/project-configuration';
import { readNxJson, updateNxJson } from '../../generators/utils/nx-json';
import { joinPathFragments } from '../../utils/path';
import { join } from 'path';
import {
transformLegacyOutputs,
validateOutputs,
} from '../../tasks-runner/utils';
import { updateJson } from '../../generators/utils/json';
import { PackageJson } from '../../utils/package-json';
export default async function (tree: Tree) {
// If the workspace doesn't have a nx.json, don't make any changes
if (!tree.exists('nx.json')) {
return;
}
const nxJson = readNxJson(tree);
for (const [projectName, project] of getProjects(tree)) {
for (const [_, target] of Object.entries(project.targets ?? {})) {
if (!target.outputs) {
continue;
}
target.outputs = transformLegacyOutputs(project.root, target.outputs);
}
try {
updateProjectConfiguration(tree, projectName, project);
} catch {
if (tree.exists(join(project.root, 'package.json'))) {
updateJson<PackageJson>(
tree,
join(project.root, 'package.json'),
(json) => {
for (const target of Object.values(json.nx?.targets ?? {})) {
if (target.outputs) {
target.outputs = transformLegacyOutputs(
project.root,
target.outputs
);
}
}
return json;
}
);
}
}
}
if (nxJson.targetDefaults) {
for (const [_, target] of Object.entries(nxJson.targetDefaults)) {
if (!target.outputs) {
continue;
}
target.outputs = transformLegacyOutputs('{projectRoot}', target.outputs);
}
updateNxJson(tree, nxJson);
}
await formatChangedFilesWithPrettierIfAvailable(tree);
}

View File

@ -1,17 +0,0 @@
import { Tree } from '../../generators/tree';
import { formatChangedFilesWithPrettierIfAvailable } from '../../generators/internal-utils/format-changed-files-with-prettier-if-available';
import { updateJson } from '../../generators/utils/json';
export default async function (tree: Tree) {
updateJson(tree, 'package.json', (json) => {
for (const deps of [json.dependencies, json.devDependencies]) {
if (deps) {
delete deps['@nrwl/cli'];
}
}
return json;
});
await formatChangedFilesWithPrettierIfAvailable(tree);
}

View File

@ -1,131 +0,0 @@
import {
addProjectConfiguration,
readNxJson,
readProjectConfiguration,
} from '../../generators/utils/project-configuration';
import update from './update-depends-on-to-tokens';
import { updateJson, writeJson } from '../../generators/utils/json';
import { createTreeWithEmptyWorkspace } from '../../generators/testing-utils/create-tree-with-empty-workspace';
import { assertRunsAgainstNxRepo } from '../../internal-testing-utils/run-migration-against-this-workspace';
describe('update-depends-on-to-tokens', () => {
it('should update nx.json', async () => {
const tree = createTreeWithEmptyWorkspace();
updateJson(tree, 'nx.json', (json) => {
json.targetDefaults = {
build: {
dependsOn: [
{
projects: 'self',
},
],
inputs: [{ projects: 'self', input: 'someInput' }],
},
test: {
dependsOn: [
{
projects: 'dependencies',
},
],
inputs: [{ projects: 'dependencies', input: 'someInput' }],
},
other: {
dependsOn: ['^deps'],
},
};
return json;
});
await update(tree);
const nxJson = readNxJson(tree);
const buildDependencyConfiguration = nxJson.targetDefaults.build
.dependsOn[0] as any;
const testDependencyConfiguration = nxJson.targetDefaults.test
.dependsOn[0] as any;
const buildInputConfiguration = nxJson.targetDefaults.build
.inputs[0] as any;
const testInputConfiguration = nxJson.targetDefaults.test.inputs[0] as any;
expect(buildDependencyConfiguration.projects).not.toBeDefined();
expect(buildDependencyConfiguration.dependencies).not.toBeDefined();
expect(buildInputConfiguration.projects).not.toBeDefined();
expect(buildInputConfiguration.dependencies).not.toBeDefined();
expect(testInputConfiguration.projects).not.toBeDefined();
expect(testInputConfiguration.dependencies).toEqual(true);
expect(testDependencyConfiguration.projects).not.toBeDefined();
expect(testDependencyConfiguration.dependencies).toEqual(true);
expect(nxJson.targetDefaults.other.dependsOn).toEqual(['^deps']);
});
it('should update project configurations', async () => {
const tree = createTreeWithEmptyWorkspace();
addProjectConfiguration(tree, 'proj1', {
root: 'proj1',
targets: {
build: {
dependsOn: [
{
projects: 'self',
target: 'build',
},
],
inputs: [{ projects: 'self', input: 'someInput' }],
},
test: {
dependsOn: [
{
projects: 'dependencies',
target: 'test',
},
],
inputs: [{ projects: 'dependencies', input: 'someInput' }],
},
other: {
dependsOn: ['^deps'],
},
},
});
await update(tree);
const project = readProjectConfiguration(tree, 'proj1');
const buildDependencyConfiguration = project.targets.build
.dependsOn[0] as any;
const testDependencyConfiguration = project.targets.test
.dependsOn[0] as any;
const buildInputConfiguration = project.targets.build.inputs[0] as any;
const testInputConfiguration = project.targets.test.inputs[0] as any;
expect(buildDependencyConfiguration.projects).not.toBeDefined();
expect(buildDependencyConfiguration.dependencies).not.toBeDefined();
expect(buildInputConfiguration.projects).not.toBeDefined();
expect(buildInputConfiguration.dependencies).not.toBeDefined();
expect(testDependencyConfiguration.projects).not.toBeDefined();
expect(testDependencyConfiguration.dependencies).toEqual(true);
expect(testInputConfiguration.projects).not.toBeDefined();
expect(testInputConfiguration.dependencies).toEqual(true);
expect(project.targets.other.dependsOn).toEqual(['^deps']);
expect(project.targets.other.inputs).not.toBeDefined();
});
it('should not throw on nulls', async () => {
const tree = createTreeWithEmptyWorkspace();
addProjectConfiguration(tree, 'proj1', {
root: 'proj1',
});
addProjectConfiguration(tree, 'proj2', {
root: 'proj2',
targets: {
build: {},
},
});
writeJson(tree, 'nx.json', {});
let promise = update(tree);
await expect(promise).resolves.toBeUndefined();
writeJson(tree, 'nx.json', {
targetDefaults: {
build: {},
},
});
promise = update(tree);
await expect(promise).resolves.toBeUndefined();
});
assertRunsAgainstNxRepo(update);
});

View File

@ -1,119 +0,0 @@
import {
getProjects,
readNxJson,
updateNxJson,
updateProjectConfiguration,
} from '../../generators/utils/project-configuration';
import { Tree } from '../../generators/tree';
import { formatChangedFilesWithPrettierIfAvailable } from '../../generators/internal-utils/format-changed-files-with-prettier-if-available';
export default async function (tree: Tree) {
updateDependsOnAndInputsInsideNxJson(tree);
const projectsConfigurations = getProjects(tree);
for (const [projectName, projectConfiguration] of projectsConfigurations) {
let projectChanged = false;
for (const [targetName, targetConfiguration] of Object.entries(
projectConfiguration.targets ?? {}
)) {
for (const dependency of targetConfiguration.dependsOn ?? []) {
if (typeof dependency !== 'string') {
if (
dependency.projects === 'self' ||
dependency.projects === '{self}'
) {
delete dependency.projects;
projectChanged = true;
} else if (
dependency.projects === 'dependencies' ||
dependency.projects === '{dependencies}'
) {
delete dependency.projects;
dependency.dependencies = true;
projectChanged = true;
}
}
}
for (let i = 0; i < targetConfiguration.inputs?.length ?? 0; i++) {
const input = targetConfiguration.inputs[i];
if (typeof input !== 'string') {
if (
'projects' in input &&
(input.projects === 'self' || input.projects === '{self}')
) {
delete input.projects;
projectChanged = true;
} else if (
'projects' in input &&
(input.projects === 'dependencies' ||
input.projects === '{dependencies}')
) {
delete input.projects;
targetConfiguration.inputs[i] = {
...input,
dependencies: true,
};
projectChanged = true;
}
}
}
}
if (projectChanged) {
updateProjectConfiguration(tree, projectName, projectConfiguration);
}
}
await formatChangedFilesWithPrettierIfAvailable(tree);
}
function updateDependsOnAndInputsInsideNxJson(tree: Tree) {
const nxJson = readNxJson(tree);
let nxJsonChanged = false;
for (const [target, defaults] of Object.entries(
nxJson?.targetDefaults ?? {}
)) {
for (const dependency of defaults.dependsOn ?? []) {
if (typeof dependency !== 'string') {
if (
dependency.projects === 'self' ||
dependency.projects === '{self}'
) {
delete dependency.projects;
nxJsonChanged = true;
} else if (
dependency.projects === 'dependencies' ||
dependency.projects === '{dependencies}'
) {
delete dependency.projects;
dependency.dependencies = true;
nxJsonChanged = true;
}
}
}
for (let i = 0; i < defaults.inputs?.length ?? 0; i++) {
const input = defaults.inputs[i];
if (typeof input !== 'string') {
if (
'projects' in input &&
(input.projects === 'self' || input.projects === '{self}')
) {
delete input.projects;
nxJsonChanged = true;
} else if (
'projects' in input &&
(input.projects === 'dependencies' ||
input.projects === '{dependencies}')
) {
delete input.projects;
defaults.inputs[i] = {
...input,
dependencies: true,
};
nxJsonChanged = true;
}
}
}
}
if (nxJsonChanged) {
updateNxJson(tree, nxJson);
}
}

View File

@ -1,34 +0,0 @@
import {
readNxJson,
updateNxJson,
} from '../../generators/utils/project-configuration';
import { Tree } from '../../generators/tree';
import { updateJson } from '../../generators/utils/json';
import { formatChangedFilesWithPrettierIfAvailable } from '../../generators/internal-utils/format-changed-files-with-prettier-if-available';
export default async function (tree: Tree) {
updateJson(tree, 'package.json', (json) => {
if (json.dependencies && json.dependencies['@nrwl/nx-cloud']) {
json.dependencies['nx-cloud'] = json.dependencies['@nrwl/nx-cloud'];
delete json.dependencies['@nrwl/nx-cloud'];
}
if (json.devDependencies && json.devDependencies['@nrwl/nx-cloud']) {
json.devDependencies['nx-cloud'] = json.devDependencies['@nrwl/nx-cloud'];
delete json.devDependencies['@nrwl/nx-cloud'];
}
return json;
});
const nxJson = readNxJson(tree);
if (!nxJson) return;
for (let opts of Object.values(nxJson.tasksRunnerOptions ?? {})) {
if (opts.runner === '@nrwl/nx-cloud') {
opts.runner = 'nx-cloud';
}
}
updateNxJson(tree, nxJson);
await formatChangedFilesWithPrettierIfAvailable(tree);
}

View File

@ -1,102 +0,0 @@
import { TargetConfiguration } from '../../config/workspace-json-project-json';
import { createTreeWithEmptyWorkspace } from '../../generators/testing-utils/create-tree-with-empty-workspace';
import { readJson, writeJson } from '../../generators/utils/json';
import {
addProjectConfiguration,
readProjectConfiguration,
} from '../../generators/utils/project-configuration';
import { assertRunsAgainstNxRepo } from '../../internal-testing-utils/run-migration-against-this-workspace';
import removeRunCommandsOutputPath from './remove-run-commands-output-path';
describe('removeRunCommandsOutputPath', () => {
it('should migrate target options correctly', () => {
const tree = createTreeWithEmptyWorkspace();
const startingTargets: Record<string, TargetConfiguration> = {
build: {
executor: 'nx:run-commands',
outputs: ['{options.outputPath}'],
options: {
outputPath: 'dist/apps/my-app',
commands: [],
},
},
other: {
executor: 'nx:run-script',
options: {
script: 'start',
},
},
};
addProjectConfiguration(tree, 'my-app', {
root: 'apps/my-app',
targets: startingTargets,
});
removeRunCommandsOutputPath(tree);
const migratedTargets = readProjectConfiguration(tree, 'my-app').targets;
expect(migratedTargets.build).not.toEqual(startingTargets.build);
expect(migratedTargets.build).toEqual({
executor: 'nx:run-commands',
outputs: ['{workspaceRoot}/dist/apps/my-app'],
options: {
commands: [],
},
});
expect(migratedTargets.other).toEqual(startingTargets.other);
});
it('should handle null options correctly', () => {
const tree = createTreeWithEmptyWorkspace();
const startingTargets: Record<string, TargetConfiguration> = {
build: {
executor: 'nx:run-commands',
outputs: ['dist/some/path'],
},
};
addProjectConfiguration(tree, 'my-app', {
root: 'apps/my-app',
targets: startingTargets,
});
expect(() => removeRunCommandsOutputPath(tree)).not.toThrow();
const migratedTargets = readProjectConfiguration(tree, 'my-app').targets;
expect(migratedTargets.build).toEqual(startingTargets.build);
expect(migratedTargets.other).toEqual(startingTargets.other);
});
it('should migrate target defaults correctly', () => {
const tree = createTreeWithEmptyWorkspace();
const startingTargetDefaults: Record<string, TargetConfiguration> = {
build: {
executor: 'nx:run-commands',
outputs: ['{options.outputPath}'],
options: {
outputPath: 'dist/apps/my-app',
commands: [],
},
},
other: {
executor: 'nx:run-script',
options: {
script: 'start',
},
},
};
writeJson(tree, 'nx.json', {
targetDefaults: startingTargetDefaults,
});
removeRunCommandsOutputPath(tree);
const migratedTargetDefaults = readJson(tree, 'nx.json').targetDefaults;
expect(migratedTargetDefaults.build).not.toEqual(
startingTargetDefaults.build
);
expect(migratedTargetDefaults.build).toEqual({
executor: 'nx:run-commands',
outputs: ['{workspaceRoot}/dist/apps/my-app'],
options: {
commands: [],
},
});
expect(migratedTargetDefaults.other).toEqual(startingTargetDefaults.other);
});
assertRunsAgainstNxRepo(removeRunCommandsOutputPath);
});

View File

@ -1,52 +0,0 @@
import { joinPathFragments } from '../../utils/path';
import { NxJsonConfiguration } from '../../config/nx-json';
import { TargetConfiguration } from '../../config/workspace-json-project-json';
import { formatChangedFilesWithPrettierIfAvailable } from '../../generators/internal-utils/format-changed-files-with-prettier-if-available';
import { Tree } from '../../generators/tree';
import { updateJson } from '../../generators/utils/json';
import {
getProjects,
updateProjectConfiguration,
} from '../../generators/utils/project-configuration';
export default async function removeRunCommandsOutputPath(tree: Tree) {
for (const [project, configuration] of getProjects(tree).entries()) {
const targets = configuration.targets ?? {};
let changed = false;
for (const [, target] of Object.entries(targets)) {
changed ||= updateTargetBlock(target);
}
if (changed) {
updateProjectConfiguration(tree, project, configuration);
}
}
if (tree.exists('nx.json')) {
updateJson<NxJsonConfiguration>(tree, 'nx.json', (json) => {
for (const [, target] of Object.entries(json.targetDefaults ?? {})) {
updateTargetBlock(target);
}
return json;
});
}
await formatChangedFilesWithPrettierIfAvailable(tree);
}
function updateTargetBlock(target: TargetConfiguration): boolean {
let changed = false;
if (target.executor === 'nx:run-commands' && target.options?.outputPath) {
changed = true;
const outputs = new Set(target.outputs ?? []);
outputs.delete('{options.outputPath}');
const newOutputs = Array.isArray(target.options.outputPath)
? target.options.outputPath.map((p) =>
joinPathFragments('{workspaceRoot}', p)
)
: [joinPathFragments('{workspaceRoot}', target.options.outputPath)];
for (const outputPath of newOutputs) {
outputs.add(outputPath);
}
delete target.options.outputPath;
target.outputs = Array.from(outputs);
}
return changed;
}

View File

@ -1,132 +0,0 @@
import { createTreeWithEmptyWorkspace } from '../../generators/testing-utils/create-tree-with-empty-workspace';
import { addProjectConfiguration } from '../../generators/utils/project-configuration';
import escapeDollarSignEnvVariables from './escape-dollar-sign-env-variables';
describe('escape $ in env variables', () => {
let tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
});
it('should escape $ in env variables in .env file', () => {
tree.write(
'.env',
`dollar=$
NX_SOME_VAR=$ABC`
);
escapeDollarSignEnvVariables(tree);
expect(tree.read('.env', 'utf-8')).toEqual(`dollar=\\$
NX_SOME_VAR=\\$ABC`);
});
it('should escape $ env variables in .env file under project', () => {
addProjectConfiguration(tree, 'my-app', {
root: 'apps/my-app',
});
addProjectConfiguration(tree, 'my-app2', {
root: 'apps/my-app2',
});
tree.write(
'apps/my-app/.env',
`dollar=$
NX_SOME_VAR=$ABC`
);
tree.write(
'apps/my-app2/.env',
`dollar=$
NX_SOME_VAR=$DEF`
);
escapeDollarSignEnvVariables(tree);
expect(tree.read('apps/my-app/.env', 'utf-8')).toEqual(`dollar=\\$
NX_SOME_VAR=\\$ABC`);
expect(tree.read('apps/my-app2/.env', 'utf-8')).toEqual(`dollar=\\$
NX_SOME_VAR=\\$DEF`);
});
it('should escape $ env variables in .env for target', () => {
tree.write('.env', 'dollar=$');
tree.write('.env.build', 'dollar=$');
addProjectConfiguration(tree, 'my-app', {
root: 'apps/my-app',
targets: {
build: {
executor: '@nx/node:build',
configurations: {
production: {},
},
},
},
});
tree.write(
'apps/my-app/.build.env',
`dollar=$
NX_SOME_VAR=$ABC`
);
tree.write(
'apps/my-app/.env',
`dollar=$
NX_SOME_VAR=$ABC`
);
escapeDollarSignEnvVariables(tree);
expect(tree.read('.env', 'utf-8')).toEqual(`dollar=\\$`);
expect(tree.read('apps/my-app/.env', 'utf-8')).toEqual(`dollar=\\$
NX_SOME_VAR=\\$ABC`);
expect(tree.read('apps/my-app/.build.env', 'utf-8')).toEqual(`dollar=\\$
NX_SOME_VAR=\\$ABC`);
});
it('should escape $ env variables in .env for configuration', () => {
tree.write('.env', 'dollar=$');
tree.write('.env.production', 'dollar=$');
addProjectConfiguration(tree, 'my-app', {
root: 'apps/my-app',
targets: {
build: {
executor: '@nx/node:build',
configurations: {
production: {},
},
},
},
});
tree.write(
'apps/my-app/.production.env',
`dollar=$
NX_SOME_VAR=$ABC`
);
tree.write(
'apps/my-app/.build.production.env',
`dollar=$
NX_SOME_VAR=$ABC`
);
tree.write(
'apps/my-app/.env',
`dollar=$
NX_SOME_VAR=$ABC`
);
escapeDollarSignEnvVariables(tree);
expect(tree.read('.env', 'utf-8')).toEqual(`dollar=\\$`);
expect(tree.read('apps/my-app/.env', 'utf-8')).toEqual(`dollar=\\$
NX_SOME_VAR=\\$ABC`);
expect(tree.read('apps/my-app/.build.production.env', 'utf-8'))
.toEqual(`dollar=\\$
NX_SOME_VAR=\\$ABC`);
expect(tree.read('apps/my-app/.production.env', 'utf-8'))
.toEqual(`dollar=\\$
NX_SOME_VAR=\\$ABC`);
});
it('should not escape $ env variables if it is already escaped', () => {
addProjectConfiguration(tree, 'my-app', {
root: 'apps/my-app',
});
tree.write(
'apps/my-app/.env',
`dollar=\\$
NX_SOME_VAR=\\$ABC`
);
escapeDollarSignEnvVariables(tree);
expect(tree.read('apps/my-app/.env', 'utf-8')).toEqual(`dollar=\\$
NX_SOME_VAR=\\$ABC`);
});
});

View File

@ -1,92 +0,0 @@
import { logger } from '../../utils/logger';
import { Tree } from '../../generators/tree';
import { getProjects } from '../../generators/utils/project-configuration';
/**
* This function escapes dollar sign in env variables
* It will go through:
* - '.env', '.local.env', '.env.local'
* - .env.[target-name], .[target-name].env
* - .env.[target-name].[configuration-name], .[target-name].[configuration-name].env
* - .env.[configuration-name], .[configuration-name].env
* at each project root and workspace root
* @param tree
*/
export default function escapeDollarSignEnvVariables(tree: Tree) {
const envFiles = ['.env', '.local.env', '.env.local'];
for (const [_, configuration] of getProjects(tree).entries()) {
envFiles.push(
`${configuration.root}/.env`,
`${configuration.root}/.local.env`,
`${configuration.root}/.env.local`
);
for (const targetName in configuration.targets) {
const task = configuration.targets[targetName];
envFiles.push(
`.env.${targetName}`,
`.${targetName}.env`,
`${configuration.root}/.env.${targetName}`,
`${configuration.root}/.${targetName}.env`
);
if (task.configurations) {
for (const configurationName in task.configurations) {
envFiles.push(
`.env.${targetName}.${configurationName}`,
`.${targetName}.${configurationName}.env`,
`.env.${configurationName}`,
`.${configurationName}.env`,
`${configuration.root}/.env.${targetName}.${configurationName}`,
`${configuration.root}/.${targetName}.${configurationName}.env`,
`${configuration.root}/.env.${configurationName}`,
`${configuration.root}/.${configurationName}.env`
);
}
}
}
}
for (const envFile of new Set(envFiles)) {
parseEnvFile(tree, envFile);
}
}
/**
* This function parse the env file and escape dollar sign
* @param tree
* @param envFilePath
* @returns
*/
function parseEnvFile(tree: Tree, envFilePath: string) {
if (!tree.exists(envFilePath)) {
return;
}
let envFileContent = tree.read(envFilePath, 'utf-8');
if (!envFileContent) {
// envFileContent is null if we fail to read the file for any reason
// e.g. the file is not utf-8 encoded
logger.info(
`Unable to update ${envFilePath}. Nx interpolates environment variables in the form of $VAR_NAME. To escape the dollar sign, use \\$VAR_NAME.`
);
return;
}
envFileContent = envFileContent
.split('\n')
.map((line) => {
line = line.trim();
if (!line || !line.includes('$')) {
return line;
}
const declarations = line.split('=');
if (declarations[1].includes('$') && !declarations[1].includes(`\\$`)) {
declarations[1] = declarations[1].replace('$', `\\$`);
line = declarations.join('=');
}
return line;
})
.join('\n');
tree.write(envFilePath, envFileContent);
}

View File

@ -1,22 +1,3 @@
{
"generators": {
"update-remove-cli-prop": {
"version": "16.0.0-beta.1",
"cli": "nx",
"description": "Removes CLI property within schema.json files and moves generators and schematics to the proper root node in migrations.json",
"factory": "./src/migrations/update-16-0-0/cli-in-schema-json"
},
"update-16-0-0-add-nx-packages": {
"cli": "nx",
"version": "16.0.0-beta.1",
"description": "Replace @nrwl/nx-plugin with @nx/plugin",
"implementation": "./src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages"
},
"update-16-2-0-replace-e2e-executor": {
"cli": "nx",
"version": "16.2.0-beta.0",
"description": "Replace @nx/plugin:e2e with @nx/jest",
"implementation": "./src/migrations/update-16-2-0/replace-e2e-executor"
}
}
"generators": {}
}

View File

@ -1,40 +0,0 @@
import { Tree, readJson, updateJson } from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import { assertRunsAgainstNxRepo } from '@nx/devkit/internal-testing-utils';
import replacePackage from './update-16-0-0-add-nx-packages';
describe('update-16-0-0-add-nx-packages', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
updateJson(tree, 'package.json', (json) => {
json.devDependencies['@nrwl/nx-plugin'] = '16.0.0';
return json;
});
});
it('should remove the dependency on @nrwl/nx-plugin', async () => {
await replacePackage(tree);
expect(
readJson(tree, 'package.json').dependencies['@nrwl/nx-plugin']
).not.toBeDefined();
expect(
readJson(tree, 'package.json').devDependencies['@nrwl/nx-plugin']
).not.toBeDefined();
});
it('should add a dependency on @nx/plugin', async () => {
await replacePackage(tree);
const packageJson = readJson(tree, 'package.json');
const newDependencyVersion =
packageJson.devDependencies['@nx/plugin'] ??
packageJson.dependencies['@nx/plugin'];
expect(newDependencyVersion).toBeDefined();
});
assertRunsAgainstNxRepo(replacePackage);
});

View File

@ -1,8 +0,0 @@
import { Tree, formatFiles } from '@nx/devkit';
import { replaceNrwlPackageWithNxPackage } from '@nx/devkit/src/utils/replace-package';
export default async function replacePackage(tree: Tree): Promise<void> {
await replaceNrwlPackageWithNxPackage(tree, '@nrwl/nx-plugin', '@nx/plugin');
await formatFiles(tree);
}

View File

@ -1,281 +0,0 @@
import 'nx/src/internal-testing-utils/mock-project-graph';
import {
ExecutorsJson,
GeneratorsJson,
joinPathFragments,
MigrationsJson,
readJson,
readProjectConfiguration,
Tree,
updateJson,
writeJson,
} from '@nx/devkit';
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
import { Linter } from '@nx/eslint';
import { assertRunsAgainstNxRepo } from '@nx/devkit/internal-testing-utils';
import { PackageJson } from 'nx/src/utils/package-json';
import executorGenerator from '../../generators/executor/executor';
import generatorGenerator from '../../generators/generator/generator';
import pluginGenerator from '../../generators/plugin/plugin';
import { updateCliPropsForPlugins } from './cli-in-schema-json';
describe('updateCliPropsForPlugins', () => {
let originalEnv: string;
beforeEach(() => {
originalEnv = process.env.NX_ADD_PLUGINS;
process.env.NX_ADD_PLUGINS = 'false';
});
afterAll(() => {
process.env.NX_ADD_PLUGINS = originalEnv;
});
it('should move non-nx generators to schematics for migrations.json', async () => {
const tree = createTreeWithEmptyWorkspace();
const { root } = await createPlugin(tree);
updatePluginPackageJson(tree, {
'nx-migrations': 'migrations.json',
});
writeJson<MigrationsJson>(
tree,
joinPathFragments(root, 'migrations.json'),
{
version: '1.0.0',
generators: {
'migration-1': {
version: '1.0.0',
description: 'My Plugin 1',
factory: './migrations/my-plugin-1',
},
},
}
);
await updateCliPropsForPlugins(tree);
const updated = readJson<MigrationsJson>(
tree,
joinPathFragments(root, 'migrations.json')
);
expect(updated.generators).not.toHaveProperty('migration-1');
expect(updated.schematics).toHaveProperty('migration-1');
});
it('should move nx generators to generators for migrations.json', async () => {
const tree = createTreeWithEmptyWorkspace();
const { root } = await createPlugin(tree);
updatePluginPackageJson(tree, {
'nx-migrations': 'migrations.json',
});
writeJson<MigrationsJson>(
tree,
joinPathFragments(root, 'migrations.json'),
{
version: '1.0.0',
schematics: {
'migration-1': {
version: '1.0.0',
description: 'My Plugin 1',
factory: './migrations/my-plugin-1',
cli: 'nx',
},
},
}
);
await updateCliPropsForPlugins(tree);
const updated = readJson<MigrationsJson>(
tree,
joinPathFragments(root, 'migrations.json')
);
expect(updated.schematics).not.toHaveProperty('migration-1');
expect(updated.generators).toHaveProperty('migration-1');
});
it('should move both nx generators to generators and non-nx schematics to schematics for migrations.json', async () => {
const tree = createTreeWithEmptyWorkspace();
const { root } = await createPlugin(tree);
updatePluginPackageJson(tree, {
'nx-migrations': 'migrations.json',
});
writeJson<MigrationsJson>(
tree,
joinPathFragments(root, 'migrations.json'),
{
version: '1.0.0',
schematics: {
'migration-1': {
version: '1.0.0',
description: 'My Plugin 1',
factory: './migrations/my-plugin-1',
cli: 'nx',
},
'migration-2': {
version: '1.0.0',
description: 'My Plugin 2',
factory: './migrations/my-plugin-2',
},
},
generators: {
'migration-3': {
version: '1.0.0',
description: 'My Plugin 3',
factory: './migrations/my-plugin-3',
cli: 'nx',
},
'migration-4': {
version: '1.0.0',
description: 'My Plugin 4',
factory: './migrations/my-plugin-4',
},
},
}
);
await updateCliPropsForPlugins(tree);
const updated = readJson<MigrationsJson>(
tree,
joinPathFragments(root, 'migrations.json')
);
expect(updated.schematics).not.toHaveProperty('migration-1');
expect(updated.generators).toHaveProperty('migration-1');
expect(updated.schematics).toHaveProperty('migration-2');
expect(updated.generators).not.toHaveProperty('migration-2');
expect(updated.schematics).not.toHaveProperty('migration-3');
expect(updated.generators).toHaveProperty('migration-3');
expect(updated.schematics).toHaveProperty('migration-4');
expect(updated.generators).not.toHaveProperty('migration-4');
});
it('should remove cli property from executors', async () => {
const tree = createTreeWithEmptyWorkspace();
const { root, name } = await createPlugin(tree);
await executorGenerator(tree, {
name: 'my-executor',
path: `${name}/src/executors/my-executor`,
unitTestRunner: 'jest',
includeHasher: false,
});
const schemaPath = joinPathFragments(
root,
'src/executors/my-executor/schema.json'
);
updateJson(tree, schemaPath, (schema) => {
schema.cli = 'nx';
return schema;
});
await updateCliPropsForPlugins(tree);
const updated = readJson(tree, schemaPath);
expect(updated).not.toHaveProperty('cli');
});
it('should remove cli property from builders', async () => {
const tree = createTreeWithEmptyWorkspace();
const { root, name } = await createPlugin(tree);
await executorGenerator(tree, {
name: 'my-executor',
path: `${name}/src/executors/my-executor`,
unitTestRunner: 'jest',
includeHasher: false,
});
updateJson<ExecutorsJson>(
tree,
joinPathFragments(root, 'executors.json'),
(json) => {
json.builders = json.executors;
delete json.builders;
return json;
}
);
const schemaPath = joinPathFragments(
root,
'src/executors/my-executor/schema.json'
);
updateJson(tree, schemaPath, (schema) => {
schema.cli = 'nx';
return schema;
});
await updateCliPropsForPlugins(tree);
const updated = readJson(tree, schemaPath);
expect(updated).not.toHaveProperty('cli');
});
it('should remove cli property from generators', async () => {
const tree = createTreeWithEmptyWorkspace();
const { root, name } = await createPlugin(tree);
await generatorGenerator(tree, {
name: 'my-generator',
path: `${name}/src/generators/my-generator`,
unitTestRunner: 'jest',
});
const schemaPath = joinPathFragments(
root,
'src/generators/my-generator/schema.json'
);
updateJson(tree, schemaPath, (schema) => {
schema.cli = 'nx';
return schema;
});
await updateCliPropsForPlugins(tree);
const updated = readJson(tree, schemaPath);
expect(updated).not.toHaveProperty('cli');
});
it('should remove cli property from schematics', async () => {
const tree = createTreeWithEmptyWorkspace();
const { root, name } = await createPlugin(tree);
await generatorGenerator(tree, {
name: 'my-schematic',
path: `${name}/src/generators/my-schematic`,
unitTestRunner: 'jest',
});
updateJson<GeneratorsJson>(
tree,
joinPathFragments(root, 'generators.json'),
(json) => {
json.schematics = json.generators;
delete json.generators;
return json;
}
);
const schemaPath = joinPathFragments(
root,
'src/generators/my-schematic/schema.json'
);
updateJson(tree, schemaPath, (schema) => {
schema.cli = 'nx';
return schema;
});
await updateCliPropsForPlugins(tree);
const updated = readJson(tree, schemaPath);
expect(updated).not.toHaveProperty('cli');
});
assertRunsAgainstNxRepo(updateCliPropsForPlugins);
});
async function createPlugin(tree: Tree) {
await pluginGenerator(tree, {
directory: 'my-plugin',
compiler: 'tsc',
linter: Linter.EsLint,
unitTestRunner: 'jest',
skipFormat: true,
skipLintChecks: false,
skipTsConfig: false,
});
return readProjectConfiguration(tree, 'my-plugin');
}
function updatePluginPackageJson(
tree: Tree,
packageJsonProps: Partial<PackageJson>
) {
const { root } = readProjectConfiguration(tree, 'my-plugin');
updateJson(tree, root + '/package.json', (json) => {
const base = { json, ...packageJsonProps };
for (const prop in base) {
if (base[prop] === null || base[prop] === undefined) {
delete json[prop];
}
}
return base;
});
}

View File

@ -1,177 +0,0 @@
import {
GeneratorsJson,
getProjects,
joinPathFragments,
MigrationsJson,
ExecutorsJson,
readJson,
Tree,
updateJson,
output,
} from '@nx/devkit';
import {
ExecutorsJsonEntry,
GeneratorsJsonEntry,
} from 'nx/src/config/misc-interfaces';
import { PackageJson, readNxMigrateConfig } from 'nx/src/utils/package-json';
import { dirname } from 'path';
export function updateCliPropsForPlugins(tree: Tree) {
const projects = getProjects(tree);
for (const project of projects.values()) {
if (tree.exists(joinPathFragments(project.root, 'package.json'))) {
const packageJson: PackageJson = readJson(
tree,
joinPathFragments(project.root, 'package.json')
);
const migrateConfig = readNxMigrateConfig(packageJson);
if (migrateConfig.migrations) {
const migrationsPath = joinPathFragments(
project.root,
migrateConfig.migrations
);
if (tree.exists(migrationsPath)) {
updateMigrationsJsonForPlugin(tree, migrationsPath);
} else {
output.warn({
title: `Migrations file specified for ${packageJson.name} does not exist: ${migrationsPath}`,
bodyLines: [
'Please ensure that migrations that use the Angular Devkit are placed inside the `schematics` property, and migrations that use the Nx Devkit are placed inside the `generators` property.',
],
});
}
}
if (packageJson.generators) {
const generatorsPath = joinPathFragments(
project.root,
packageJson.generators
);
if (tree.exists(generatorsPath)) {
removeCliFromGeneratorSchemaJsonFiles(tree, generatorsPath);
} else {
output.warn({
title: `Generators file specified for ${packageJson.name} does not exist: ${generatorsPath}`,
bodyLines: [
"The `cli` property inside generator's `schema.json` files is no longer supported.",
],
});
}
}
if (packageJson.executors) {
const executorsPath = joinPathFragments(
project.root,
packageJson.executors
);
if (tree.exists(executorsPath)) {
removeCliFromExecutorSchemaJsonFiles(tree, executorsPath);
} else {
output.warn({
title: `Executors file specified for ${packageJson.name} does not exist: ${executorsPath}`,
bodyLines: [
"The `cli` property inside executor's `schema.json` files is no longer supported.",
],
});
}
}
if (packageJson.builders) {
const buildersPath = joinPathFragments(
project.root,
packageJson.builders
);
if (tree.exists(buildersPath)) {
removeCliFromExecutorSchemaJsonFiles(tree, buildersPath);
} else {
output.warn({
title: `Builders file specified for ${packageJson.name} does not exist: ${buildersPath}`,
bodyLines: [
"The `cli` property inside builder's `schema.json` files is no longer supported.",
],
});
}
}
if (packageJson.schematics) {
const schematicsPath = joinPathFragments(
project.root,
packageJson.schematics
);
if (tree.exists(schematicsPath)) {
removeCliFromGeneratorSchemaJsonFiles(tree, schematicsPath);
} else {
output.warn({
title: `Schematics file specified for ${packageJson.name} does not exist: ${schematicsPath}`,
bodyLines: [
"The `cli` property inside schematic's `schema.json` files is no longer supported.",
],
});
}
}
}
}
}
function removeCliFromExecutorSchemaJsonFiles(
tree: Tree,
collectionPath: string
) {
const collection: ExecutorsJson = readJson(tree, collectionPath);
for (const [name, entry] of Object.entries(collection.executors ?? {}).concat(
Object.entries(collection.builders ?? {})
)) {
deleteCliPropFromSchemaFile(collectionPath, entry, tree);
}
}
function removeCliFromGeneratorSchemaJsonFiles(
tree: Tree,
collectionPath: string
) {
const collection: GeneratorsJson = readJson(tree, collectionPath);
for (const [name, entry] of Object.entries(
collection.generators ?? {}
).concat(Object.entries(collection.schematics ?? {}))) {
deleteCliPropFromSchemaFile(collectionPath, entry, tree);
}
}
function updateMigrationsJsonForPlugin(tree: Tree, collectionPath: string) {
updateJson<MigrationsJson>(tree, collectionPath, (json) => {
for (const migration in json.generators ?? {}) {
if (!(json.generators[migration].cli === 'nx')) {
json.schematics ??= {};
json.schematics[migration] = json.generators[migration];
delete json.generators[migration];
}
}
for (const migration in json.schematics ?? {}) {
if (json.schematics[migration].cli === 'nx') {
json.generators ??= {};
json.generators[migration] = json.schematics[migration];
delete json.schematics[migration];
}
}
return json;
});
}
export default updateCliPropsForPlugins;
function deleteCliPropFromSchemaFile(
collectionPath: string,
entry: ExecutorsJsonEntry | GeneratorsJsonEntry,
tree: Tree
) {
if (typeof entry === 'string' || !entry.schema) {
return;
}
const schemaPath = joinPathFragments(dirname(collectionPath), entry.schema);
if (tree.exists(schemaPath)) {
updateJson(tree, schemaPath, (json) => {
if (json.cli) {
delete json.cli;
}
return json;
});
} else {
console.warn(`Could not find schema file ${schemaPath}`);
}
}

Some files were not shown because too many files have changed in this diff Show More