@teambit/dependency-resolver 1.0.106 → 1.0.108

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/apply-updates.spec.ts +215 -0
  2. package/apply-updates.ts +81 -0
  3. package/dependency-detector.ts +5 -0
  4. package/dependency-env.ts +6 -0
  5. package/dependency-installer.ts +347 -0
  6. package/dependency-linker.ts +719 -0
  7. package/dependency-resolver.aspect.ts +7 -0
  8. package/dependency-resolver.graphql.ts +99 -0
  9. package/dependency-resolver.main.runtime.spec.ts +530 -0
  10. package/dependency-resolver.main.runtime.ts +1797 -0
  11. package/dependency-version-resolver.ts +42 -0
  12. package/dist/apply-updates.js +2 -4
  13. package/dist/apply-updates.js.map +1 -1
  14. package/dist/dependencies/base-dependency.d.ts +7 -7
  15. package/dist/dependencies/base-dependency.js +1 -2
  16. package/dist/dependencies/base-dependency.js.map +1 -1
  17. package/dist/dependencies/component-dependency/component-dependency.js +1 -2
  18. package/dist/dependencies/component-dependency/component-dependency.js.map +1 -1
  19. package/dist/dependencies/dependency-list-factory.js +2 -4
  20. package/dist/dependencies/dependency-list-factory.js.map +1 -1
  21. package/dist/dependencies/dependency-list.d.ts +2 -2
  22. package/dist/dependencies/dependency-list.js +1 -4
  23. package/dist/dependencies/dependency-list.js.map +1 -1
  24. package/dist/dependencies/dependency.d.ts +5 -5
  25. package/dist/dependencies.service.d.ts +4 -4
  26. package/dist/dependencies.service.js +3 -3
  27. package/dist/dependencies.service.js.map +1 -1
  28. package/dist/dependency-installer.d.ts +10 -9
  29. package/dist/dependency-installer.js +5 -8
  30. package/dist/dependency-installer.js.map +1 -1
  31. package/dist/dependency-linker.d.ts +10 -9
  32. package/dist/dependency-linker.js +7 -11
  33. package/dist/dependency-linker.js.map +1 -1
  34. package/dist/dependency-resolver.composition.d.ts +2 -2
  35. package/dist/dependency-resolver.main.runtime.d.ts +15 -15
  36. package/dist/dependency-resolver.main.runtime.js +33 -39
  37. package/dist/dependency-resolver.main.runtime.js.map +1 -1
  38. package/dist/dependency-version-resolver.d.ts +2 -1
  39. package/dist/get-all-policy-pkgs.d.ts +4 -4
  40. package/dist/manifest/deduping/dedupe-dependencies.d.ts +4 -4
  41. package/dist/manifest/deduping/dedupe-dependencies.js +1 -1
  42. package/dist/manifest/deduping/dedupe-dependencies.js.map +1 -1
  43. package/dist/manifest/deduping/hoist-dependencies.js +2 -3
  44. package/dist/manifest/deduping/hoist-dependencies.js.map +1 -1
  45. package/dist/manifest/deduping/hoist-dependencies.spec.js +6 -8
  46. package/dist/manifest/deduping/hoist-dependencies.spec.js.map +1 -1
  47. package/dist/manifest/deduping/index-by-dep-id.d.ts +4 -4
  48. package/dist/manifest/deduping/index-by-dep-id.js +1 -2
  49. package/dist/manifest/deduping/index-by-dep-id.js.map +1 -1
  50. package/dist/manifest/manifest.d.ts +4 -4
  51. package/dist/manifest/update-dependency-version.js +2 -2
  52. package/dist/manifest/update-dependency-version.js.map +1 -1
  53. package/dist/manifest/workspace-manifest-factory.d.ts +3 -3
  54. package/dist/manifest/workspace-manifest-factory.js +3 -5
  55. package/dist/manifest/workspace-manifest-factory.js.map +1 -1
  56. package/dist/manifest/workspace-manifest.js +1 -2
  57. package/dist/manifest/workspace-manifest.js.map +1 -1
  58. package/dist/package-manager-legacy.d.ts +1 -1
  59. package/dist/package-manager.d.ts +5 -5
  60. package/dist/policy/env-policy/env-policy.d.ts +7 -7
  61. package/dist/policy/policy.d.ts +9 -9
  62. package/dist/policy/variant-policy/variant-policy.d.ts +9 -9
  63. package/dist/policy/workspace-policy/workspace-policy.d.ts +11 -11
  64. package/dist/{preview-1703505948637.js → preview-1703647408454.js} +2 -2
  65. package/dist/registry/registry.d.ts +6 -6
  66. package/dist/show-fragments/serialize-by-lifecycle.js +1 -2
  67. package/dist/show-fragments/serialize-by-lifecycle.js.map +1 -1
  68. package/dist/types.d.ts +8 -8
  69. package/extend-with-components-from-dir.ts +29 -0
  70. package/get-all-policy-pkgs.spec.ts +82 -0
  71. package/get-all-policy-pkgs.ts +126 -0
  72. package/index.ts +70 -0
  73. package/package-manager-legacy.ts +137 -0
  74. package/package-manager.ts +174 -0
  75. package/package.json +27 -34
  76. package/tsconfig.json +16 -21
  77. package/types/asset.d.ts +15 -3
  78. package/types.ts +77 -0
