@teambit/dependencies 1.0.1271 → 1.0.1273

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.
@@ -23,7 +23,7 @@ import { ComponentOverrides } from '@teambit/legacy.consumer-config';
23
23
  import OverridesDependencies from './overrides-dependencies';
24
24
  import { DependenciesData } from './dependencies-data';
25
25
  import type { DebugDependencies, FileType } from './auto-detect-deps';
26
- import { getValidComponentVersion } from './auto-detect-deps';
26
+ import { getValidComponentVersion, getVersionInRangeIfOutOfIt } from './auto-detect-deps';
27
27
 
28
28
  export type AllDependencies = {
29
29
  dependencies: Dependency[];
@@ -343,21 +343,14 @@ export class ApplyOverrides {
343
343
  }
344
344
 
345
345
  /**
346
- * the scope side of the installed version in updateDependenciesVersions(): a workspace installs a component peer in
347
- * the range of the policy, and records the installed version. so when the version is out of the range, it's changed
348
- * to the version of the range. (when it's in the range, it's kept, as a workspace that has it installed would do)
346
+ * the scope side of peerVersionInRange() in updateDependenciesVersions(): when the version of a component peer is
347
+ * out of the range of the policy, it's changed to the version of the range. (when it's in the range, it's kept)
349
348
  */
350
349
  private setComponentPeerVersionInRange(dependency: Dependency, range: string) {
351
350
  if (!this.workspaceComponentIds || this.workspaceComponentIds.hasWithoutVersion(dependency.id)) return;
352
351
  const version = dependency.id.version;
353
- if (!version || !semver.validRange(range)) return;
354
- // a snap is not in any semver range, a workspace would install a version of the range instead
355
- if (semver.valid(version) && semver.satisfies(version, range)) return;
356
- const { version: versionInRange } = getValidComponentVersion(range);
357
- // e.g. "<2.0.0" is coerced to "2.0.0", which is out of the range. there's no version to take for such a range.
358
- if (versionInRange && semver.satisfies(versionInRange, range)) {
359
- dependency.id = dependency.id.changeVersion(versionInRange);
360
- }
352
+ const versionInRange = version ? getVersionInRangeIfOutOfIt(version, range) : undefined;
353
+ if (versionInRange) dependency.id = dependency.id.changeVersion(versionInRange);
361
354
  }
362
355
 
363
356
  private setVersionFromConfig(id: ComponentID) {
@@ -755,6 +755,18 @@ export class AutoDetectDeps {
755
755
  }
756
756
  }
757
757
 
758
+ /**
759
+ * a policy (e.g. an env) can set the range of a component peer. a version that satisfies the range is kept, so this
760
+ * returns undefined. otherwise, it returns the version of the range (a snap is not in any semver range).
761
+ * it returns undefined also when the range has no such version, e.g. "<2.0.0" is coerced to "2.0.0".
762
+ */
763
+ export function getVersionInRangeIfOutOfIt(version: string, range: string): string | undefined {
764
+ if (!semver.validRange(range)) return undefined;
765
+ if (semver.valid(version) && semver.satisfies(version, range)) return undefined;
766
+ const { version: versionInRange } = getValidComponentVersion(range);
767
+ return versionInRange && semver.satisfies(versionInRange, range) ? versionInRange : undefined;
768
+ }
769
+
758
770
  /**
759
771
  * this is not necessarily a valid semver version. in case of a snap, it returns the hash only, not a valid semver.
760
772
  * this is for the ComponentID.version.
@@ -0,0 +1,88 @@
1
+ import { expect } from 'chai';
2
+ import { ComponentID, ComponentIdList } from '@teambit/component-id';
3
+ import { Dependencies, Dependency } from '@teambit/legacy.consumer-component';
4
+ import type { DependencyResolverMain } from '@teambit/dependency-resolver';
5
+ import { updateDependenciesVersions } from './dependencies-versions-resolver';
6
+
7
+ const linkPkg = '@my-scope/navigation.link';
8
+ const linkId = ComponentID.fromString('my-scope/navigation/link');
9
+
10
+ /**
11
+ * a component with a component peer that its env sets with a range (the range is set before, by ApplyOverrides).
12
+ * the last snap of the component has the peer in version 2.0.1.
13
+ */
14
+ async function resolvePeerVersion({
15
+ range,
16
+ inBitmap = false,
17
+ forced,
18
+ workspacePolicy,
19
+ debugDependencies,
20
+ }: {
21
+ range: string;
22
+ inBitmap?: boolean;
23
+ forced?: string;
24
+ workspacePolicy?: string;
25
+ debugDependencies?: any[];
26
+ }): Promise<string | undefined> {
27
+ const peer = new Dependency(linkId.changeVersion('2.0.1'), [], linkPkg, range);
28
+ const component: any = {
29
+ id: ComponentID.fromString('my-scope/card@0.0.1'),
30
+ dependencies: new Dependencies(),
31
+ devDependencies: new Dependencies(),
32
+ peerDependencies: new Dependencies([peer]),
33
+ overrides: { getComponentDependenciesWithVersion: () => ({}) },
34
+ componentFromModel: { getAllDependenciesIds: () => ComponentIdList.fromArray([linkId.changeVersion('2.0.1')]) },
35
+ };
36
+ const workspace: any = {
37
+ getAutoDetectConfigMerge: () => undefined,
38
+ getCurrentLaneObject: async () => undefined,
39
+ consumer: { bitmapIdsFromCurrentLane: ComponentIdList.fromArray(inBitmap ? [linkId.changeVersion('2.0.5')] : []) },
40
+ };
41
+ const depsResolver = {
42
+ calcComponentRangePrefixByConsumerComponent: () => (workspacePolicy ? '^' : undefined),
43
+ getWorkspacePolicyManifest: () => ({ dependencies: workspacePolicy ? { [linkPkg]: workspacePolicy } : {} }),
44
+ } as unknown as DependencyResolverMain;
45
+ const overridesDependencies: any = {
46
+ envOwnPkgNames: new Set(),
47
+ getDependenciesToAddManually: () => (forced ? { peerDependencies: { [linkPkg]: forced } } : undefined),
48
+ };
49
+ await updateDependenciesVersions(
50
+ depsResolver,
51
+ workspace,
52
+ component,
53
+ overridesDependencies,
54
+ undefined,
55
+ debugDependencies,
56
+ false
57
+ );
58
+ return component.peerDependencies.get()[0].id.version;
59
+ }
60
+
61
+ describe('updateDependenciesVersions, a component peer with a range from a policy', () => {
62
+ it('should take the version of the range when the version found is out of the range', async () => {
63
+ expect(await resolvePeerVersion({ range: '^2.0.3' })).to.equal('2.0.3');
64
+ });
65
+ it('should show the version of the range in the dependencies debug', async () => {
66
+ const debugDependencies = [{ id: linkId.changeVersion('2.0.1') }];
67
+ await resolvePeerVersion({ range: '^2.0.3', debugDependencies });
68
+ expect(debugDependencies[0]).to.include({
69
+ version: '2.0.3',
70
+ versionResolvedFrom: 'Model (out of the range ^2.0.3)',
71
+ });
72
+ });
73
+ it('should keep the version found when it is in the range', async () => {
74
+ expect(await resolvePeerVersion({ range: '^2.0.0' })).to.equal('2.0.1');
75
+ });
76
+ it('should keep the version of a workspace component', async () => {
77
+ expect(await resolvePeerVersion({ range: '^2.0.3', inBitmap: true })).to.equal('2.0.5');
78
+ });
79
+ it('should keep a forced version', async () => {
80
+ expect(await resolvePeerVersion({ range: '^2.0.3', forced: '2.0.2' })).to.equal('2.0.2');
81
+ });
82
+ it('should check the version against the range of the workspace policy when it replaces the range', async () => {
83
+ expect(await resolvePeerVersion({ range: '^2.0.3', workspacePolicy: '^2.0.0' })).to.equal('2.0.1');
84
+ });
85
+ it('should keep the version found when the range has no version in it', async () => {
86
+ expect(await resolvePeerVersion({ range: '<2.0.0' })).to.equal('2.0.1');
87
+ });
88
+ });
@@ -12,7 +12,7 @@ import { isPlusVersion } from '@teambit/dependency-resolver';
12
12
  import { DEPENDENCIES_FIELDS } from '@teambit/legacy.constants';
13
13
  import type OverridesDependencies from './overrides-dependencies';
14
14
  import type { DebugComponentsDependency } from './auto-detect-deps';
15
- import { getValidComponentVersion } from './auto-detect-deps';
15
+ import { getValidComponentVersion, getVersionInRangeIfOutOfIt } from './auto-detect-deps';
16
16
 
17
17
  type DepType = 'dependencies' | 'devDependencies' | 'peerDependencies';
18
18
 
@@ -112,10 +112,23 @@ export async function updateDependenciesVersions(
112
112
 
113
113
  function updateDependency(dependency: Dependency, depType: DepType) {
114
114
  const { id, packageName } = dependency;
115
- const { version: resolvedVersion, range, fromConfig } = resolveVersion(id, depType, packageName);
115
+ const resolved = resolveVersion(id, depType, packageName);
116
+ const { range, fromConfig } = resolved;
117
+ // the range that is recorded below. a range of a strategy (e.g. the workspace policy) replaces the one of the policy
118
+ const recordedRange = (supportComponentRange && range) || dependency.versionRange;
119
+ const resolvedVersion = fromConfig
120
+ ? resolved.version
121
+ : peerVersionInRange(dependency, depType, resolved.version, recordedRange);
116
122
  if (!resolvedVersion) {
117
123
  return;
118
124
  }
125
+ if (resolvedVersion !== resolved.version) {
126
+ const debugDep = debugDependencies?.find((dep) => dep.id.isEqualWithoutVersion(id));
127
+ if (debugDep) {
128
+ debugDep.versionResolvedFrom = `${debugDep.versionResolvedFrom} (out of the range ${recordedRange})`;
129
+ debugDep.version = resolvedVersion;
130
+ }
131
+ }
119
132
  if (fromConfig) dependenciesWithVersionFromConfig.push(id.toStringWithoutVersion());
120
133
  dependency.id = dependency.id.changeVersion(resolvedVersion);
121
134
  if (supportComponentRange) {
@@ -131,6 +144,21 @@ export async function updateDependenciesVersions(
131
144
  dependency.versionRange = undefined;
132
145
  }
133
146
  }
147
+ /**
148
+ * a policy (e.g. an env) sets the range of a component peer, and the package.json gets this range. the version found
149
+ * (e.g. the one of the last snap, or the installed one) can be out of this range, e.g. after the env raised it. then,
150
+ * take the version of the range, otherwise it's installed and recorded although the range doesn't allow it.
151
+ * a component of the workspace keeps its version.
152
+ */
153
+ function peerVersionInRange(
154
+ dependency: Dependency,
155
+ depType: DepType,
156
+ version?: string,
157
+ range?: string
158
+ ): string | undefined {
159
+ if (depType !== 'peerDependencies' || !version || !range || getIdFromBitMap(dependency.id)) return version;
160
+ return getVersionInRangeIfOutOfIt(version, range) || version;
161
+ }
134
162
  function updateDependencies(dependencies: Dependencies, depType: DepType) {
135
163
  dependencies.get().forEach((dep) => updateDependency(dep, depType));
136
164
  }
@@ -108,9 +108,8 @@ export declare class ApplyOverrides {
108
108
  */
109
109
  private getComponentIdFromForcedVersion;
110
110
  /**
111
- * the scope side of the installed version in updateDependenciesVersions(): a workspace installs a component peer in
112
- * the range of the policy, and records the installed version. so when the version is out of the range, it's changed
113
- * to the version of the range. (when it's in the range, it's kept, as a workspace that has it installed would do)
111
+ * the scope side of peerVersionInRange() in updateDependenciesVersions(): when the version of a component peer is
112
+ * out of the range of the policy, it's changed to the version of the range. (when it's in the range, it's kept)
114
113
  */
115
114
  private setComponentPeerVersionInRange;
116
115
  private setVersionFromConfig;
@@ -382,23 +382,14 @@ class ApplyOverrides {
382
382
  }
383
383
 
384
384
  /**
385
- * the scope side of the installed version in updateDependenciesVersions(): a workspace installs a component peer in
386
- * the range of the policy, and records the installed version. so when the version is out of the range, it's changed
387
- * to the version of the range. (when it's in the range, it's kept, as a workspace that has it installed would do)
385
+ * the scope side of peerVersionInRange() in updateDependenciesVersions(): when the version of a component peer is
386
+ * out of the range of the policy, it's changed to the version of the range. (when it's in the range, it's kept)
388
387
  */
389
388
  setComponentPeerVersionInRange(dependency, range) {
390
389
  if (!this.workspaceComponentIds || this.workspaceComponentIds.hasWithoutVersion(dependency.id)) return;
391
390
  const version = dependency.id.version;
392
- if (!version || !_semver().default.validRange(range)) return;
393
- // a snap is not in any semver range, a workspace would install a version of the range instead
394
- if (_semver().default.valid(version) && _semver().default.satisfies(version, range)) return;
395
- const {
396
- version: versionInRange
397
- } = (0, _autoDetectDeps().getValidComponentVersion)(range);
398
- // e.g. "<2.0.0" is coerced to "2.0.0", which is out of the range. there's no version to take for such a range.
399
- if (versionInRange && _semver().default.satisfies(versionInRange, range)) {
400
- dependency.id = dependency.id.changeVersion(versionInRange);
401
- }
391
+ const versionInRange = version ? (0, _autoDetectDeps().getVersionInRangeIfOutOfIt)(version, range) : undefined;
392
+ if (versionInRange) dependency.id = dependency.id.changeVersion(versionInRange);
402
393
  }
403
394
  setVersionFromConfig(id) {
404
395
  const idStr = id.toStringWithoutVersion();