Skip to content

Commit 89a990f

Browse files
fix(components/packages): remove package before installing it to prevent duplicates (#839)
1 parent 71069cd commit 89a990f

File tree

5 files changed

+100
-84
lines changed

5 files changed

+100
-84
lines changed

libs/components/packages/src/schematics/migrations/update-7/add-autonumeric-dependency.spec.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,33 @@ describe('Migrations > Add autonumeric as a dependency', () => {
5151

5252
expect(tree.readJson('/package.json')).toEqual({});
5353
});
54+
55+
it('should force-install autonumeric in dependencies', async () => {
56+
const { runSchematic, tree } = await setupTest();
57+
58+
// Add autonumeric to both dependencies and devDependencies.
59+
tree.overwrite(
60+
'/package.json',
61+
JSON.stringify({
62+
dependencies: {
63+
'@skyux/autonumeric': '*',
64+
autonumeric: '*',
65+
},
66+
devDependencies: {
67+
autonumeric: '*',
68+
},
69+
})
70+
);
71+
72+
await runSchematic();
73+
74+
// The version listed in devDependencies should be removed.
75+
expect(tree.readJson('/package.json')).toEqual({
76+
dependencies: {
77+
'@skyux/autonumeric': '*',
78+
autonumeric: '4.6.0',
79+
},
80+
devDependencies: {},
81+
});
82+
});
5483
});
Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,10 @@
11
import { Rule } from '@angular-devkit/schematics';
2-
import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
3-
import {
4-
NodeDependencyType,
5-
addPackageJsonDependency,
6-
} from '@schematics/angular/utility/dependencies';
2+
import { NodeDependencyType } from '@schematics/angular/utility/dependencies';
73

8-
import { readRequiredFile } from '../../utility/tree';
4+
import { ensurePeersInstalled } from '../../rules/ensure-peers-installed';
95

106
export default function (): Rule {
11-
return async (tree, context) => {
12-
const packageJson: {
13-
dependencies?: Record<string, string>;
14-
devDependencies?: Record<string, string>;
15-
} = JSON.parse(readRequiredFile(tree, '/package.json'));
16-
17-
const dependencies: Record<string, string> = {
18-
...(packageJson.dependencies || {}),
19-
...(packageJson.devDependencies || {}),
20-
};
21-
22-
if (dependencies['@skyux/autonumeric']) {
23-
context.addTask(new NodePackageInstallTask());
24-
25-
addPackageJsonDependency(tree, {
26-
type: NodeDependencyType.Default,
27-
name: 'autonumeric',
28-
version: '4.6.0',
29-
overwrite: false,
30-
});
31-
}
32-
};
7+
return ensurePeersInstalled('@skyux/autonumeric', [
8+
{ name: 'autonumeric', version: '4.6.0', type: NodeDependencyType.Default },
9+
]);
3310
}
Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,10 @@
11
import { Rule } from '@angular-devkit/schematics';
2-
import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
3-
import {
4-
NodeDependencyType,
5-
addPackageJsonDependency,
6-
} from '@schematics/angular/utility/dependencies';
2+
import { NodeDependencyType } from '@schematics/angular/utility/dependencies';
73

8-
import { readRequiredFile } from '../../utility/tree';
4+
import { ensurePeersInstalled } from '../../rules/ensure-peers-installed';
95

106
export default function (): Rule {
11-
return async (tree, context) => {
12-
const packageJson: {
13-
dependencies?: Record<string, string>;
14-
devDependencies?: Record<string, string>;
15-
} = JSON.parse(readRequiredFile(tree, '/package.json'));
16-
17-
const dependencies: Record<string, string> = {
18-
...(packageJson.dependencies || {}),
19-
...(packageJson.devDependencies || {}),
20-
};
21-
22-
if (dependencies['@skyux-sdk/testing']) {
23-
context.addTask(new NodePackageInstallTask());
24-
25-
addPackageJsonDependency(tree, {
26-
type: NodeDependencyType.Dev,
27-
name: 'axe-core',
28-
version: '3.5.6',
29-
overwrite: false,
30-
});
31-
}
32-
};
7+
return ensurePeersInstalled('@skyux-sdk/testing', [
8+
{ name: 'axe-core', version: '3.5.6', type: NodeDependencyType.Dev },
9+
]);
3310
}
Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,10 @@
11
import { Rule } from '@angular-devkit/schematics';
2-
import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
3-
import {
4-
NodeDependencyType,
5-
addPackageJsonDependency,
6-
} from '@schematics/angular/utility/dependencies';
2+
import { NodeDependencyType } from '@schematics/angular/utility/dependencies';
73

8-
import { readRequiredFile } from '../../utility/tree';
4+
import { ensurePeersInstalled } from '../../rules/ensure-peers-installed';
95

106
export default function (): Rule {
11-
return async (tree, context) => {
12-
const packageJson: {
13-
dependencies?: Record<string, string>;
14-
devDependencies?: Record<string, string>;
15-
} = JSON.parse(readRequiredFile(tree, '/package.json'));
16-
17-
const dependencies: Record<string, string> = {
18-
...(packageJson.dependencies || {}),
19-
...(packageJson.devDependencies || {}),
20-
};
21-
22-
if (dependencies['@skyux/datetime']) {
23-
context.addTask(new NodePackageInstallTask());
24-
25-
addPackageJsonDependency(tree, {
26-
type: NodeDependencyType.Default,
27-
name: 'moment',
28-
version: '2.29.4',
29-
overwrite: false,
30-
});
31-
}
32-
};
7+
return ensurePeersInstalled('@skyux/datetime', [
8+
{ name: 'moment', version: '2.29.4', type: NodeDependencyType.Default },
9+
]);
3310
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { Rule } from '@angular-devkit/schematics';
2+
import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
3+
import {
4+
NodeDependencyType,
5+
addPackageJsonDependency,
6+
removePackageJsonDependency,
7+
} from '@schematics/angular/utility/dependencies';
8+
9+
import { readRequiredFile } from '../utility/tree';
10+
11+
type PackageDetails = {
12+
name: string;
13+
version: string;
14+
type: NodeDependencyType;
15+
};
16+
17+
function installPackages(packages: PackageDetails[]): Rule {
18+
return (tree, context) => {
19+
for (const details of packages) {
20+
// Remove the package (if it exists) so we can ensure it's added to the appropriate section.
21+
removePackageJsonDependency(tree, details.name, '/package.json');
22+
addPackageJsonDependency(tree, {
23+
type: details.type,
24+
name: details.name,
25+
version: details.version,
26+
});
27+
}
28+
29+
context.addTask(new NodePackageInstallTask());
30+
};
31+
}
32+
33+
/**
34+
* Ensures peer dependencies for a given package are installed on the client's workspace.
35+
* If the client does not use the target package, this function is skipped.
36+
* @param targetPackageName The name of the package that has peer dependencies.
37+
* @param peers The target package's peer dependencies to install on the client's workspace.
38+
*/
39+
export function ensurePeersInstalled(
40+
targetPackageName: string,
41+
peers: PackageDetails[]
42+
): Rule {
43+
return (tree) => {
44+
const packageJson: {
45+
dependencies?: Record<string, string>;
46+
devDependencies?: Record<string, string>;
47+
} = JSON.parse(readRequiredFile(tree, '/package.json'));
48+
49+
const dependencies: Record<string, string> = {
50+
...(packageJson.dependencies || {}),
51+
...(packageJson.devDependencies || {}),
52+
};
53+
54+
return dependencies[targetPackageName] ? installPackages(peers) : undefined;
55+
};
56+
}

0 commit comments

Comments
 (0)