@pnpm/installing.deps-resolver 1100.2.2 → 1100.2.4

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.
@@ -9,6 +9,7 @@ import { logger } from '@pnpm/logger';
9
9
  import { getPatchInfo } from '@pnpm/patching.config';
10
10
  import { convertEnginesRuntimeToDependencies } from '@pnpm/pkg-manifest.utils';
11
11
  import { DIRECT_DEP_SELECTOR_WEIGHT, } from '@pnpm/resolving.resolver-base';
12
+ import { lexCompare } from '@pnpm/util.lex-comparator';
12
13
  import normalizePath from 'normalize-path';
13
14
  import pDefer from 'p-defer';
14
15
  import { pathExists } from 'path-exists';
@@ -313,6 +314,7 @@ function getPublishedByDate(pkgAddresses, timeFromLockfile = {}) {
313
314
  export async function resolveDependencies(ctx, preferredVersions, wantedDependencies, options) {
314
315
  const extendedWantedDeps = getDepsToResolve(wantedDependencies, ctx.wantedLockfile, {
315
316
  preferredDependencies: options.preferredDependencies,
317
+ preferredVersions,
316
318
  prefix: options.prefix,
317
319
  proceed: options.proceed || ctx.forceFullResolution,
318
320
  registries: ctx.registries,
@@ -522,6 +524,7 @@ async function resolveDependenciesOfDependency(ctx, preferredVersions, options,
522
524
  }
523
525
  const postponedResolution = resolveChildren.bind(null, ctx, {
524
526
  parentPkg: resolveDependencyResult,
527
+ childrenResolutionId: resolveDependencyResult.childrenResolutionId,
525
528
  dependencyLockfile: extendedWantedDep.infoFromLockfile?.dependencyLockfile,
526
529
  parentDepth: options.currentDepth,
527
530
  parentIds: [...options.parentIds, resolveDependencyResult.pkgId],
@@ -534,7 +537,18 @@ async function resolveDependenciesOfDependency(ctx, preferredVersions, options,
534
537
  return {
535
538
  resolveDependencyResult,
536
539
  postponedResolution: async (postponedResolutionOpts) => {
540
+ if (!isCurrentChildrenResolution(ctx, resolveDependencyResult.pkgId, resolveDependencyResult.childrenResolutionId)) {
541
+ setDependencyTreeNodeWithCurrentChildren(ctx, {
542
+ parentDepth: options.currentDepth,
543
+ parentIds: [...options.parentIds, resolveDependencyResult.pkgId],
544
+ parentPkg: resolveDependencyResult,
545
+ });
546
+ return resolveMissingPeersFromCurrentChildrenResolution(ctx, resolveDependencyResult.pkgId, postponedResolutionOpts.parentPkgAliases);
547
+ }
537
548
  const { missingPeers, resolvedPeers } = await postponedResolution(postponedResolutionOpts);
549
+ if (!isCurrentChildrenResolution(ctx, resolveDependencyResult.pkgId, resolveDependencyResult.childrenResolutionId)) {
550
+ return resolveMissingPeersFromCurrentChildrenResolution(ctx, resolveDependencyResult.pkgId, postponedResolutionOpts.parentPkgAliases);
551
+ }
538
552
  if (resolveDependencyResult.missingPeersOfChildren) {
539
553
  resolveDependencyResult.missingPeersOfChildren.resolved = true;
540
554
  resolveDependencyResult.missingPeersOfChildren.resolve(missingPeers);
@@ -563,7 +577,195 @@ function filterMissingPeers({ missingPeers, resolvedPeers }, parentPkgAliases) {
563
577
  missingPeers: newMissing,
564
578
  };
565
579
  }
566
- async function resolveChildren(ctx, { parentPkg, parentIds, dependencyLockfile, parentDepth, updateDepth, updateMatching, prefix, supportedArchitectures, }, { parentPkgAliases, preferredVersions, publishedBy, }) {
580
+ function startPackageResolution(ctx, depth) {
581
+ const activeCount = ctx.packageResolutionBarrier.activeByDepth.get(depth) ?? 0;
582
+ ctx.packageResolutionBarrier.activeByDepth.set(depth, activeCount + 1);
583
+ let finished = false;
584
+ return () => {
585
+ if (finished)
586
+ return;
587
+ finished = true;
588
+ const nextActiveCount = (ctx.packageResolutionBarrier.activeByDepth.get(depth) ?? 1) - 1;
589
+ if (nextActiveCount > 0) {
590
+ ctx.packageResolutionBarrier.activeByDepth.set(depth, nextActiveCount);
591
+ }
592
+ else {
593
+ ctx.packageResolutionBarrier.activeByDepth.delete(depth);
594
+ }
595
+ const waiters = ctx.packageResolutionBarrier.waiters.splice(0);
596
+ for (const resolve of waiters) {
597
+ resolve();
598
+ }
599
+ };
600
+ }
601
+ async function waitForPackageResolutionTurn(ctx, depth) {
602
+ if (!hasActivePackageResolutionBeforeDepth(ctx, depth))
603
+ return;
604
+ await new Promise((resolve) => ctx.packageResolutionBarrier.waiters.push(resolve));
605
+ return waitForPackageResolutionTurn(ctx, depth);
606
+ }
607
+ function hasActivePackageResolutionBeforeDepth(ctx, depth) {
608
+ for (const [activeDepth, activeCount] of ctx.packageResolutionBarrier.activeByDepth) {
609
+ if (activeDepth < depth && activeCount > 0)
610
+ return true;
611
+ }
612
+ return false;
613
+ }
614
+ function claimChildrenResolution(ctx, opts) {
615
+ const owner = {
616
+ depth: opts.currentDepth,
617
+ importerOrder: ctx.importerResolutionOrder[opts.parentIds[0]] ?? Number.MAX_SAFE_INTEGER,
618
+ parentPath: opts.parentIds,
619
+ };
620
+ const existing = ctx.childrenResolutionByPkgId[opts.pkgId];
621
+ if (existing == null || compareChildrenResolutionOwners(owner, existing.owner) < 0) {
622
+ const previousMissingPeersOfChildren = existing?.missingPeersOfChildren;
623
+ const missingPeersOfChildren = ctx.hoistPeers && !opts.parentIds.includes(opts.pkgId)
624
+ ? createMissingPeersOfChildren()
625
+ : undefined;
626
+ const resolution = {
627
+ id: ++ctx.childrenResolutionId,
628
+ owner,
629
+ missingPeersOfChildren,
630
+ };
631
+ ctx.childrenResolutionByPkgId[opts.pkgId] = resolution;
632
+ if (missingPeersOfChildren) {
633
+ ctx.missingPeersOfChildrenByPkgId[opts.pkgId] = {
634
+ depth: owner.depth,
635
+ missingPeersOfChildren,
636
+ };
637
+ }
638
+ if (previousMissingPeersOfChildren) {
639
+ if (missingPeersOfChildren) {
640
+ missingPeersOfChildren.get().then((missingPeers) => {
641
+ previousMissingPeersOfChildren.resolved = true;
642
+ previousMissingPeersOfChildren.resolve(missingPeers);
643
+ }, previousMissingPeersOfChildren.reject);
644
+ }
645
+ else {
646
+ previousMissingPeersOfChildren.resolved = true;
647
+ previousMissingPeersOfChildren.resolve({});
648
+ }
649
+ }
650
+ return {
651
+ id: resolution.id,
652
+ isOwner: true,
653
+ missingPeersOfChildren,
654
+ };
655
+ }
656
+ let missingPeersOfChildren;
657
+ if (ctx.hoistPeers &&
658
+ !opts.parentIds.includes(opts.pkgId) &&
659
+ existing.missingPeersOfChildren &&
660
+ (existing.owner.depth >= opts.currentDepth ||
661
+ existing.missingPeersOfChildren.resolved)) {
662
+ missingPeersOfChildren = existing.missingPeersOfChildren;
663
+ }
664
+ return {
665
+ id: existing.id,
666
+ isOwner: false,
667
+ missingPeersOfChildren,
668
+ };
669
+ }
670
+ function compareChildrenResolutionOwners(owner1, owner2) {
671
+ if (owner1.depth !== owner2.depth)
672
+ return owner1.depth - owner2.depth;
673
+ if (owner1.importerOrder !== owner2.importerOrder)
674
+ return owner1.importerOrder - owner2.importerOrder;
675
+ const pathLength = Math.min(owner1.parentPath.length, owner2.parentPath.length);
676
+ for (let i = 0; i < pathLength; i++) {
677
+ const result = lexCompare(owner1.parentPath[i], owner2.parentPath[i]);
678
+ if (result !== 0)
679
+ return result;
680
+ }
681
+ return owner1.parentPath.length - owner2.parentPath.length;
682
+ }
683
+ function createMissingPeersOfChildren() {
684
+ const p = pDefer();
685
+ return {
686
+ resolve: p.resolve,
687
+ reject: p.reject,
688
+ get: pShare(p.promise),
689
+ };
690
+ }
691
+ function isCurrentChildrenResolution(ctx, pkgId, childrenResolutionId) {
692
+ return childrenResolutionId != null && ctx.childrenResolutionByPkgId[pkgId]?.id === childrenResolutionId;
693
+ }
694
+ async function resolveMissingPeersFromCurrentChildrenResolution(ctx, pkgId, parentPkgAliases) {
695
+ const missingPeersOfChildren = ctx.childrenResolutionByPkgId[pkgId]?.missingPeersOfChildren;
696
+ if (missingPeersOfChildren == null) {
697
+ return {
698
+ missingPeers: {},
699
+ resolvedPeers: {},
700
+ };
701
+ }
702
+ const missingPeers = await missingPeersOfChildren.get();
703
+ return filterMissingPeers({ missingPeers, resolvedPeers: {} }, parentPkgAliases);
704
+ }
705
+ function setDependencyTreeNodeWithCurrentChildren(ctx, { parentDepth, parentIds, parentPkg, }) {
706
+ ctx.dependenciesTree.set(parentPkg.nodeId, {
707
+ children: () => buildTree(ctx, parentPkg.pkgId, parentIds, ctx.childrenByParentId[parentPkg.pkgId] ?? [], parentDepth + 1, parentPkg.installable),
708
+ depth: parentDepth,
709
+ installable: parentPkg.installable,
710
+ lockedPeerContext: parentPkg.lockedPeerContext,
711
+ previousDepPath: parentPkg.previousDepPath,
712
+ resolvedPackage: ctx.resolvedPkgsById[parentPkg.pkgId],
713
+ });
714
+ ctx.nodeResolutionContextByNodeId.set(parentPkg.nodeId, {
715
+ depth: parentDepth,
716
+ installable: parentPkg.installable,
717
+ parentIds,
718
+ pkgId: parentPkg.pkgId,
719
+ });
720
+ }
721
+ function updateChildrenResolutionNodes(ctx, pkgId, currentNodeId) {
722
+ for (const [nodeId, nodeContext] of ctx.nodeResolutionContextByNodeId) {
723
+ if (nodeId === currentNodeId || nodeContext.pkgId !== pkgId)
724
+ continue;
725
+ const node = ctx.dependenciesTree.get(nodeId);
726
+ if (node == null || node.depth === -1)
727
+ continue;
728
+ node.children = () => buildTree(ctx, pkgId, nodeContext.parentIds, ctx.childrenByParentId[pkgId] ?? [], nodeContext.depth + 1, nodeContext.installable);
729
+ }
730
+ }
731
+ export function buildTree(ctx, parentId, parentIds, children, depth, installable) {
732
+ const childrenNodeIds = {};
733
+ for (const child of children) {
734
+ if (child.id.startsWith('link:')) {
735
+ childrenNodeIds[child.alias] = child.id;
736
+ continue;
737
+ }
738
+ if (parentIdsContainSequence(parentIds, parentId, child.id) || parentId === child.id) {
739
+ continue;
740
+ }
741
+ if (ctx.resolvedPkgsById[child.id].isLeaf) {
742
+ childrenNodeIds[child.alias] = child.id;
743
+ continue;
744
+ }
745
+ const childNodeId = nextNodeId();
746
+ childrenNodeIds[child.alias] = childNodeId;
747
+ installable = installable || !ctx.skipped.has(child.id);
748
+ ctx.dependenciesTree.set(childNodeId, {
749
+ children: () => buildTree(ctx, child.id, [...parentIds, child.id], ctx.childrenByParentId[child.id], depth + 1, installable),
750
+ depth,
751
+ installable,
752
+ resolvedPackage: ctx.resolvedPkgsById[child.id],
753
+ });
754
+ }
755
+ return childrenNodeIds;
756
+ }
757
+ async function resolveChildren(ctx, { parentPkg, childrenResolutionId, parentIds, dependencyLockfile, parentDepth, updateDepth, updateMatching, prefix, supportedArchitectures, }, { parentPkgAliases, preferredVersions, publishedBy, }) {
758
+ if (!isCurrentChildrenResolution(ctx, parentPkg.pkgId, childrenResolutionId)) {
759
+ setDependencyTreeNodeWithCurrentChildren(ctx, {
760
+ parentDepth,
761
+ parentIds,
762
+ parentPkg,
763
+ });
764
+ return {
765
+ missingPeers: {},
766
+ resolvedPeers: {},
767
+ };
768
+ }
567
769
  const currentResolvedDependencies = (dependencyLockfile != null)
568
770
  ? {
569
771
  ...dependencyLockfile.dependencies,
@@ -593,6 +795,14 @@ async function resolveChildren(ctx, { parentPkg, parentIds, dependencyLockfile,
593
795
  supportedArchitectures,
594
796
  parentIds,
595
797
  });
798
+ if (!isCurrentChildrenResolution(ctx, parentPkg.pkgId, childrenResolutionId)) {
799
+ setDependencyTreeNodeWithCurrentChildren(ctx, {
800
+ parentDepth,
801
+ parentIds,
802
+ parentPkg,
803
+ });
804
+ return resolvingPeers;
805
+ }
596
806
  ctx.childrenByParentId[parentPkg.pkgId] = pkgAddresses.map((child) => ({
597
807
  alias: child.alias,
598
808
  id: child.pkgId,
@@ -617,6 +827,13 @@ async function resolveChildren(ctx, { parentPkg, parentIds, dependencyLockfile,
617
827
  previousDepPath: parentPkg.previousDepPath,
618
828
  resolvedPackage: ctx.resolvedPkgsById[parentPkg.pkgId],
619
829
  });
830
+ ctx.nodeResolutionContextByNodeId.set(parentPkg.nodeId, {
831
+ depth: parentDepth,
832
+ installable: parentPkg.installable,
833
+ parentIds,
834
+ pkgId: parentPkg.pkgId,
835
+ });
836
+ updateChildrenResolutionNodes(ctx, parentPkg.pkgId, parentPkg.nodeId);
620
837
  return resolvingPeers;
621
838
  }
622
839
  function getDepsToResolve(wantedDependencies, wantedLockfile, options) {
@@ -633,12 +850,33 @@ function getDepsToResolve(wantedDependencies, wantedLockfile, options) {
633
850
  });
634
851
  for (const wantedDependency of wantedDependencies) {
635
852
  let reference = undefined;
853
+ let preferredVersion = undefined;
636
854
  let proceed = proceedAll;
637
855
  if (wantedDependency.alias) {
638
856
  const satisfiesWanted = satisfiesWanted2Args.bind(null, wantedDependency);
639
857
  if (resolvedDependencies[wantedDependency.alias] &&
640
858
  (satisfiesWanted(resolvedDependencies[wantedDependency.alias]) || resolvedDependencies[wantedDependency.alias].startsWith('file:'))) {
641
- reference = resolvedDependencies[wantedDependency.alias];
859
+ const pinnedRef = resolvedDependencies[wantedDependency.alias];
860
+ // Reusing a lockfile pin verbatim bypasses the preferred-versions
861
+ // walk, so a transitive edge stays on a stale lower version even
862
+ // when a direct dependency resolved to a higher version in range.
863
+ const pinned = pinnedRef.startsWith('file:')
864
+ ? undefined
865
+ : getPinnedNameVer(wantedLockfile, pinnedRef, wantedDependency.alias);
866
+ const higherDirectVersion = pinned == null
867
+ ? undefined
868
+ : findHigherDirectDepVersion(options.preferredVersions, pinned.name, pinned.version, wantedDependency.bareSpecifier);
869
+ if (higherDirectVersion != null) {
870
+ // `preferredVersion` (singular) overrides the
871
+ // EXISTING_VERSION_SELECTOR_WEIGHT stability bias that would
872
+ // otherwise re-pick the lower version. The lower version is then
873
+ // never resolved or fetched.
874
+ proceed = true;
875
+ preferredVersion = higherDirectVersion;
876
+ }
877
+ else {
878
+ reference = pinnedRef;
879
+ }
642
880
  }
643
881
  else if (
644
882
  // If dependencies that were used by the previous version of the package
@@ -669,6 +907,7 @@ function getDepsToResolve(wantedDependencies, wantedLockfile, options) {
669
907
  }
670
908
  extendedWantedDeps.push({
671
909
  infoFromLockfile,
910
+ preferredVersion,
672
911
  proceed,
673
912
  wantedDependency,
674
913
  });
@@ -693,6 +932,44 @@ function referenceSatisfiesWantedSpec(opts, wantedDep, preferredRef) {
693
932
  }
694
933
  return semver.satisfies(version, wantedDep.bareSpecifier, true);
695
934
  }
935
+ function getPinnedNameVer(lockfile, reference, alias) {
936
+ const depPath = dp.refToRelative(reference, alias);
937
+ if (depPath === null)
938
+ return undefined;
939
+ const pkgSnapshot = lockfile.packages?.[depPath];
940
+ if (pkgSnapshot == null)
941
+ return undefined;
942
+ return nameVerFromPkgSnapshot(depPath, pkgSnapshot);
943
+ }
944
+ // The highest version a direct dependency (the only deterministic,
945
+ // resolved-first anchor) resolved to that is higher than the
946
+ // lockfile-pinned `pinnedVersion` and still satisfies the edge's range, or
947
+ // `undefined` when none exists. Direct-dependency versions are marked with
948
+ // DIRECT_DEP_SELECTOR_WEIGHT in preferredVersions.
949
+ function findHigherDirectDepVersion(preferredVersions, pinnedName, pinnedVersion, bareSpecifier) {
950
+ if (preferredVersions == null)
951
+ return undefined;
952
+ if (!semver.valid(pinnedVersion))
953
+ return undefined;
954
+ if (semver.validRange(bareSpecifier) === null)
955
+ return undefined;
956
+ const selectors = preferredVersions[pinnedName];
957
+ if (selectors == null)
958
+ return undefined;
959
+ let best;
960
+ for (const [candidate, selector] of Object.entries(selectors)) {
961
+ if (typeof selector === 'object' &&
962
+ selector.selectorType === 'version' &&
963
+ selector.weight === DIRECT_DEP_SELECTOR_WEIGHT &&
964
+ semver.valid(candidate) &&
965
+ semver.gt(candidate, pinnedVersion) &&
966
+ semver.satisfies(candidate, bareSpecifier, true) &&
967
+ (best == null || semver.gt(candidate, best))) {
968
+ best = candidate;
969
+ }
970
+ }
971
+ return best;
972
+ }
696
973
  function getLockedPeerContext(dependencyLockfile) {
697
974
  if (dependencyLockfile.peerDependencies == null)
698
975
  return undefined;
@@ -775,345 +1052,338 @@ async function resolveDependency(wantedDependency, ctx, options) {
775
1052
  optional: true,
776
1053
  };
777
1054
  }
778
- // Normalize the `preferredVersion` (singular) and `preferredVersions`
779
- // (plural) options. If the singular option is passed through, it'll be used
780
- // instead of the plural option.
781
- const preferredVersions = !options.updateRequested && options.preferredVersion != null
782
- ? getExactSinglePreferredVersions(wantedDependency, options.preferredVersion)
783
- : options.preferredVersions;
1055
+ const finishPackageResolution = startPackageResolution(ctx, options.currentDepth);
784
1056
  try {
785
- const calcSpecifier = options.currentDepth === 0;
786
- if (!options.update && currentPkg.version && currentPkg.pkgId?.endsWith(`@${currentPkg.version}`) && !calcSpecifier) {
787
- wantedDependency.bareSpecifier = replaceVersionInBareSpecifier(wantedDependency.bareSpecifier, currentPkg.version, ctx.namedRegistryPrefixes);
1057
+ await waitForPackageResolutionTurn(ctx, options.currentDepth);
1058
+ // Normalize the `preferredVersion` (singular) and `preferredVersions`
1059
+ // (plural) options. If the singular option is passed through, it'll be used
1060
+ // instead of the plural option.
1061
+ const preferredVersions = !options.updateRequested && options.preferredVersion != null
1062
+ ? getExactSinglePreferredVersions(wantedDependency, options.preferredVersion)
1063
+ : options.preferredVersions;
1064
+ try {
1065
+ const calcSpecifier = options.currentDepth === 0;
1066
+ if (!options.update && currentPkg.version && currentPkg.pkgId?.endsWith(`@${currentPkg.version}`) && !calcSpecifier) {
1067
+ wantedDependency.bareSpecifier = replaceVersionInBareSpecifier(wantedDependency.bareSpecifier, currentPkg.version, ctx.namedRegistryPrefixes);
1068
+ }
1069
+ pkgResponse = await ctx.storeController.requestPackage(wantedDependency, {
1070
+ allowBuild: ctx.allowBuild,
1071
+ alwaysTryWorkspacePackages: ctx.linkWorkspacePackagesDepth >= options.currentDepth,
1072
+ currentPkg: currentPkg
1073
+ ? {
1074
+ id: currentPkg.pkgId,
1075
+ name: currentPkg.name,
1076
+ resolution: currentPkg.resolution,
1077
+ version: currentPkg.version,
1078
+ publishedAt: currentPkg.pkgId ? ctx.wantedLockfile.time?.[currentPkg.pkgId] : undefined,
1079
+ }
1080
+ : undefined,
1081
+ expectedPkg: currentPkg,
1082
+ defaultTag: ctx.defaultTag,
1083
+ ignoreScripts: ctx.ignoreScripts,
1084
+ publishedBy: options.publishedBy,
1085
+ publishedByExclude: ctx.publishedByExclude,
1086
+ pickLowestVersion: options.pickLowestVersion,
1087
+ downloadPriority: -options.currentDepth,
1088
+ lockfileDir: ctx.lockfileDir,
1089
+ preferredVersions,
1090
+ preferWorkspacePackages: ctx.preferWorkspacePackages,
1091
+ projectDir: (options.currentDepth > 0 &&
1092
+ !wantedDependency.bareSpecifier.startsWith('file:'))
1093
+ ? ctx.lockfileDir
1094
+ : options.parentPkg.rootDir,
1095
+ skipFetch: ctx.dryRun,
1096
+ trustPolicy: ctx.trustPolicy,
1097
+ trustPolicyExclude: ctx.trustPolicyExclude,
1098
+ trustPolicyIgnoreAfter: ctx.trustPolicyIgnoreAfter,
1099
+ update: options.update,
1100
+ updateChecksums: options.updateChecksums,
1101
+ workspacePackages: ctx.workspacePackages,
1102
+ supportedArchitectures: options.supportedArchitectures,
1103
+ onFetchError: (err) => {
1104
+ err.prefix = options.prefix;
1105
+ err.pkgsStack = getPkgsInfoFromIds(options.parentIds, ctx.resolvedPkgsById);
1106
+ return err;
1107
+ },
1108
+ injectWorkspacePackages: ctx.injectWorkspacePackages,
1109
+ calcSpecifier,
1110
+ pinnedVersion: options.pinnedVersion,
1111
+ });
788
1112
  }
789
- pkgResponse = await ctx.storeController.requestPackage(wantedDependency, {
790
- allowBuild: ctx.allowBuild,
791
- alwaysTryWorkspacePackages: ctx.linkWorkspacePackagesDepth >= options.currentDepth,
792
- currentPkg: currentPkg
793
- ? {
794
- id: currentPkg.pkgId,
795
- name: currentPkg.name,
796
- resolution: currentPkg.resolution,
797
- version: currentPkg.version,
798
- publishedAt: currentPkg.pkgId ? ctx.wantedLockfile.time?.[currentPkg.pkgId] : undefined,
799
- }
800
- : undefined,
801
- expectedPkg: currentPkg,
802
- defaultTag: ctx.defaultTag,
803
- ignoreScripts: ctx.ignoreScripts,
804
- publishedBy: options.publishedBy,
805
- publishedByExclude: ctx.publishedByExclude,
806
- pickLowestVersion: options.pickLowestVersion,
807
- downloadPriority: -options.currentDepth,
808
- lockfileDir: ctx.lockfileDir,
809
- preferredVersions,
810
- preferWorkspacePackages: ctx.preferWorkspacePackages,
811
- projectDir: (options.currentDepth > 0 &&
812
- !wantedDependency.bareSpecifier.startsWith('file:'))
813
- ? ctx.lockfileDir
814
- : options.parentPkg.rootDir,
815
- skipFetch: ctx.dryRun,
816
- trustPolicy: ctx.trustPolicy,
817
- trustPolicyExclude: ctx.trustPolicyExclude,
818
- trustPolicyIgnoreAfter: ctx.trustPolicyIgnoreAfter,
819
- update: options.update,
820
- updateChecksums: options.updateChecksums,
821
- workspacePackages: ctx.workspacePackages,
822
- supportedArchitectures: options.supportedArchitectures,
823
- onFetchError: (err) => {
824
- err.prefix = options.prefix;
825
- err.pkgsStack = getPkgsInfoFromIds(options.parentIds, ctx.resolvedPkgsById);
826
- return err;
1113
+ catch (err) { // eslint-disable-line
1114
+ const wantedDependencyDetails = {
1115
+ name: wantedDependency.alias,
1116
+ bareSpecifier: wantedDependency.bareSpecifier,
1117
+ version: wantedDependency.alias ? wantedDependency.bareSpecifier : undefined,
1118
+ };
1119
+ if (wantedDependency.optional && err.code !== 'ERR_PNPM_TRUST_DOWNGRADE') {
1120
+ skippedOptionalDependencyLogger.debug({
1121
+ details: err.toString(),
1122
+ package: wantedDependencyDetails,
1123
+ parents: getPkgsInfoFromIds(options.parentIds, ctx.resolvedPkgsById),
1124
+ prefix: options.prefix,
1125
+ reason: 'resolution_failure',
1126
+ });
1127
+ return null;
1128
+ }
1129
+ err.package = wantedDependencyDetails;
1130
+ err.prefix = options.prefix;
1131
+ err.pkgsStack = getPkgsInfoFromIds(options.parentIds, ctx.resolvedPkgsById);
1132
+ throw err;
1133
+ }
1134
+ dependencyResolvedLogger.debug({
1135
+ resolution: pkgResponse.body.id,
1136
+ wanted: {
1137
+ dependentId: options.parentPkg.pkgId,
1138
+ name: wantedDependency.alias,
1139
+ rawSpec: wantedDependency.bareSpecifier,
827
1140
  },
828
- injectWorkspacePackages: ctx.injectWorkspacePackages,
829
- calcSpecifier,
830
- pinnedVersion: options.pinnedVersion,
831
1141
  });
832
- }
833
- catch (err) { // eslint-disable-line
834
- const wantedDependencyDetails = {
835
- name: wantedDependency.alias,
836
- bareSpecifier: wantedDependency.bareSpecifier,
837
- version: wantedDependency.alias ? wantedDependency.bareSpecifier : undefined,
838
- };
839
- if (wantedDependency.optional && err.code !== 'ERR_PNPM_TRUST_DOWNGRADE') {
840
- skippedOptionalDependencyLogger.debug({
841
- details: err.toString(),
842
- package: wantedDependencyDetails,
843
- parents: getPkgsInfoFromIds(options.parentIds, ctx.resolvedPkgsById),
844
- prefix: options.prefix,
845
- reason: 'resolution_failure',
846
- });
847
- return null;
1142
+ // Resolver-inline policy violations (e.g. minimumReleaseAge) flow up
1143
+ // here; collect them onto the shared context so resolveDependencyTree
1144
+ // can hand the full set to the install command between
1145
+ // resolveDependencyTree and resolvePeers.
1146
+ if (pkgResponse.body.policyViolation) {
1147
+ ctx.resolutionPolicyViolations.push(pkgResponse.body.policyViolation);
848
1148
  }
849
- err.package = wantedDependencyDetails;
850
- err.prefix = options.prefix;
851
- err.pkgsStack = getPkgsInfoFromIds(options.parentIds, ctx.resolvedPkgsById);
852
- throw err;
853
- }
854
- dependencyResolvedLogger.debug({
855
- resolution: pkgResponse.body.id,
856
- wanted: {
857
- dependentId: options.parentPkg.pkgId,
858
- name: wantedDependency.alias,
859
- rawSpec: wantedDependency.bareSpecifier,
860
- },
861
- });
862
- // Resolver-inline policy violations (e.g. minimumReleaseAge) flow up
863
- // here; collect them onto the shared context so resolveDependencyTree
864
- // can hand the full set to the install command between
865
- // resolveDependencyTree and resolvePeers.
866
- if (pkgResponse.body.policyViolation) {
867
- ctx.resolutionPolicyViolations.push(pkgResponse.body.policyViolation);
868
- }
869
- // Check if exotic dependencies are disallowed in subdependencies
870
- if (ctx.blockExoticSubdeps &&
871
- options.currentDepth > 0 &&
872
- pkgResponse.body.resolvedVia != null && // This is already coming from the lockfile, we skip the check in this case for now. Should be fixed later.
873
- isExoticDep(pkgResponse.body.resolvedVia)) {
874
- const error = new PnpmError('EXOTIC_SUBDEP', `Exotic dependency "${wantedDependency.alias ?? wantedDependency.bareSpecifier}" (resolved via ${pkgResponse.body.resolvedVia}) is not allowed in subdependencies when blockExoticSubdeps is enabled`);
875
- error.prefix = options.prefix;
876
- error.pkgsStack = getPkgsInfoFromIds(options.parentIds, ctx.resolvedPkgsById);
877
- throw error;
878
- }
879
- if (ctx.allPreferredVersions && pkgResponse.body.manifest?.version) {
880
- if (!ctx.allPreferredVersions[pkgResponse.body.manifest.name]) {
881
- ctx.allPreferredVersions[pkgResponse.body.manifest.name] = {};
1149
+ // Check if exotic dependencies are disallowed in subdependencies
1150
+ if (ctx.blockExoticSubdeps &&
1151
+ options.currentDepth > 0 &&
1152
+ pkgResponse.body.resolvedVia != null && // This is already coming from the lockfile, we skip the check in this case for now. Should be fixed later.
1153
+ isExoticDep(pkgResponse.body.resolvedVia)) {
1154
+ const error = new PnpmError('EXOTIC_SUBDEP', `Exotic dependency "${wantedDependency.alias ?? wantedDependency.bareSpecifier}" (resolved via ${pkgResponse.body.resolvedVia}) is not allowed in subdependencies when blockExoticSubdeps is enabled`);
1155
+ error.prefix = options.prefix;
1156
+ error.pkgsStack = getPkgsInfoFromIds(options.parentIds, ctx.resolvedPkgsById);
1157
+ throw error;
882
1158
  }
883
- ctx.allPreferredVersions[pkgResponse.body.manifest.name][pkgResponse.body.manifest.version] = 'version';
884
- }
885
- if (!pkgResponse.body.updated &&
886
- options.currentDepth === Math.max(0, options.updateDepth) &&
887
- depIsLinked && !ctx.force && !options.proceed) {
888
- return null;
889
- }
890
- if (pkgResponse.body.isLocal) {
891
- if (!pkgResponse.body.manifest) {
892
- // This should actually never happen because the local-resolver returns a manifest
893
- // even if no real manifest exists in the filesystem.
894
- throw new PnpmError('MISSING_PACKAGE_JSON', `Can't install ${wantedDependency.bareSpecifier}: Missing package.json file`);
1159
+ if (ctx.allPreferredVersions && pkgResponse.body.manifest?.version) {
1160
+ if (!ctx.allPreferredVersions[pkgResponse.body.manifest.name]) {
1161
+ ctx.allPreferredVersions[pkgResponse.body.manifest.name] = {};
1162
+ }
1163
+ ctx.allPreferredVersions[pkgResponse.body.manifest.name][pkgResponse.body.manifest.version] = 'version';
895
1164
  }
896
- return {
897
- alias: wantedDependency.alias ?? pkgResponse.body.alias ?? pkgResponse.body.manifest.name ?? path.basename(pkgResponse.body.resolution.directory),
898
- dev: wantedDependency.dev,
899
- isLinkedDependency: true,
900
- name: pkgResponse.body.manifest.name,
901
- optional: wantedDependency.optional,
902
- pkgId: pkgResponse.body.id,
903
- resolution: pkgResponse.body.resolution,
904
- version: pkgResponse.body.manifest.version,
905
- normalizedBareSpecifier: pkgResponse.body.normalizedBareSpecifier,
906
- pkg: pkgResponse.body.manifest,
907
- };
908
- }
909
- let prepare;
910
- let hasBin;
911
- let pkg = getManifestFromResponse(pkgResponse, wantedDependency, currentPkg);
912
- if (!pkg.dependencies) {
913
- pkg.dependencies = {};
914
- }
915
- if (ctx.readPackageHook != null) {
916
- pkg = await ctx.readPackageHook(pkg);
917
- }
918
- if (pkg.peerDependencies && pkg.dependencies) {
919
- if (ctx.autoInstallPeers) {
920
- pkg = {
921
- ...pkg,
922
- dependencies: omit(Object.keys(pkg.peerDependencies), pkg.dependencies),
923
- };
1165
+ if (!pkgResponse.body.updated &&
1166
+ options.currentDepth === Math.max(0, options.updateDepth) &&
1167
+ depIsLinked && !ctx.force && !options.proceed) {
1168
+ return null;
924
1169
  }
925
- else {
926
- pkg = {
927
- ...pkg,
928
- dependencies: omit(Object.keys(pkg.peerDependencies).filter((peerDep) => options.parentPkgAliases[peerDep]), pkg.dependencies),
1170
+ if (pkgResponse.body.isLocal) {
1171
+ if (!pkgResponse.body.manifest) {
1172
+ // This should actually never happen because the local-resolver returns a manifest
1173
+ // even if no real manifest exists in the filesystem.
1174
+ throw new PnpmError('MISSING_PACKAGE_JSON', `Can't install ${wantedDependency.bareSpecifier}: Missing package.json file`);
1175
+ }
1176
+ return {
1177
+ alias: wantedDependency.alias ?? pkgResponse.body.alias ?? pkgResponse.body.manifest.name ?? path.basename(pkgResponse.body.resolution.directory),
1178
+ dev: wantedDependency.dev,
1179
+ isLinkedDependency: true,
1180
+ name: pkgResponse.body.manifest.name,
1181
+ optional: wantedDependency.optional,
1182
+ pkgId: pkgResponse.body.id,
1183
+ resolution: pkgResponse.body.resolution,
1184
+ version: pkgResponse.body.manifest.version,
1185
+ normalizedBareSpecifier: pkgResponse.body.normalizedBareSpecifier,
1186
+ pkg: pkgResponse.body.manifest,
929
1187
  };
930
1188
  }
931
- }
932
- if (pkg.engines?.runtime != null) {
933
- convertEnginesRuntimeToDependencies(pkg, 'engines', 'dependencies');
934
- }
935
- if (!pkg.name) { // TODO: don't fail on optional dependencies
936
- throw new PnpmError('MISSING_PACKAGE_NAME', `Can't install ${wantedDependency.bareSpecifier}: Missing package name`);
937
- }
938
- let pkgIdWithPatchHash = (pkgResponse.body.id.startsWith(`${pkg.name}@`) ? pkgResponse.body.id : `${pkg.name}@${pkgResponse.body.id}`);
939
- const patch = getPatchInfo(ctx.patchedDependencies, pkg.name, pkg.version);
940
- if (patch) {
941
- ctx.appliedPatches.add(patch.key);
942
- pkgIdWithPatchHash = `${pkgIdWithPatchHash}(patch_hash=${patch.hash})`;
943
- }
944
- // We are building the dependency tree only until there are new packages
945
- // or the packages repeat in a unique order.
946
- // This is needed later during peer dependencies resolution.
947
- //
948
- // So we resolve foo > bar > qar > foo
949
- // But we stop on foo > bar > qar > foo > qar
950
- // In the second example, there's no reason to walk qar again
951
- // when qar is included the first time, the dependencies of foo
952
- // are already resolved and included as parent dependencies of qar.
953
- // So during peers resolution, qar cannot possibly get any new or different
954
- // peers resolved, after the first occurrence.
955
- //
956
- // However, in the next example we would analyze the second qar as well,
957
- // because zoo is a new parent package:
958
- // foo > bar > qar > zoo > qar
959
- if (parentIdsContainSequence(options.parentIds, options.parentPkg.pkgId, pkgResponse.body.id) || pkgResponse.body.id === options.parentPkg.pkgId) {
960
- return null;
961
- }
962
- if (!options.update && (currentPkg.dependencyLockfile != null) && currentPkg.depPath &&
963
- !pkgResponse.body.updated &&
964
- // peerDependencies field is also used for transitive peer dependencies which should not be linked
965
- // That's why we cannot omit reading package.json of such dependencies.
966
- // This can be removed if we implement something like peerDependenciesMeta.transitive: true
967
- (currentPkg.dependencyLockfile.peerDependencies == null)) {
968
- hasBin = currentPkg.dependencyLockfile.hasBin === true;
969
- pkg = {
970
- ...nameVerFromPkgSnapshot(currentPkg.depPath, currentPkg.dependencyLockfile),
971
- ...omitDepsFields(currentPkg.dependencyLockfile),
972
- ...pkg,
973
- };
974
- }
975
- else {
976
- prepare = Boolean(pkgResponse.body.resolvedVia === 'git-repository' &&
977
- typeof pkg.scripts?.prepare === 'string');
978
- if (currentPkg.dependencyLockfile?.deprecated &&
979
- !pkgResponse.body.updated && !pkg.deprecated) {
980
- pkg.deprecated = currentPkg.dependencyLockfile.deprecated;
1189
+ let prepare;
1190
+ let hasBin;
1191
+ let pkg = getManifestFromResponse(pkgResponse, wantedDependency, currentPkg);
1192
+ if (!pkg.dependencies) {
1193
+ pkg.dependencies = {};
981
1194
  }
982
- hasBin = (currentPkg.dependencyLockfile?.hasBin != null && !pkg.bin)
983
- ? currentPkg.dependencyLockfile.hasBin
984
- : Boolean((pkg.bin && !(pkg.bin === '' || Object.keys(pkg.bin).length === 0)) ?? pkg.directories?.bin);
985
- }
986
- if (options.currentDepth === 0 && pkgResponse.body.latest && pkgResponse.body.latest !== pkg.version) {
987
- ctx.outdatedDependencies[pkgResponse.body.id] = pkgResponse.body.latest;
988
- }
989
- if (pkg.peerDependencies != null) {
990
- for (const name in pkg.peerDependencies) {
991
- ctx.allPeerDepNames.add(name);
1195
+ if (ctx.readPackageHook != null) {
1196
+ pkg = await ctx.readPackageHook(pkg);
992
1197
  }
993
- }
994
- if (pkg.peerDependenciesMeta != null) {
995
- for (const name in pkg.peerDependenciesMeta) {
996
- ctx.allPeerDepNames.add(name);
1198
+ if (pkg.peerDependencies && pkg.dependencies) {
1199
+ if (ctx.autoInstallPeers) {
1200
+ pkg = {
1201
+ ...pkg,
1202
+ dependencies: omit(Object.keys(pkg.peerDependencies), pkg.dependencies),
1203
+ };
1204
+ }
1205
+ else {
1206
+ pkg = {
1207
+ ...pkg,
1208
+ dependencies: omit(Object.keys(pkg.peerDependencies).filter((peerDep) => options.parentPkgAliases[peerDep]), pkg.dependencies),
1209
+ };
1210
+ }
997
1211
  }
998
- }
999
- // In case of leaf dependencies (dependencies that have no prod deps or peer deps),
1000
- // we only ever need to analyze one leaf dep in a graph, so the nodeId can be short and stateless.
1001
- const nodeId = pkgIsLeaf(pkg) ? pkgResponse.body.id : nextNodeId();
1002
- const parentIsInstallable = options.parentPkg.installable === undefined || options.parentPkg.installable;
1003
- const installable = parentIsInstallable && pkgResponse.body.isInstallable !== false;
1004
- const isNew = !ctx.resolvedPkgsById[pkgResponse.body.id];
1005
- const parentImporterId = options.parentIds[0];
1006
- const currentIsOptional = wantedDependency.optional || options.parentPkg.optional;
1007
- if (isNew) {
1008
- if (pkg.deprecated &&
1009
- (!ctx.allowedDeprecatedVersions[pkg.name] || !semver.satisfies(pkg.version, ctx.allowedDeprecatedVersions[pkg.name]))) {
1010
- // Report deprecated packages only on first occurrence.
1011
- deprecationLogger.debug({
1012
- deprecated: pkg.deprecated,
1013
- depth: options.currentDepth,
1014
- pkgId: pkgResponse.body.id,
1015
- pkgName: pkg.name,
1016
- pkgVersion: pkg.version,
1017
- prefix: options.prefix,
1018
- });
1212
+ if (pkg.engines?.runtime != null) {
1213
+ convertEnginesRuntimeToDependencies(pkg, 'engines', 'dependencies');
1019
1214
  }
1020
- if (pkgResponse.body.isInstallable === false || !parentIsInstallable) {
1021
- ctx.skipped.add(pkgResponse.body.id);
1215
+ if (!pkg.name) { // TODO: don't fail on optional dependencies
1216
+ throw new PnpmError('MISSING_PACKAGE_NAME', `Can't install ${wantedDependency.bareSpecifier}: Missing package name`);
1022
1217
  }
1023
- progressLogger.debug({
1024
- packageId: pkgResponse.body.id,
1025
- requester: ctx.lockfileDir,
1026
- status: 'resolved',
1027
- });
1028
- // WARN: It is very important to keep this sync
1029
- // Otherwise, deprecation messages for the same package might get written several times
1030
- ctx.resolvedPkgsById[pkgResponse.body.id] = getResolvedPackage({
1031
- dependencyLockfile: currentPkg.dependencyLockfile,
1032
- pkgIdWithPatchHash,
1033
- force: ctx.force,
1034
- hasBin,
1035
- patch,
1036
- pkg,
1037
- pkgResponse,
1038
- prepare,
1039
- wantedDependency,
1040
- parentImporterId,
1041
- optional: currentIsOptional,
1042
- });
1043
- }
1044
- else {
1045
- ctx.resolvedPkgsById[pkgResponse.body.id].prod = ctx.resolvedPkgsById[pkgResponse.body.id].prod || !wantedDependency.dev && !wantedDependency.optional;
1046
- ctx.resolvedPkgsById[pkgResponse.body.id].dev = ctx.resolvedPkgsById[pkgResponse.body.id].dev || wantedDependency.dev;
1047
- ctx.resolvedPkgsById[pkgResponse.body.id].optional = ctx.resolvedPkgsById[pkgResponse.body.id].optional && currentIsOptional;
1048
- if (ctx.resolvedPkgsById[pkgResponse.body.id].fetching == null && pkgResponse.fetching != null) {
1049
- ctx.resolvedPkgsById[pkgResponse.body.id].fetching = pkgResponse.fetching;
1050
- ctx.resolvedPkgsById[pkgResponse.body.id].filesIndexFile = pkgResponse.filesIndexFile;
1218
+ let pkgIdWithPatchHash = (pkgResponse.body.id.startsWith(`${pkg.name}@`) ? pkgResponse.body.id : `${pkg.name}@${pkgResponse.body.id}`);
1219
+ const patch = getPatchInfo(ctx.patchedDependencies, pkg.name, pkg.version);
1220
+ if (patch) {
1221
+ ctx.appliedPatches.add(patch.key);
1222
+ pkgIdWithPatchHash = `${pkgIdWithPatchHash}(patch_hash=${patch.hash})`;
1223
+ }
1224
+ // We are building the dependency tree only until there are new packages
1225
+ // or the packages repeat in a unique order.
1226
+ // This is needed later during peer dependencies resolution.
1227
+ //
1228
+ // So we resolve foo > bar > qar > foo
1229
+ // But we stop on foo > bar > qar > foo > qar
1230
+ // In the second example, there's no reason to walk qar again
1231
+ // when qar is included the first time, the dependencies of foo
1232
+ // are already resolved and included as parent dependencies of qar.
1233
+ // So during peers resolution, qar cannot possibly get any new or different
1234
+ // peers resolved, after the first occurrence.
1235
+ //
1236
+ // However, in the next example we would analyze the second qar as well,
1237
+ // because zoo is a new parent package:
1238
+ // foo > bar > qar > zoo > qar
1239
+ if (parentIdsContainSequence(options.parentIds, options.parentPkg.pkgId, pkgResponse.body.id) || pkgResponse.body.id === options.parentPkg.pkgId) {
1240
+ return null;
1051
1241
  }
1052
- if (ctx.dependenciesTree.has(nodeId)) {
1053
- ctx.dependenciesTree.get(nodeId).depth = Math.min(ctx.dependenciesTree.get(nodeId).depth, options.currentDepth);
1242
+ if (!options.update && (currentPkg.dependencyLockfile != null) && currentPkg.depPath &&
1243
+ !pkgResponse.body.updated &&
1244
+ // peerDependencies field is also used for transitive peer dependencies which should not be linked
1245
+ // That's why we cannot omit reading package.json of such dependencies.
1246
+ // This can be removed if we implement something like peerDependenciesMeta.transitive: true
1247
+ (currentPkg.dependencyLockfile.peerDependencies == null)) {
1248
+ hasBin = currentPkg.dependencyLockfile.hasBin === true;
1249
+ pkg = {
1250
+ ...nameVerFromPkgSnapshot(currentPkg.depPath, currentPkg.dependencyLockfile),
1251
+ ...omitDepsFields(currentPkg.dependencyLockfile),
1252
+ ...pkg,
1253
+ };
1054
1254
  }
1055
1255
  else {
1056
- ctx.pendingNodes.push({
1057
- alias: wantedDependency.alias ?? pkgResponse.body.alias ?? pkg.name,
1058
- depth: options.currentDepth,
1059
- parentIds: options.parentIds,
1060
- installable,
1061
- lockedPeerContext: currentPkg.lockedPeerContext,
1062
- previousDepPath: currentPkg.depPath,
1063
- nodeId,
1064
- resolvedPackage: ctx.resolvedPkgsById[pkgResponse.body.id],
1065
- });
1256
+ prepare = Boolean(pkgResponse.body.resolvedVia === 'git-repository' &&
1257
+ typeof pkg.scripts?.prepare === 'string');
1258
+ if (currentPkg.dependencyLockfile?.deprecated &&
1259
+ !pkgResponse.body.updated && !pkg.deprecated) {
1260
+ pkg.deprecated = currentPkg.dependencyLockfile.deprecated;
1261
+ }
1262
+ hasBin = (currentPkg.dependencyLockfile?.hasBin != null && !pkg.bin)
1263
+ ? currentPkg.dependencyLockfile.hasBin
1264
+ : Boolean((pkg.bin && !(pkg.bin === '' || Object.keys(pkg.bin).length === 0)) ?? pkg.directories?.bin);
1066
1265
  }
1067
- }
1068
- const rootDir = pkgResponse.body.resolution.type === 'directory'
1069
- ? path.resolve(ctx.lockfileDir, pkgResponse.body.resolution.directory)
1070
- : options.prefix;
1071
- let missingPeersOfChildren;
1072
- if (ctx.hoistPeers && !options.parentIds.includes(pkgResponse.body.id)) {
1073
- if (ctx.missingPeersOfChildrenByPkgId[pkgResponse.body.id]) {
1074
- // This if condition is used to avoid a dead lock.
1075
- // There might be a better way to hoist peer dependencies during resolution
1076
- // but it would probably require a big rewrite of the resolution algorithm.
1077
- if (ctx.missingPeersOfChildrenByPkgId[pkgResponse.body.id].depth >= options.currentDepth ||
1078
- ctx.missingPeersOfChildrenByPkgId[pkgResponse.body.id].missingPeersOfChildren.resolved) {
1079
- missingPeersOfChildren = ctx.missingPeersOfChildrenByPkgId[pkgResponse.body.id].missingPeersOfChildren;
1266
+ if (options.currentDepth === 0 && pkgResponse.body.latest && pkgResponse.body.latest !== pkg.version) {
1267
+ ctx.outdatedDependencies[pkgResponse.body.id] = pkgResponse.body.latest;
1268
+ }
1269
+ if (pkg.peerDependencies != null) {
1270
+ for (const name in pkg.peerDependencies) {
1271
+ ctx.allPeerDepNames.add(name);
1272
+ }
1273
+ }
1274
+ if (pkg.peerDependenciesMeta != null) {
1275
+ for (const name in pkg.peerDependenciesMeta) {
1276
+ ctx.allPeerDepNames.add(name);
1277
+ }
1278
+ }
1279
+ // In case of leaf dependencies (dependencies that have no prod deps or peer deps),
1280
+ // we only ever need to analyze one leaf dep in a graph, so the nodeId can be short and stateless.
1281
+ const nodeId = pkgIsLeaf(pkg) ? pkgResponse.body.id : nextNodeId();
1282
+ const parentIsInstallable = options.parentPkg.installable === undefined || options.parentPkg.installable;
1283
+ const installable = parentIsInstallable && pkgResponse.body.isInstallable !== false;
1284
+ const packageIsNew = !ctx.resolvedPkgsById[pkgResponse.body.id];
1285
+ const parentImporterId = options.parentIds[0];
1286
+ const currentIsOptional = wantedDependency.optional || options.parentPkg.optional;
1287
+ const childrenResolution = claimChildrenResolution(ctx, {
1288
+ currentDepth: options.currentDepth,
1289
+ parentIds: options.parentIds,
1290
+ pkgId: pkgResponse.body.id,
1291
+ });
1292
+ const isNew = childrenResolution.isOwner;
1293
+ if (packageIsNew) {
1294
+ if (pkg.deprecated &&
1295
+ (!ctx.allowedDeprecatedVersions[pkg.name] || !semver.satisfies(pkg.version, ctx.allowedDeprecatedVersions[pkg.name]))) {
1296
+ // Report deprecated packages only on first occurrence.
1297
+ deprecationLogger.debug({
1298
+ deprecated: pkg.deprecated,
1299
+ depth: options.currentDepth,
1300
+ pkgId: pkgResponse.body.id,
1301
+ pkgName: pkg.name,
1302
+ pkgVersion: pkg.version,
1303
+ prefix: options.prefix,
1304
+ });
1305
+ }
1306
+ if (pkgResponse.body.isInstallable === false || !parentIsInstallable) {
1307
+ ctx.skipped.add(pkgResponse.body.id);
1080
1308
  }
1309
+ progressLogger.debug({
1310
+ packageId: pkgResponse.body.id,
1311
+ requester: ctx.lockfileDir,
1312
+ status: 'resolved',
1313
+ });
1314
+ // WARN: It is very important to keep this sync
1315
+ // Otherwise, deprecation messages for the same package might get written several times
1316
+ ctx.resolvedPkgsById[pkgResponse.body.id] = getResolvedPackage({
1317
+ dependencyLockfile: currentPkg.dependencyLockfile,
1318
+ pkgIdWithPatchHash,
1319
+ force: ctx.force,
1320
+ hasBin,
1321
+ patch,
1322
+ pkg,
1323
+ pkgResponse,
1324
+ prepare,
1325
+ wantedDependency,
1326
+ parentImporterId,
1327
+ optional: currentIsOptional,
1328
+ });
1081
1329
  }
1082
1330
  else {
1083
- const p = pDefer();
1084
- missingPeersOfChildren = {
1085
- resolve: p.resolve,
1086
- reject: p.reject,
1087
- get: pShare(p.promise),
1088
- };
1089
- ctx.missingPeersOfChildrenByPkgId[pkgResponse.body.id] = {
1090
- depth: options.currentDepth,
1091
- missingPeersOfChildren,
1092
- };
1331
+ ctx.resolvedPkgsById[pkgResponse.body.id].prod = ctx.resolvedPkgsById[pkgResponse.body.id].prod || !wantedDependency.dev && !wantedDependency.optional;
1332
+ ctx.resolvedPkgsById[pkgResponse.body.id].dev = ctx.resolvedPkgsById[pkgResponse.body.id].dev || wantedDependency.dev;
1333
+ ctx.resolvedPkgsById[pkgResponse.body.id].optional = ctx.resolvedPkgsById[pkgResponse.body.id].optional && currentIsOptional;
1334
+ if (ctx.resolvedPkgsById[pkgResponse.body.id].fetching == null && pkgResponse.fetching != null) {
1335
+ ctx.resolvedPkgsById[pkgResponse.body.id].fetching = pkgResponse.fetching;
1336
+ ctx.resolvedPkgsById[pkgResponse.body.id].filesIndexFile = pkgResponse.filesIndexFile;
1337
+ }
1338
+ if (!isNew) {
1339
+ if (ctx.dependenciesTree.has(nodeId)) {
1340
+ ctx.dependenciesTree.get(nodeId).depth = Math.min(ctx.dependenciesTree.get(nodeId).depth, options.currentDepth);
1341
+ }
1342
+ else {
1343
+ ctx.pendingNodes.push({
1344
+ alias: wantedDependency.alias ?? pkgResponse.body.alias ?? pkg.name,
1345
+ depth: options.currentDepth,
1346
+ parentIds: options.parentIds,
1347
+ installable,
1348
+ lockedPeerContext: currentPkg.lockedPeerContext,
1349
+ previousDepPath: currentPkg.depPath,
1350
+ nodeId,
1351
+ resolvedPackage: ctx.resolvedPkgsById[pkgResponse.body.id],
1352
+ });
1353
+ }
1354
+ }
1093
1355
  }
1356
+ const rootDir = pkgResponse.body.resolution.type === 'directory'
1357
+ ? path.resolve(ctx.lockfileDir, pkgResponse.body.resolution.directory)
1358
+ : options.prefix;
1359
+ const missingPeersOfChildren = childrenResolution.missingPeersOfChildren;
1360
+ const resolvedPkg = ctx.resolvedPkgsById[pkgResponse.body.id];
1361
+ return {
1362
+ alias: wantedDependency.alias ?? pkgResponse.body.alias ?? pkg.name,
1363
+ depIsLinked,
1364
+ resolvedVia: pkgResponse.body.resolvedVia,
1365
+ isNew,
1366
+ nodeId,
1367
+ normalizedBareSpecifier: pkgResponse.body.normalizedBareSpecifier,
1368
+ missingPeersOfChildren,
1369
+ childrenResolutionId: childrenResolution.id,
1370
+ pkgId: pkgResponse.body.id,
1371
+ rootDir,
1372
+ missingPeers: getMissingPeers(pkg),
1373
+ optional: resolvedPkg.optional,
1374
+ version: resolvedPkg.version,
1375
+ saveCatalogName: wantedDependency.saveCatalogName,
1376
+ // Next fields are actually only needed when isNew = true
1377
+ installable,
1378
+ isLinkedDependency: undefined,
1379
+ pkg,
1380
+ updated: pkgResponse.body.updated,
1381
+ publishedAt: pkgResponse.body.publishedAt,
1382
+ };
1383
+ }
1384
+ finally {
1385
+ finishPackageResolution();
1094
1386
  }
1095
- const resolvedPkg = ctx.resolvedPkgsById[pkgResponse.body.id];
1096
- return {
1097
- alias: wantedDependency.alias ?? pkgResponse.body.alias ?? pkg.name,
1098
- depIsLinked,
1099
- resolvedVia: pkgResponse.body.resolvedVia,
1100
- isNew,
1101
- nodeId,
1102
- normalizedBareSpecifier: pkgResponse.body.normalizedBareSpecifier,
1103
- missingPeersOfChildren,
1104
- pkgId: pkgResponse.body.id,
1105
- rootDir,
1106
- missingPeers: getMissingPeers(pkg),
1107
- optional: resolvedPkg.optional,
1108
- version: resolvedPkg.version,
1109
- saveCatalogName: wantedDependency.saveCatalogName,
1110
- // Next fields are actually only needed when isNew = true
1111
- installable,
1112
- isLinkedDependency: undefined,
1113
- pkg,
1114
- updated: pkgResponse.body.updated,
1115
- publishedAt: pkgResponse.body.publishedAt,
1116
- };
1117
1387
  }
1118
1388
  export function getManifestFromResponse(pkgResponse, wantedDependency, currentPkg) {
1119
1389
  if (pkgResponse.body.manifest)