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
  • Loading branch information
jaysoo committed Jan 16, 2024
1 parent 9747eea commit 8f60b29
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 20 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

0 comments on commit 8f60b29

Please sign in to comment.