From 253c0ff2ab1060dd36d9bc405c9672d0b4938ed1 Mon Sep 17 00:00:00 2001 From: Jack Hsu Date: Tue, 16 Jan 2024 14:24:14 -0500 Subject: [PATCH] feat(devkit): add a flag to keep existing versions when calling addDependenciesToPackageJson (#21123) --- .../devkit/addDependenciesToPackageJson.md | 15 +++--- .../devkit/src/utils/package-json.spec.ts | 23 ++++++++ packages/devkit/src/utils/package-json.ts | 52 ++++++++++++++----- .../convert-to-monorepo.spec.ts | 2 +- .../generators/move/lib/move-project-files.ts | 2 +- 5 files changed, 72 insertions(+), 22 deletions(-) diff --git a/docs/generated/devkit/addDependenciesToPackageJson.md b/docs/generated/devkit/addDependenciesToPackageJson.md index 5e13d71a7a710..d881ee458edf5 100644 --- a/docs/generated/devkit/addDependenciesToPackageJson.md +++ b/docs/generated/devkit/addDependenciesToPackageJson.md @@ -1,6 +1,6 @@ # Function: addDependenciesToPackageJson -▸ **addDependenciesToPackageJson**(`tree`, `dependencies`, `devDependencies`, `packageJsonPath?`): [`GeneratorCallback`](../../devkit/documents/GeneratorCallback) +▸ **addDependenciesToPackageJson**(`tree`, `dependencies`, `devDependencies`, `packageJsonPath?`, `keepExistingVersions?`): [`GeneratorCallback`](../../devkit/documents/GeneratorCallback) Add Dependencies and Dev Dependencies to package.json @@ -14,12 +14,13 @@ This will **add** `react` and `jest` to the dependencies and devDependencies sec #### Parameters -| Name | Type | Description | -| :----------------- | :------------------------------------ | :---------------------------------------------------------------------- | -| `tree` | [`Tree`](../../devkit/documents/Tree) | Tree representing file system to modify | -| `dependencies` | `Record`\<`string`, `string`\> | Dependencies to be added to the dependencies section of package.json | -| `devDependencies` | `Record`\<`string`, `string`\> | Dependencies to be added to the devDependencies section of package.json | -| `packageJsonPath?` | `string` | Path to package.json | +| Name | Type | Description | +| :---------------------- | :------------------------------------ | :-------------------------------------------------------------------------- | +| `tree` | [`Tree`](../../devkit/documents/Tree) | Tree representing file system to modify | +| `dependencies` | `Record`\<`string`, `string`\> | Dependencies to be added to the dependencies section of package.json | +| `devDependencies` | `Record`\<`string`, `string`\> | Dependencies to be added to the devDependencies section of package.json | +| `packageJsonPath?` | `string` | Path to package.json | +| `keepExistingVersions?` | `boolean` | If true, prevents existing dependencies from being bumped to newer versions | #### Returns diff --git a/packages/devkit/src/utils/package-json.spec.ts b/packages/devkit/src/utils/package-json.spec.ts index 607df2bec761a..2ec5f7d36cc07 100644 --- a/packages/devkit/src/utils/package-json.spec.ts +++ b/packages/devkit/src/utils/package-json.spec.ts @@ -446,6 +446,29 @@ describe('addDependenciesToPackageJson', () => { }); expect(installTask).toBeDefined(); }); + + it('should allow existing versions to be kept', () => { + writeJson(tree, 'package.json', { + dependencies: { + foo: '1.0.0', + }, + }); + + addDependenciesToPackageJson( + tree, + { + foo: '2.0.0', + }, + {}, + undefined, + true + ); + + const result = readJson(tree, 'package.json'); + expect(result.dependencies).toEqual({ + foo: '1.0.0', + }); + }); }); describe('ensurePackage', () => { diff --git a/packages/devkit/src/utils/package-json.ts b/packages/devkit/src/utils/package-json.ts index 0a2f7d4d55003..77811b0eb7237 100644 --- a/packages/devkit/src/utils/package-json.ts +++ b/packages/devkit/src/utils/package-json.ts @@ -132,13 +132,15 @@ function updateExistingDependenciesVersion( * @param dependencies Dependencies to be added to the dependencies section of package.json * @param devDependencies Dependencies to be added to the devDependencies section of package.json * @param packageJsonPath Path to package.json + * @param keepExistingVersions If true, prevents existing dependencies from being bumped to newer versions * @returns Callback to install dependencies only if necessary, no-op otherwise */ export function addDependenciesToPackageJson( tree: Tree, dependencies: Record, devDependencies: Record, - packageJsonPath: string = 'package.json' + packageJsonPath: string = 'package.json', + keepExistingVersions?: boolean ): GeneratorCallback { const currentPackageJson = readJson(tree, packageJsonPath); @@ -155,6 +157,7 @@ export function addDependenciesToPackageJson( // filtered dependencies should consist of: // - dependencies of the same type that are not present + // by default, filtered dependencies also include these (unless keepExistingVersions is true): // - dependencies of the same type that have greater version // - specified dependencies of the other type that have greater version and are already installed as current type filteredDependencies = { @@ -178,14 +181,25 @@ export function addDependenciesToPackageJson( ), }; - filteredDependencies = removeLowerVersions( - filteredDependencies, - currentPackageJson.dependencies - ); - filteredDevDependencies = removeLowerVersions( - filteredDevDependencies, - currentPackageJson.devDependencies - ); + if (keepExistingVersions) { + filteredDependencies = removeExistingDependencies( + filteredDependencies, + currentPackageJson.dependencies + ); + filteredDevDependencies = removeExistingDependencies( + filteredDevDependencies, + currentPackageJson.devDependencies + ); + } else { + filteredDependencies = removeLowerVersions( + filteredDependencies, + currentPackageJson.dependencies + ); + filteredDevDependencies = removeLowerVersions( + filteredDevDependencies, + currentPackageJson.devDependencies + ); + } if ( requiresAddingOfPackages( @@ -227,12 +241,24 @@ function removeLowerVersions( ) { return Object.keys(incomingDeps).reduce((acc, d) => { if ( - existingDeps?.[d] && - !isIncomingVersionGreater(incomingDeps[d], existingDeps[d]) + !existingDeps?.[d] || + isIncomingVersionGreater(incomingDeps[d], existingDeps[d]) ) { - return acc; + acc[d] = incomingDeps[d]; + } + return acc; + }, {}); +} + +function removeExistingDependencies( + incomingDeps: Record, + existingDeps: Record +): Record { + return Object.keys(incomingDeps).reduce((acc, d) => { + if (!existingDeps?.[d]) { + acc[d] = incomingDeps[d]; } - return { ...acc, [d]: incomingDeps[d] }; + return acc; }, {}); } diff --git a/packages/workspace/src/generators/convert-to-monorepo/convert-to-monorepo.spec.ts b/packages/workspace/src/generators/convert-to-monorepo/convert-to-monorepo.spec.ts index 78653e9a83a99..2420df4db2370 100644 --- a/packages/workspace/src/generators/convert-to-monorepo/convert-to-monorepo.spec.ts +++ b/packages/workspace/src/generators/convert-to-monorepo/convert-to-monorepo.spec.ts @@ -129,6 +129,6 @@ describe('monorepo generator', () => { // Extracted base config files expect(tree.exists('tsconfig.base.json')).toBeTruthy(); - expect(tree.exists('jest.config.ts')).toBeTruthy(); + expect(tree.exists('jest.preset.js')).toBeTruthy(); }); }); diff --git a/packages/workspace/src/generators/move/lib/move-project-files.ts b/packages/workspace/src/generators/move/lib/move-project-files.ts index e10c0ca640f64..70c6ebcd01394 100644 --- a/packages/workspace/src/generators/move/lib/move-project-files.ts +++ b/packages/workspace/src/generators/move/lib/move-project-files.ts @@ -25,7 +25,7 @@ export function moveProjectFiles( '.babelrc', '.eslintrc.json', 'eslint.config.js', - /^jest\.config\.(app|lib)\.[jt]s$/, + /^jest\.config\.((app|lib)\.)?[jt]s$/, 'vite.config.ts', /^webpack.*\.js$/, 'index.html', // Vite