Skip to content

Commit

Permalink
feat(devkit): add a flag to keep existing versions when calling addDe…
Browse files Browse the repository at this point in the history
…pendenciesToPackageJson (#21123)
  • Loading branch information
jaysoo authored Jan 16, 2024
1 parent f024923 commit 253c0ff
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 22 deletions.
15 changes: 8 additions & 7 deletions docs/generated/devkit/addDependenciesToPackageJson.md
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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

Expand Down
23 changes: 23 additions & 0 deletions packages/devkit/src/utils/package-json.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down
52 changes: 39 additions & 13 deletions packages/devkit/src/utils/package-json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, string>,
devDependencies: Record<string, string>,
packageJsonPath: string = 'package.json'
packageJsonPath: string = 'package.json',
keepExistingVersions?: boolean
): GeneratorCallback {
const currentPackageJson = readJson(tree, packageJsonPath);

Expand All @@ -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 = {
Expand All @@ -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(
Expand Down Expand Up @@ -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<string, string>,
existingDeps: Record<string, string>
): Record<string, string> {
return Object.keys(incomingDeps).reduce((acc, d) => {
if (!existingDeps?.[d]) {
acc[d] = incomingDeps[d];
}
return { ...acc, [d]: incomingDeps[d] };
return acc;
}, {});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

1 comment on commit 253c0ff

@vercel
Copy link

@vercel vercel bot commented on 253c0ff Jan 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

nx-dev – ./

nx-dev-nrwl.vercel.app
nx-five.vercel.app
nx-dev-git-master-nrwl.vercel.app
nx.dev

Please sign in to comment.