@@ -0,0 +1,215 @@
1
+ import { ComponentID } from '@teambit/component';
2
+ import { applyUpdates } from './apply-updates';
3
+
4
+ describe('applyUpdates()', () => {
5
+ it('should apply updates on root dependencies', () => {
6
+ const { updatedWorkspacePolicyEntries } = applyUpdates(
7
+ [
8
+ {
9
+ name: 'lodash',
10
+ latestRange: '2.0.0',
11
+ source: 'rootPolicy',
12
+ targetField: 'dependencies' as const,
13
+ },
14
+ {
15
+ name: 'react-dom',
16
+ latestRange: '2.0.0',
17
+ source: 'rootPolicy',
18
+ targetField: 'peerDependencies' as const,
19
+ },
20
+ ],
21
+ {
22
+ variantPoliciesByPatterns: {},
23
+ }
24
+ );
25
+ // @ts-ignore
26
+ expect(updatedWorkspacePolicyEntries).toStrictEqual(
27
+ [
28
+ {
29
+ dependencyId: 'lodash',
30
+ value: {
31
+ version: '2.0.0',
32
+ },
33
+ lifecycleType: 'runtime',
34
+ },
35
+ {
36
+ dependencyId: 'react-dom',
37
+ value: {
38
+ version: '2.0.0',
39
+ },
40
+ lifecycleType: 'peer',
41
+ },
42
+ ],
43
+ // @ts-ignore
44
+ { updateExisting: true }
45
+ );
46
+ });
47
+ it('should apply updates on variant dependencies', () => {
48
+ const variantPoliciesByPatterns = {
49
+ variant1: {
50
+ dependencies: {
51
+ 'variant1-runtime-dep1': { version: '1.0.0', resolveFromEnv: true },
52
+ 'variant1-runtime-dep2': '1.0.0',
53
+ },
54
+ devDependencies: {
55
+ 'variant1-dev-dep1': '1.0.0',
56
+ 'variant1-dev-dep2': '1.0.0',
57
+ },
58
+ peerDependencies: {
59
+ 'variant1-peer-dep1': '1.0.0',
60
+ 'variant1-peer-dep2': '1.0.0',
61
+ },
62
+ },
63
+ variant2: {
64
+ dependencies: {
65
+ 'variant2-runtime-dep1': '1.0.0',
66
+ 'variant2-runtime-dep2': '1.0.0',
67
+ },
68
+ devDependencies: {
69
+ 'variant2-dev-dep1': '1.0.0',
70
+ 'variant2-dev-dep2': '1.0.0',
71
+ },
72
+ peerDependencies: {
73
+ 'variant2-peer-dep1': '1.0.0',
74
+ 'variant2-peer-dep2': '1.0.0',
75
+ },
76
+ },
77
+ variant3: {
78
+ dependencies: {
79
+ 'variant3-runtime-dep1': '1.0.0',
80
+ 'variant3-runtime-dep2': '1.0.0',
81
+ },
82
+ devDependencies: {
83
+ 'variant3-dev-dep1': '1.0.0',
84
+ 'variant3-dev-dep2': '1.0.0',
85
+ },
86
+ peerDependencies: {
87
+ 'variant3-peer-dep1': '1.0.0',
88
+ 'variant3-peer-dep2': '1.0.0',
89
+ },
90
+ },
91
+ };
92
+ applyUpdates(
93
+ [
94
+ {
95
+ name: 'variant1-runtime-dep1',
96
+ latestRange: '2.0.0',
97
+ source: 'variants',
98
+ variantPattern: 'variant1',
99
+ targetField: 'dependencies',
100
+ },
101
+ {
102
+ name: 'variant2-dev-dep1',
103
+ latestRange: '2.0.0',
104
+ source: 'variants',
105
+ variantPattern: 'variant2',
106
+ targetField: 'devDependencies',
107
+ },
108
+ {
109
+ name: 'variant3-peer-dep1',
110
+ latestRange: '2.0.0',
111
+ source: 'variants',
112
+ variantPattern: 'variant3',
113
+ targetField: 'peerDependencies',
114
+ },
115
+ ],
116
+ {
117
+ variantPoliciesByPatterns,
118
+ }
119
+ );
120
+ // @ts-ignore
121
+ expect(variantPoliciesByPatterns.variant1).toStrictEqual({
122
+ dependencies: {
123
+ 'variant1-runtime-dep1': { version: '2.0.0', resolveFromEnv: true },
124
+ 'variant1-runtime-dep2': '1.0.0',
125
+ },
126
+ devDependencies: {
127
+ 'variant1-dev-dep1': '1.0.0',
128
+ 'variant1-dev-dep2': '1.0.0',
129
+ },
130
+ peerDependencies: {
131
+ 'variant1-peer-dep1': '1.0.0',
132
+ 'variant1-peer-dep2': '1.0.0',
133
+ },
134
+ });
135
+ // @ts-ignore
136
+ expect(variantPoliciesByPatterns.variant2).toStrictEqual({
137
+ dependencies: {
138
+ 'variant2-runtime-dep1': '1.0.0',
139
+ 'variant2-runtime-dep2': '1.0.0',
140
+ },
141
+ devDependencies: {
142
+ 'variant2-dev-dep1': '2.0.0',
143
+ 'variant2-dev-dep2': '1.0.0',
144
+ },
145
+ peerDependencies: {
146
+ 'variant2-peer-dep1': '1.0.0',
147
+ 'variant2-peer-dep2': '1.0.0',
148
+ },
149
+ });
150
+ // @ts-ignore
151
+ expect(variantPoliciesByPatterns.variant3).toStrictEqual({
152
+ dependencies: {
153
+ 'variant3-runtime-dep1': '1.0.0',
154
+ 'variant3-runtime-dep2': '1.0.0',
155
+ },
156
+ devDependencies: {
157
+ 'variant3-dev-dep1': '1.0.0',
158
+ 'variant3-dev-dep2': '1.0.0',
159
+ },
160
+ peerDependencies: {
161
+ 'variant3-peer-dep1': '2.0.0',
162
+ 'variant3-peer-dep2': '1.0.0',
163
+ },
164
+ });
165
+ });
166
+ it('should apply updates on component dependencies', () => {
167
+ const { updatedComponents } = applyUpdates(
168
+ [
169
+ {
170
+ name: 'component1-runtime-dep1',
171
+ latestRange: '2.0.0',
172
+ source: 'component',
173
+ componentId: ComponentID.fromString('scope/component1'),
174
+ targetField: 'dependencies',
175
+ },
176
+ {
177
+ name: 'component1-dev-dep1',
178
+ latestRange: '2.0.0',
179
+ source: 'component',
180
+ componentId: ComponentID.fromString('scope/component1'),
181
+ targetField: 'devDependencies',
182
+ },
183
+ {
184
+ name: 'component1-peer-dep1',
185
+ latestRange: '2.0.0',
186
+ source: 'component',
187
+ componentId: ComponentID.fromString('scope/component1'),
188
+ targetField: 'peerDependencies',
189
+ },
190
+ ],
191
+ {
192
+ variantPoliciesByPatterns: {},
193
+ }
194
+ );
195
+ // @ts-ignore
196
+ expect(updatedComponents).toStrictEqual([
197
+ {
198
+ componentId: ComponentID.fromString('scope/component1'),
199
+ config: {
200
+ policy: {
201
+ dependencies: {
202
+ 'component1-runtime-dep1': '2.0.0',
203
+ },
204
+ devDependencies: {
205
+ 'component1-dev-dep1': '2.0.0',
206
+ },
207
+ peerDependencies: {
208
+ 'component1-peer-dep1': '2.0.0',
209
+ },
210
+ },
211
+ },
212
+ },
213
+ ]);
214
+ });
215
+ });
@@ -0,0 +1,81 @@
1
+ import { ComponentID } from '@teambit/component';
2
+ import { MergedOutdatedPkg } from './dependency-resolver.main.runtime';
3
+ import { VariantPolicyConfigObject, WorkspacePolicyEntry } from './policy';
4
+
5
+ export interface UpdatedComponent {
6
+ componentId: ComponentID;
7
+ config: Record<string, any>;
8
+ }
9
+
10
+ /**
11
+ * Applies updates to policies.
12
+ */
13
+ export function applyUpdates(
14
+ outdatedPkgs: Array<Omit<MergedOutdatedPkg, 'currentRange'>>,
15
+ {
16
+ variantPoliciesByPatterns,
17
+ }: {
18
+ variantPoliciesByPatterns: Record<string, VariantPolicyConfigObject>;
19
+ }
20
+ ): {
21
+ updatedVariants: string[];
22
+ updatedComponents: UpdatedComponent[];
23
+ updatedWorkspacePolicyEntries: WorkspacePolicyEntry[];
24
+ } {
25
+ const updatedWorkspacePolicyEntries: WorkspacePolicyEntry[] = [];
26
+ const updatedVariants = new Set<string>();
27
+ const updatedComponents = new Map<string, UpdatedComponent>();
28
+
29
+ for (const outdatedPkg of outdatedPkgs) {
30
+ if (
31
+ outdatedPkg.source === 'component' ||
32
+ (outdatedPkg.source === 'rootPolicy' && outdatedPkg.dependentComponents?.length && !outdatedPkg.isAuto)
33
+ ) {
34
+ // eslint-disable-next-line
35
+ (outdatedPkg.dependentComponents ?? [outdatedPkg.componentId!]).forEach((componentId) => {
36
+ const id = componentId.toString();
37
+ if (!updatedComponents.has(id)) {
38
+ updatedComponents.set(id, { componentId, config: { policy: {} } });
39
+ }
40
+ const { config } = updatedComponents.get(id)!; // eslint-disable-line
41
+ if (!config.policy[outdatedPkg.targetField]) {
42
+ config.policy[outdatedPkg.targetField] = {};
43
+ }
44
+ config.policy[outdatedPkg.targetField][outdatedPkg.name] = outdatedPkg.latestRange;
45
+ });
46
+ } else {
47
+ switch (outdatedPkg.source) {
48
+ case 'rootPolicy':
49
+ case 'component-model':
50
+ updatedWorkspacePolicyEntries.push({
51
+ dependencyId: outdatedPkg.name,
52
+ value: {
53
+ version: outdatedPkg.latestRange,
54
+ },
55
+ lifecycleType: outdatedPkg.targetField === 'peerDependencies' ? 'peer' : 'runtime',
56
+ });
57
+ break;
58
+ case 'variants':
59
+ if (outdatedPkg.variantPattern) {
60
+ const { variantPattern, targetField, name } = outdatedPkg;
61
+ updatedVariants.add(outdatedPkg.variantPattern);
62
+ // eslint-disable-next-line dot-notation, @typescript-eslint/dot-notation
63
+ if (variantPoliciesByPatterns[variantPattern]?.[targetField]?.[name]?.['version']) {
64
+ // eslint-disable-line
65
+ variantPoliciesByPatterns[variantPattern][targetField]![name]['version'] = outdatedPkg.latestRange; // eslint-disable-line
66
+ } else {
67
+ variantPoliciesByPatterns[variantPattern][targetField]![name] = outdatedPkg.latestRange; // eslint-disable-line
68
+ }
69
+ }
70
+ break;
71
+ default:
72
+ throw new Error(`Unsupported policy source for update: ${outdatedPkg.source}`);
73
+ }
74
+ }
75
+ }
76
+ return {
77
+ updatedVariants: Array.from(updatedVariants),
78
+ updatedComponents: Array.from(updatedComponents.values()),
79
+ updatedWorkspacePolicyEntries,
80
+ };
81
+ }
@@ -0,0 +1,5 @@
1
+ export {
2
+ DetectorHook,
3
+ DependencyDetector,
4
+ FileContext,
5
+ } from '@teambit/legacy/dist/consumer/component/dependencies/files-dependency-builder/detector-hook';
@@ -0,0 +1,6 @@
1
+ import { EnvHandler } from '@teambit/envs';
2
+ import { DependencyDetector } from './dependency-detector';
3
+
4
+ export interface DependencyEnv {
5
+ detectors?(): EnvHandler<DependencyDetector[] | null>;
6
+ }
@@ -0,0 +1,347 @@
1
+ import mapSeries from 'p-map-series';
2
+ import path from 'path';
3
+ import fs from 'fs-extra';
4
+ import { MainAspect, AspectLoaderMain } from '@teambit/aspect-loader';
5
+ import { ComponentMap } from '@teambit/component';
6
+ import { CreateFromComponentsOptions, DependencyResolverMain } from '@teambit/dependency-resolver';
7
+ import { Logger } from '@teambit/logger';
8
+ import { PathAbsolute } from '@teambit/legacy/dist/utils/path';
9
+ import { PeerDependencyRules, ProjectManifest } from '@pnpm/types';
10
+ import { MainAspectNotInstallable, RootDirNotDefined } from './exceptions';
11
+ import { PackageManager, PackageManagerInstallOptions, PackageImportMethod } from './package-manager';
12
+ import { WorkspacePolicy } from './policy';
13
+
14
+ const DEFAULT_PM_INSTALL_OPTIONS: PackageManagerInstallOptions = {
15
+ dedupe: true,
16
+ copyPeerToRuntimeOnRoot: true,
17
+ copyPeerToRuntimeOnComponents: false,
18
+ installPeersFromEnvs: false,
19
+ };
20
+
21
+ const DEFAULT_INSTALL_OPTIONS: InstallOptions = {
22
+ installTeambitBit: false,
23
+ excludeExtensionsDependencies: false,
24
+ };
25
+
26
+ export type DepInstallerContext = {
27
+ inCapsule?: boolean;
28
+ };
29
+
30
+ export type InstallArgs = {
31
+ rootDir: string | undefined;
32
+ rootPolicy: WorkspacePolicy;
33
+ componentDirectoryMap: ComponentMap<string>;
34
+ options: InstallOptions;
35
+ packageManagerOptions: PackageManagerInstallOptions;
36
+ };
37
+
38
+ export type InstallOptions = {
39
+ installTeambitBit: boolean;
40
+ packageManagerConfigRootDir?: string;
41
+ resolveVersionsFromDependenciesOnly?: boolean;
42
+ linkedDependencies?: Record<string, Record<string, string>>;
43
+ forceTeambitHarmonyLink?: boolean;
44
+ excludeExtensionsDependencies?: boolean;
45
+ dedupeInjectedDeps?: boolean;
46
+ };
47
+
48
+ export type GetComponentManifestsOptions = {
49
+ componentDirectoryMap: ComponentMap<string>;
50
+ rootPolicy: WorkspacePolicy;
51
+ rootDir: string;
52
+ resolveVersionsFromDependenciesOnly?: boolean;
53
+ referenceLocalPackages?: boolean;
54
+ hasRootComponents?: boolean;
55
+ excludeExtensionsDependencies?: boolean;
56
+ } & Pick<
57
+ PackageManagerInstallOptions,
58
+ 'dedupe' | 'dependencyFilterFn' | 'copyPeerToRuntimeOnComponents' | 'copyPeerToRuntimeOnRoot' | 'installPeersFromEnvs'
59
+ >;
60
+
61
+ export type PreInstallSubscriber = (installer: DependencyInstaller, installArgs: InstallArgs) => Promise<void>;
62
+ export type PreInstallSubscriberList = Array<PreInstallSubscriber>;
63
+
64
+ export type PostInstallSubscriber = (installer: DependencyInstaller, installArgs: InstallArgs) => Promise<void>;
65
+ export type PostInstallSubscriberList = Array<PostInstallSubscriber>;
66
+
67
+ export class DependencyInstaller {
68
+ constructor(
69
+ /**
70
+ * package manager instance.
71
+ */
72
+ private packageManager: PackageManager,
73
+
74
+ private aspectLoader: AspectLoaderMain,
75
+
76
+ private logger: Logger,
77
+
78
+ private dependencyResolver: DependencyResolverMain,
79
+
80
+ private rootDir?: string | PathAbsolute,
81
+
82
+ private cacheRootDir?: string | PathAbsolute,
83
+
84
+ private preInstallSubscriberList?: PreInstallSubscriberList,
85
+
86
+ private postInstallSubscriberList?: PostInstallSubscriberList,
87
+
88
+ private nodeLinker?: 'hoisted' | 'isolated',
89
+
90
+ private packageImportMethod?: PackageImportMethod,
91
+
92
+ private sideEffectsCache?: boolean,
93
+
94
+ private nodeVersion?: string,
95
+
96
+ private engineStrict?: boolean,
97
+
98
+ private peerDependencyRules?: PeerDependencyRules,
99
+
100
+ private neverBuiltDependencies?: string[],
101
+
102
+ private preferOffline?: boolean,
103
+
104
+ private installingContext: DepInstallerContext = {}
105
+ ) {}
106
+
107
+ async install(
108
+ rootDir: string | undefined,
109
+ rootPolicy: WorkspacePolicy,
110
+ componentDirectoryMap: ComponentMap<string>,
111
+ options: InstallOptions = DEFAULT_INSTALL_OPTIONS,
112
+ packageManagerOptions: PackageManagerInstallOptions = DEFAULT_PM_INSTALL_OPTIONS
113
+ ) {
114
+ const finalRootDir = rootDir ?? this.rootDir;
115
+ if (!finalRootDir) {
116
+ throw new RootDirNotDefined();
117
+ }
118
+ const manifests = await this.getComponentManifests({
119
+ ...packageManagerOptions,
120
+ componentDirectoryMap,
121
+ rootPolicy,
122
+ rootDir: finalRootDir,
123
+ resolveVersionsFromDependenciesOnly: options.resolveVersionsFromDependenciesOnly,
124
+ referenceLocalPackages: packageManagerOptions.rootComponentsForCapsules,
125
+ excludeExtensionsDependencies: options.excludeExtensionsDependencies,
126
+ });
127
+ return this.installComponents(
128
+ finalRootDir,
129
+ manifests,
130
+ rootPolicy,
131
+ componentDirectoryMap,
132
+ options,
133
+ packageManagerOptions
134
+ );
135
+ }
136
+
137
+ async installComponents(
138
+ rootDir: string | undefined,
139
+ manifests: Record<string, ProjectManifest>,
140
+ rootPolicy: WorkspacePolicy,
141
+ componentDirectoryMap: ComponentMap<string>,
142
+ options: InstallOptions = DEFAULT_INSTALL_OPTIONS,
143
+ packageManagerOptions: PackageManagerInstallOptions = DEFAULT_PM_INSTALL_OPTIONS
144
+ ): Promise<{ dependenciesChanged: boolean }> {
145
+ const args = {
146
+ componentDirectoryMap,
147
+ options,
148
+ packageManagerOptions,
149
+ rootDir,
150
+ rootPolicy,
151
+ };
152
+ await this.runPrePostSubscribers(this.preInstallSubscriberList, 'pre', args);
153
+ const mainAspect: MainAspect = this.aspectLoader.mainAspect;
154
+ const finalRootDir = rootDir || this.rootDir;
155
+ if (!finalRootDir) {
156
+ throw new RootDirNotDefined();
157
+ }
158
+ if (options.linkedDependencies) {
159
+ manifests = JSON.parse(JSON.stringify(manifests));
160
+ const linkedDependencies = JSON.parse(
161
+ JSON.stringify(options.linkedDependencies)
162
+ ) as typeof options.linkedDependencies;
163
+ if (linkedDependencies[finalRootDir]) {
164
+ const directDeps = new Set<string>();
165
+ Object.values(manifests).forEach((manifest) => {
166
+ for (const depName of Object.keys({ ...manifest.dependencies, ...manifest.devDependencies })) {
167
+ directDeps.add(depName);
168
+ }
169
+ });
170
+ for (const manifest of Object.values(manifests)) {
171
+ if (manifest.name && directDeps.has(manifest.name)) {
172
+ delete linkedDependencies[finalRootDir][manifest.name];
173
+ }
174
+ }
175
+ if (options.forceTeambitHarmonyLink && manifests[finalRootDir].dependencies?.['@teambit/harmony']) {
176
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
177
+ delete manifests[finalRootDir].dependencies!['@teambit/harmony'];
178
+ }
179
+ }
180
+ Object.entries(linkedDependencies).forEach(([dir, linkedDeps]) => {
181
+ if (!manifests[dir]) {
182
+ manifests[dir] = {};
183
+ }
184
+ manifests[dir].dependencies = {
185
+ ...linkedDeps,
186
+ ...manifests[dir].dependencies,
187
+ };
188
+ });
189
+ }
190
+ const hidePackageManagerOutput = !!(this.installingContext.inCapsule && process.env.VERBOSE_PM_OUTPUT !== 'true');
191
+
192
+ // Make sure to take other default if passed options with only one option
193
+ const calculatedPmOpts = {
194
+ ...DEFAULT_PM_INSTALL_OPTIONS,
195
+ cacheRootDir: this.cacheRootDir,
196
+ nodeLinker: this.nodeLinker,
197
+ packageImportMethod: this.packageImportMethod,
198
+ sideEffectsCache: this.sideEffectsCache,
199
+ nodeVersion: this.nodeVersion,
200
+ engineStrict: this.engineStrict,
201
+ packageManagerConfigRootDir: options.packageManagerConfigRootDir,
202
+ peerDependencyRules: this.peerDependencyRules,
203
+ hidePackageManagerOutput,
204
+ neverBuiltDependencies: ['core-js', ...(this.neverBuiltDependencies ?? [])],
205
+ preferOffline: this.preferOffline,
206
+ dedupeInjectedDeps: options.dedupeInjectedDeps,
207
+ ...packageManagerOptions,
208
+ };
209
+ if (options.installTeambitBit) {
210
+ if (!mainAspect.version || !mainAspect.packageName) {
211
+ throw new MainAspectNotInstallable();
212
+ }
213
+ const version = mainAspect.version;
214
+ rootPolicy.add({
215
+ dependencyId: mainAspect.packageName,
216
+ lifecycleType: 'runtime',
217
+ value: {
218
+ version,
219
+ },
220
+ });
221
+ }
222
+
223
+ if (!packageManagerOptions.rootComponents && !packageManagerOptions.keepExistingModulesDir) {
224
+ // Remove node modules dir for all components dirs, since it might contain left overs from previous install.
225
+ //
226
+ // This is not needed when "rootComponents" are used, as in that case the package manager handles the node_modules
227
+ // and it never leaves node_modules in a broken state.
228
+ // Removing node_modules in that case would delete useful state information that is used by Yarn or pnpm.
229
+ await this.cleanCompsNodeModules(componentDirectoryMap);
230
+ }
231
+
232
+ const messagePrefix = 'running package installation';
233
+ const messageSuffix = `using ${this.packageManager.name}`;
234
+ const message = this.installingContext?.inCapsule
235
+ ? `(capsule) ${messagePrefix} in root dir ${this.rootDir} ${messageSuffix}`
236
+ : `${messagePrefix} ${messageSuffix}`;
237
+ if (!hidePackageManagerOutput) {
238
+ this.logger.setStatusLine(message);
239
+ }
240
+ const startTime = process.hrtime();
241
+
242
+ // TODO: the cache should be probably passed to the package manager constructor not to the install function
243
+ const installResult = await this.packageManager.install(
244
+ {
245
+ rootDir: finalRootDir,
246
+ manifests,
247
+ componentDirectoryMap,
248
+ },
249
+ calculatedPmOpts
250
+ );
251
+ if (!hidePackageManagerOutput) {
252
+ this.logger.consoleSuccess(`done ${message}`, startTime);
253
+ }
254
+ await this.runPrePostSubscribers(this.postInstallSubscriberList, 'post', args);
255
+ return installResult;
256
+ }
257
+
258
+ public async pruneModules(rootDir: string): Promise<void> {
259
+ if (!this.packageManager.pruneModules) {
260
+ return;
261
+ }
262
+ await this.packageManager.pruneModules(rootDir);
263
+ }
264
+
265
+ /**
266
+ * Compute all the component manifests (a.k.a. package.json files) that should be passed to the package manager
267
+ * in order to install the dependencies.
268
+ */
269
+ public async getComponentManifests({
270
+ componentDirectoryMap,
271
+ rootPolicy,
272
+ rootDir,
273
+ dedupe,
274
+ dependencyFilterFn,
275
+ copyPeerToRuntimeOnComponents,
276
+ copyPeerToRuntimeOnRoot,
277
+ installPeersFromEnvs,
278
+ resolveVersionsFromDependenciesOnly,
279
+ referenceLocalPackages,
280
+ hasRootComponents,
281
+ excludeExtensionsDependencies,
282
+ }: GetComponentManifestsOptions) {
283
+ const options: CreateFromComponentsOptions = {
284
+ filterComponentsFromManifests: true,
285
+ createManifestForComponentsWithoutDependencies: true,
286
+ dedupe,
287
+ dependencyFilterFn,
288
+ resolveVersionsFromDependenciesOnly,
289
+ referenceLocalPackages,
290
+ hasRootComponents,
291
+ excludeExtensionsDependencies,
292
+ };
293
+ const workspaceManifest = await this.dependencyResolver.getWorkspaceManifest(
294
+ undefined,
295
+ undefined,
296
+ rootPolicy,
297
+ rootDir,
298
+ componentDirectoryMap.components,
299
+ options,
300
+ this.installingContext
301
+ );
302
+ const manifests: Record<string, ProjectManifest> = componentDirectoryMap
303
+ .toArray()
304
+ .reduce((acc, [component, dir]) => {
305
+ const packageName = this.dependencyResolver.getPackageName(component);
306
+ const manifest = workspaceManifest.componentsManifestsMap.get(packageName);
307
+ if (manifest) {
308
+ acc[dir] = manifest.toJson({ copyPeerToRuntime: copyPeerToRuntimeOnComponents });
309
+ }
310
+ return acc;
311
+ }, {});
312
+ if (!manifests[rootDir]) {
313
+ manifests[rootDir] = workspaceManifest.toJson({
314
+ copyPeerToRuntime: copyPeerToRuntimeOnRoot,
315
+ installPeersFromEnvs,
316
+ });
317
+ }
318
+ return manifests;
319
+ }
320
+
321
+ private async cleanCompsNodeModules(componentDirectoryMap: ComponentMap<string>) {
322
+ const promises = componentDirectoryMap.toArray().map(([, dir]) => {
323
+ const nmDir = path.join(dir, 'node_modules');
324
+ return fs.remove(nmDir);
325
+ });
326
+ return Promise.all(promises);
327
+ }
328
+
329
+ private async runPrePostSubscribers(
330
+ subscribers: PreInstallSubscriberList | PostInstallSubscriberList = [],
331
+ type: 'pre' | 'post',
332
+ args: InstallArgs
333
+ ): Promise<void> {
334
+ const message = this.installingContext?.inCapsule
335
+ ? `(capsule) running ${type} install subscribers in root dir ${this.rootDir}`
336
+ : `running ${type} install subscribers`;
337
+ if (!this.installingContext?.inCapsule) {
338
+ this.logger.setStatusLine(message);
339
+ }
340
+ await mapSeries(subscribers, async (subscriber) => {
341
+ return subscriber(this, args);
342
+ });
343
+ if (!this.installingContext?.inCapsule) {
344
+ this.logger.consoleSuccess(message);
345
+ }
346
+ }
347
+ }