refactor: @pnpm/resolve-dependencies and @pnpm/core (#4085)

This commit is contained in:
Zoltan Kochan
2021-12-08 13:27:05 +02:00
committed by GitHub
parent a626c60fc3
commit ae32d313e4
23 changed files with 316 additions and 185 deletions

View File

@@ -0,0 +1,5 @@
---
"@pnpm/which-version-is-pinned": major
---
Initial release.

View File

@@ -0,0 +1,5 @@
---
"@pnpm/resolve-dependencies": major
---
Breaking changes to the API. New required options added: `defaultUpdateDepth` and `preferredVersions`.

View File

@@ -46,12 +46,12 @@
"@pnpm/store-controller-types": "workspace:11.0.7",
"@pnpm/symlink-dependency": "workspace:4.0.8",
"@pnpm/types": "workspace:7.6.0",
"@pnpm/which-version-is-pinned": "workspace:0.0.0",
"@zkochan/npm-package-arg": "^2.0.1",
"@zkochan/rimraf": "^2.1.1",
"dependency-path": "workspace:8.0.6",
"graph-sequencer": "2.0.0",
"is-inner-link": "^4.0.0",
"is-subdir": "^1.1.1",
"load-json-file": "^6.2.0",
"normalize-path": "^3.0.0",
"p-every": "^2.0.0",
@@ -62,7 +62,6 @@
"ramda": "^0.27.1",
"run-groups": "^3.0.1",
"semver": "^7.3.4",
"semver-utils": "^1.1.4",
"version-selector-type": "^3.0.0"
},
"devDependencies": {

View File

@@ -1,8 +1,7 @@
import { nameVerFromPkgSnapshot, PackageSnapshots } from '@pnpm/lockfile-utils'
import { getAllDependenciesFromManifest } from '@pnpm/manifest-utils'
import { PreferredVersions } from '@pnpm/resolver-base'
import { Dependencies, DependencyManifest, ProjectManifest } from '@pnpm/types'
import getVerSelType from 'version-selector-type'
import { DependencyManifest } from '@pnpm/types'
export function getAllUniqueSpecs (manifests: DependencyManifest[]) {
const allSpecs: Record<string, string> = {}
@@ -22,36 +21,6 @@ export function getAllUniqueSpecs (manifests: DependencyManifest[]) {
return allSpecs
}
export default function getPreferredVersionsFromPackage (
pkg: Pick<ProjectManifest, 'devDependencies' | 'dependencies' | 'optionalDependencies'>
): PreferredVersions {
return getVersionSpecsByRealNames(getAllDependenciesFromManifest(pkg))
}
function getVersionSpecsByRealNames (deps: Dependencies) {
return Object.keys(deps)
.reduce((acc, depName) => {
if (deps[depName].startsWith('npm:')) {
const pref = deps[depName].substr(4)
const index = pref.lastIndexOf('@')
const spec = pref.substr(index + 1)
const selector = getVerSelType(spec)
if (selector != null) {
const pkgName = pref.substr(0, index)
acc[pkgName] = acc[pkgName] || {}
acc[pkgName][selector.normalized] = selector.type
}
} else if (!deps[depName].includes(':')) { // we really care only about semver specs
const selector = getVerSelType(deps[depName])
if (selector != null) {
acc[depName] = acc[depName] || {}
acc[depName][selector.normalized] = selector.type
}
}
return acc
}, {})
}
export function getPreferredVersionsFromLockfile (snapshots: PackageSnapshots): PreferredVersions {
const preferredVersions: PreferredVersions = {}
for (const [depPath, snapshot] of Object.entries(snapshots)) {

View File

@@ -38,9 +38,12 @@ import resolveDependencies, {
DependenciesGraph,
DependenciesGraphNode,
} from '@pnpm/resolve-dependencies'
import getWantedDependencies, {
PinnedVersion,
WantedDependency,
} from '@pnpm/resolve-dependencies/lib/getWantedDependencies'
import {
PreferredVersions,
WorkspacePackages,
} from '@pnpm/resolver-base'
import {
DependenciesField,
@@ -61,7 +64,6 @@ import pipeWith from 'ramda/src/pipeWith'
import props from 'ramda/src/props'
import unnest from 'ramda/src/unnest'
import parseWantedDependencies from '../parseWantedDependencies'
import safeIsInnerLink from '../safeIsInnerLink'
import removeDeps from '../uninstall/removeDeps'
import allProjectsAreUpToDate from './allProjectsAreUpToDate'
import createPackageExtender from './createPackageExtender'
@@ -70,11 +72,7 @@ import extendOptions, {
InstallOptions,
StrictInstallOptions,
} from './extendInstallOptions'
import getPreferredVersionsFromPackage, { getPreferredVersionsFromLockfile, getAllUniqueSpecs } from './getPreferredVersions'
import getWantedDependencies, {
PinnedVersion,
WantedDependency,
} from './getWantedDependencies'
import { getPreferredVersionsFromLockfile, getAllUniqueSpecs } from './getPreferredVersions'
import linkPackages from './link'
const BROKEN_LOCKFILE_INTEGRITY_ERRORS = new Set([
@@ -561,51 +559,6 @@ function pkgHasDependencies (manifest: ProjectManifest) {
)
}
async function partitionLinkedPackages (
dependencies: WantedDependency[],
opts: {
projectDir: string
lockfileOnly: boolean
modulesDir: string
storeDir: string
virtualStoreDir: string
workspacePackages?: WorkspacePackages
}
) {
const nonLinkedDependencies: WantedDependency[] = []
const linkedAliases = new Set<string>()
for (const dependency of dependencies) {
if (
!dependency.alias ||
opts.workspacePackages?.[dependency.alias] != null ||
dependency.pref.startsWith('workspace:')
) {
nonLinkedDependencies.push(dependency)
continue
}
const isInnerLink = await safeIsInnerLink(opts.modulesDir, dependency.alias, {
hideAlienModules: !opts.lockfileOnly,
projectDir: opts.projectDir,
storeDir: opts.storeDir,
virtualStoreDir: opts.virtualStoreDir,
})
if (isInnerLink === true) {
nonLinkedDependencies.push(dependency)
continue
}
// This info-log might be better to be moved to the reporter
logger.info({
message: `${dependency.alias} is linked to ${opts.modulesDir} from ${isInnerLink}`,
prefix: opts.projectDir,
})
linkedAliases.add(dependency.alias)
}
return {
linkedAliases,
nonLinkedDependencies,
}
}
// If the specifier is new, the old resolution probably does not satisfy it anymore.
// By removing these resolutions we ensure that they are resolved again using the new specs.
function forgetResolutionsOfPrevWantedDeps (importer: ProjectSnapshot, wantedDeps: WantedDependency[]) {
@@ -664,7 +617,7 @@ export type ImporterToUpdate = {
pruneDirectDependencies: boolean
removePackages?: string[]
updatePackageManifest: boolean
wantedDependencies: Array<WantedDependency & { isNew?: Boolean, updateSpec?: Boolean }>
wantedDependencies: Array<WantedDependency & { isNew?: boolean, updateSpec?: boolean }>
} & DependenciesMutation
type InstallFunction = (
@@ -736,16 +689,6 @@ const _installInContext: InstallFunction = async (projects, ctx, opts) => {
opts.force ||
opts.needsFullResolution ||
ctx.lockfileHadConflicts
const _toResolveImporter = toResolveImporter.bind(null, {
defaultUpdateDepth: (opts.update || (opts.updateMatching != null)) ? opts.depth : -1,
lockfileOnly: opts.lockfileOnly,
preferredVersions,
storeDir: ctx.storeDir,
updateAll: Boolean(opts.updateMatching),
virtualStoreDir: ctx.virtualStoreDir,
workspacePackages: opts.workspacePackages,
})
const projectsToResolve = await Promise.all(projects.map(async (project) => _toResolveImporter(project)))
// Ignore some fields when fixing lockfile, so these fields can be regenerated
// and make sure it's up-to-date
@@ -776,9 +719,10 @@ const _installInContext: InstallFunction = async (projects, ctx, opts) => {
wantedToBeSkippedPackageIds,
waitTillAllFetchingsFinish,
} = await resolveDependencies(
projectsToResolve,
projects,
{
currentLockfile: ctx.currentLockfile,
defaultUpdateDepth: (opts.update || (opts.updateMatching != null)) ? opts.depth : -1,
dryRun: opts.lockfileOnly,
engineStrict: opts.engineStrict,
force: opts.force,
@@ -790,6 +734,7 @@ const _installInContext: InstallFunction = async (projects, ctx, opts) => {
nodeVersion: opts.nodeVersion,
pnpmVersion: opts.packageManager.name === 'pnpm' ? opts.packageManager.version : '',
preferWorkspacePackages: opts.preferWorkspacePackages,
preferredVersions,
preserveWorkspaceProtocol: opts.preserveWorkspaceProtocol,
registries: ctx.registries,
saveWorkspaceProtocol: opts.saveWorkspaceProtocol,
@@ -819,7 +764,7 @@ const _installInContext: InstallFunction = async (projects, ctx, opts) => {
const lockfileOpts = { forceSharedFormat: opts.forceSharedLockfile }
if (!opts.lockfileOnly && opts.enableModulesDir) {
const result = await linkPackages(
projectsToResolve,
projects,
dependenciesGraph,
{
currentLockfile: ctx.currentLockfile,
@@ -910,7 +855,7 @@ const _installInContext: InstallFunction = async (projects, ctx, opts) => {
})
}
await Promise.all(projectsToResolve.map(async (project, index) => {
await Promise.all(projects.map(async (project, index) => {
let linkedPackages!: string[]
if (ctx.publicHoistPattern?.length && path.relative(project.rootDir, opts.lockfileDir) === '') {
const nodeExecPathByAlias = Object.entries(project.manifest.dependenciesMeta ?? {})
@@ -1018,7 +963,7 @@ const _installInContext: InstallFunction = async (projects, ctx, opts) => {
return {
newLockfile,
projects: projectsToResolve.map(({ manifest, rootDir }) => ({ rootDir, manifest })),
projects: projects.map(({ manifest, rootDir }) => ({ rootDir, manifest })),
}
}
@@ -1040,68 +985,6 @@ const installInContext: InstallFunction = async (projects, ctx, opts) => {
}
}
async function toResolveImporter (
opts: {
defaultUpdateDepth: number
lockfileOnly: boolean
preferredVersions?: PreferredVersions
storeDir: string
updateAll: boolean
virtualStoreDir: string
workspacePackages: WorkspacePackages
},
project: ImporterToUpdate
) {
const allDeps = getWantedDependencies(project.manifest)
const { nonLinkedDependencies } = await partitionLinkedPackages(allDeps, {
lockfileOnly: opts.lockfileOnly,
modulesDir: project.modulesDir,
projectDir: project.rootDir,
storeDir: opts.storeDir,
virtualStoreDir: opts.virtualStoreDir,
workspacePackages: opts.workspacePackages,
})
const existingDeps = nonLinkedDependencies
.filter(({ alias }) => !project.wantedDependencies.some((wantedDep) => wantedDep.alias === alias))
let wantedDependencies!: Array<WantedDependency & { isNew?: boolean, updateDepth: number }>
if (!project.manifest) {
wantedDependencies = [
...project.wantedDependencies,
...existingDeps,
]
.map((dep) => ({
...dep,
updateDepth: opts.defaultUpdateDepth,
}))
} else {
// Direct local tarballs are always checked,
// so their update depth should be at least 0
const updateLocalTarballs = (dep: WantedDependency) => ({
...dep,
updateDepth: opts.updateAll
? opts.defaultUpdateDepth
: (prefIsLocalTarball(dep.pref) ? 0 : -1),
})
wantedDependencies = [
...project.wantedDependencies.map(
opts.defaultUpdateDepth < 0
? updateLocalTarballs
: (dep) => ({ ...dep, updateDepth: opts.defaultUpdateDepth })),
...existingDeps.map(updateLocalTarballs),
]
}
return {
...project,
hasRemovedDependencies: Boolean(project.removePackages?.length),
preferredVersions: opts.preferredVersions ?? (project.manifest && getPreferredVersionsFromPackage(project.manifest)) ?? {},
wantedDependencies,
}
}
function prefIsLocalTarball (pref: string) {
return pref.startsWith('file:') && pref.endsWith('.tgz')
}
const limitLinking = pLimit(16)
async function linkAllBins (

View File

@@ -19,7 +19,6 @@ import {
DependenciesGraph,
DependenciesGraphNode,
LinkedDependency,
ImporterToResolve,
} from '@pnpm/resolve-dependencies'
import { StoreController } from '@pnpm/store-controller-types'
import symlinkDependency, { symlinkDirectRootDependency } from '@pnpm/symlink-dependency'
@@ -34,11 +33,12 @@ import equals from 'ramda/src/equals'
import difference from 'ramda/src/difference'
import omit from 'ramda/src/omit'
import props from 'ramda/src/props'
import { ImporterToUpdate } from './index'
const brokenModulesLogger = logger('_broken_node_modules')
export default async function linkPackages (
projects: ImporterToResolve[],
projects: ImporterToUpdate[],
depGraph: DependenciesGraph,
opts: {
currentLockfile: Lockfile

View File

@@ -1,7 +1,7 @@
import parseWantedDependency from '@pnpm/parse-wanted-dependency'
import { Dependencies } from '@pnpm/types'
import guessPinnedVersionFromExistingSpec from './guessPinnedVersionFromExistingSpec'
import { PinnedVersion, WantedDependency } from './install/getWantedDependencies'
import whichVersionIsPinned from '@pnpm/which-version-is-pinned'
import { PinnedVersion, WantedDependency } from '@pnpm/resolve-dependencies/lib/getWantedDependencies'
export default function parseWantedDependencies (
rawWantedDependencies: string[],
@@ -34,7 +34,7 @@ export default function parseWantedDependencies (
? 'workspace:*'
: opts.currentPrefs[alias]
}
pinnedVersion = guessPinnedVersionFromExistingSpec(opts.currentPrefs[alias])
pinnedVersion = whichVersionIsPinned(opts.currentPrefs[alias])
}
const result = {
alias,

View File

@@ -125,6 +125,9 @@
},
{
"path": "../types"
},
{
"path": "../which-version-is-pinned"
}
]
}

View File

@@ -42,9 +42,12 @@
"@pnpm/resolver-base": "workspace:8.1.1",
"@pnpm/store-controller-types": "workspace:11.0.7",
"@pnpm/types": "workspace:7.6.0",
"@pnpm/which-version-is-pinned": "workspace:0.0.0",
"dependency-path": "workspace:8.0.6",
"encode-registry": "^3.0.0",
"get-npm-tarball-url": "^2.0.3",
"is-inner-link": "^4.0.0",
"is-subdir": "^1.1.1",
"path-exists": "^4.0.0",
"ramda": "^0.27.1",
"replace-string": "^3.1.0",

View File

@@ -5,7 +5,7 @@ import {
IncludedDependencies,
ProjectManifest,
} from '@pnpm/types'
import guessPinnedVersionFromExistingSpec from '../guessPinnedVersionFromExistingSpec'
import whichVersionIsPinned from '@pnpm/which-version-is-pinned'
export type PinnedVersion = 'major' | 'minor' | 'patch' | 'none'
@@ -71,7 +71,7 @@ function getWantedDependenciesFromGivenSet (
injected: opts.dependenciesMeta[alias]?.injected,
optional: depType === 'optional',
nodeExecPath: opts.nodeExecPath ?? opts.dependenciesMeta[alias]?.node,
pinnedVersion: guessPinnedVersionFromExistingSpec(deps[alias]),
pinnedVersion: whichVersionIsPinned(deps[alias]),
pref,
raw: `${alias}@${pref}`,
}

View File

@@ -33,6 +33,7 @@ import resolvePeers, {
GenericDependenciesGraph,
GenericDependenciesGraphNode,
} from './resolvePeers'
import toResolveImporter from './toResolveImporter'
import updateLockfile from './updateLockfile'
import updateProjectManifest from './updateProjectManifest'
@@ -73,27 +74,37 @@ export type ImporterToResolve = Importer<{
export default async function (
importers: ImporterToResolve[],
opts: ResolveDependenciesOptions & {
defaultUpdateDepth: number
preserveWorkspaceProtocol: boolean
saveWorkspaceProtocol: boolean
strictPeerDependencies: boolean
}
) {
const _toResolveImporter = toResolveImporter.bind(null, {
defaultUpdateDepth: opts.defaultUpdateDepth,
lockfileOnly: opts.dryRun,
preferredVersions: opts.preferredVersions,
updateAll: Boolean(opts.updateMatching),
virtualStoreDir: opts.virtualStoreDir,
workspacePackages: opts.workspacePackages,
})
const projectsToResolve = await Promise.all(importers.map(async (project) => _toResolveImporter(project)))
const {
dependenciesTree,
outdatedDependencies,
resolvedImporters,
resolvedPackagesByDepPath,
wantedToBeSkippedPackageIds,
} = await resolveDependencyTree(importers, opts)
} = await resolveDependencyTree(projectsToResolve, opts)
const linkedDependenciesByProjectId: Record<string, LinkedDependency[]> = {}
const projectsToLink = await Promise.all<ProjectToLink>(importers.map(async (project, index) => {
const projectsToLink = await Promise.all<ProjectToLink>(projectsToResolve.map(async (project, index) => {
const resolvedImporter = resolvedImporters[project.id]
linkedDependenciesByProjectId[project.id] = resolvedImporter.linkedDependencies
let updatedManifest: ProjectManifest | undefined = project.manifest
let updatedOriginalManifest: ProjectManifest | undefined = project.originalManifest
if (project.updatePackageManifest) {
const manifests = await updateProjectManifest(importers[index], {
const manifests = await updateProjectManifest(project, {
directDependencies: resolvedImporter.directDependencies,
preserveWorkspaceProtocol: opts.preserveWorkspaceProtocol,
saveWorkspaceProtocol: opts.saveWorkspaceProtocol,
@@ -130,13 +141,14 @@ export default async function (
)
: []
project.manifest = updatedOriginalManifest ?? project.originalManifest ?? project.manifest
const manifest = updatedOriginalManifest ?? project.originalManifest ?? project.manifest
importers[index].manifest = manifest
return {
binsDir: project.binsDir,
directNodeIdsByAlias: resolvedImporter.directNodeIdsByAlias,
id: project.id,
linkedDependencies: resolvedImporter.linkedDependencies,
manifest: project.manifest,
manifest,
modulesDir: project.modulesDir,
rootDir: project.rootDir,
topParents,

View File

@@ -2,6 +2,7 @@ import { Lockfile } from '@pnpm/lockfile-types'
import { PreferredVersions, Resolution, WorkspacePackages } from '@pnpm/resolver-base'
import { StoreController } from '@pnpm/store-controller-types'
import {
ProjectManifest,
ReadPackageHook,
Registries,
} from '@pnpm/types'
@@ -37,10 +38,16 @@ export interface ResolvedDirectDependency {
export interface Importer<T> {
id: string
hasRemovedDependencies?: boolean
manifest: ProjectManifest
modulesDir: string
preferredVersions?: PreferredVersions
removePackages?: string[]
rootDir: string
wantedDependencies: Array<T & WantedDependency>
}
export interface ImporterToResolveGeneric<T> extends Importer<T> {
hasRemovedDependencies?: boolean
preferredVersions?: PreferredVersions
wantedDependencies: Array<T & WantedDependency & { updateDepth: number }>
}
@@ -57,6 +64,7 @@ export interface ResolveDependenciesOptions {
nodeVersion: string
registries: Registries
pnpmVersion: string
preferredVersions?: PreferredVersions
preferWorkspacePackages?: boolean
updateMatching?: (pkgName: string) => boolean
linkWorkspacePackagesDepth?: number
@@ -69,7 +77,7 @@ export interface ResolveDependenciesOptions {
}
export default async function<T> (
importers: Array<Importer<T>>,
importers: Array<ImporterToResolveGeneric<T>>,
opts: ResolveDependenciesOptions
) {
const directDepsByImporterId = {} as {[id: string]: Array<PkgAddress | LinkedDependency>}

View File

@@ -10,7 +10,6 @@ export default async function safeIsInnerLink (
opts: {
hideAlienModules: boolean
projectDir: string
storeDir: string
virtualStoreDir: string
}
): Promise<true | string> {
@@ -19,7 +18,7 @@ export default async function safeIsInnerLink (
if (link.isInner) return true
if (isSubdir(opts.virtualStoreDir, link.target) || isSubdir(opts.storeDir, link.target)) return true
if (isSubdir(opts.virtualStoreDir, link.target)) return true
return link.target as string
} catch (err: any) { // eslint-disable-line

View File

@@ -0,0 +1,141 @@
import logger from '@pnpm/logger'
import { getAllDependenciesFromManifest } from '@pnpm/manifest-utils'
import {
PreferredVersions,
WorkspacePackages,
} from '@pnpm/resolver-base'
import { Dependencies, ProjectManifest } from '@pnpm/types'
import getVerSelType from 'version-selector-type'
import { ImporterToResolve } from '.'
import getWantedDependencies, { WantedDependency } from './getWantedDependencies'
import safeIsInnerLink from './safeIsInnerLink'
export default async function toResolveImporter (
opts: {
defaultUpdateDepth: number
lockfileOnly: boolean
preferredVersions?: PreferredVersions
updateAll: boolean
virtualStoreDir: string
workspacePackages: WorkspacePackages
},
project: ImporterToResolve
) {
const allDeps = getWantedDependencies(project.manifest)
const nonLinkedDependencies = await partitionLinkedPackages(allDeps, {
lockfileOnly: opts.lockfileOnly,
modulesDir: project.modulesDir,
projectDir: project.rootDir,
virtualStoreDir: opts.virtualStoreDir,
workspacePackages: opts.workspacePackages,
})
const existingDeps = nonLinkedDependencies
.filter(({ alias }) => !project.wantedDependencies.some((wantedDep) => wantedDep.alias === alias))
let wantedDependencies!: Array<WantedDependency & { isNew?: boolean, updateDepth: number }>
if (!project.manifest) {
wantedDependencies = [
...project.wantedDependencies,
...existingDeps,
]
.map((dep) => ({
...dep,
updateDepth: opts.defaultUpdateDepth,
}))
} else {
// Direct local tarballs are always checked,
// so their update depth should be at least 0
const updateLocalTarballs = (dep: WantedDependency) => ({
...dep,
updateDepth: opts.updateAll
? opts.defaultUpdateDepth
: (prefIsLocalTarball(dep.pref) ? 0 : -1),
})
wantedDependencies = [
...project.wantedDependencies.map(
opts.defaultUpdateDepth < 0
? updateLocalTarballs
: (dep) => ({ ...dep, updateDepth: opts.defaultUpdateDepth })),
...existingDeps.map(updateLocalTarballs),
]
}
return {
...project,
hasRemovedDependencies: Boolean(project.removePackages?.length),
preferredVersions: opts.preferredVersions ?? (project.manifest && getPreferredVersionsFromPackage(project.manifest)) ?? {},
wantedDependencies,
}
}
function prefIsLocalTarball (pref: string) {
return pref.startsWith('file:') && pref.endsWith('.tgz')
}
async function partitionLinkedPackages (
dependencies: WantedDependency[],
opts: {
projectDir: string
lockfileOnly: boolean
modulesDir: string
virtualStoreDir: string
workspacePackages?: WorkspacePackages
}
): Promise<WantedDependency[]> {
const nonLinkedDependencies: WantedDependency[] = []
const linkedAliases = new Set<string>()
for (const dependency of dependencies) {
if (
!dependency.alias ||
opts.workspacePackages?.[dependency.alias] != null ||
dependency.pref.startsWith('workspace:')
) {
nonLinkedDependencies.push(dependency)
continue
}
const isInnerLink = await safeIsInnerLink(opts.modulesDir, dependency.alias, {
hideAlienModules: !opts.lockfileOnly,
projectDir: opts.projectDir,
virtualStoreDir: opts.virtualStoreDir,
})
if (isInnerLink === true) {
nonLinkedDependencies.push(dependency)
continue
}
// This info-log might be better to be moved to the reporter
logger.info({
message: `${dependency.alias} is linked to ${opts.modulesDir} from ${isInnerLink}`,
prefix: opts.projectDir,
})
linkedAliases.add(dependency.alias)
}
return nonLinkedDependencies
}
function getPreferredVersionsFromPackage (
pkg: Pick<ProjectManifest, 'devDependencies' | 'dependencies' | 'optionalDependencies'>
): PreferredVersions {
return getVersionSpecsByRealNames(getAllDependenciesFromManifest(pkg))
}
function getVersionSpecsByRealNames (deps: Dependencies) {
return Object.keys(deps)
.reduce((acc, depName) => {
if (deps[depName].startsWith('npm:')) {
const pref = deps[depName].substr(4)
const index = pref.lastIndexOf('@')
const spec = pref.substr(index + 1)
const selector = getVerSelType(spec)
if (selector != null) {
const pkgName = pref.substr(0, index)
acc[pkgName] = acc[pkgName] || {}
acc[pkgName][selector.normalized] = selector.type
}
} else if (!deps[depName].includes(':')) { // we really care only about semver specs
const selector = getVerSelType(deps[depName])
if (selector != null) {
acc[depName] = acc[depName] || {}
acc[depName][selector.normalized] = selector.type
}
}
return acc
}, {})
}

View File

@@ -50,6 +50,9 @@
},
{
"path": "../types"
},
{
"path": "../which-version-is-pinned"
}
]
}

View File

@@ -0,0 +1,22 @@
# @pnpm/which-version-is-pinned
> Takes a version spec and returns which version is pinned by it
## Installation
```
pnpm add @pnpm/which-version-is-pinned
```
## Usage
```ts
import whichVersionIsPinned from '@pnpm/which-version-is-pinned'
whichVersionIsPinned('^1.0.0')
// major
```
## License
[MIT](LICENSE)

View File

@@ -0,0 +1 @@
module.exports = require('../../jest.config')

View File

@@ -0,0 +1,34 @@
{
"name": "@pnpm/which-version-is-pinned",
"description": "Takes a version spec and returns which version is pinned by it",
"version": "0.0.0",
"bugs": {
"url": "https://github.com/pnpm/pnpm/issues"
},
"main": "lib/index.js",
"types": "lib/index.d.ts",
"files": [
"lib",
"!*.map"
],
"keywords": [
"pnpm6"
],
"license": "MIT",
"engines": {
"node": ">=12.17"
},
"repository": "https://github.com/pnpm/pnpm/blob/master/packages/which-version-is-pinned",
"scripts": {
"_test": "jest",
"test": "pnpm run compile && pnpm run _test",
"lint": "eslint src/**/*.ts test/**/*.ts",
"prepublishOnly": "pnpm run compile",
"compile": "rimraf lib tsconfig.tsbuildinfo && tsc --build && pnpm run lint -- --fix"
},
"homepage": "https://github.com/pnpm/pnpm/blob/master/packages/which-version-is-pinned#readme",
"funding": "https://opencollective.com/pnpm",
"dependencies": {
"semver-utils": "^1.1.4"
}
}

View File

@@ -1,6 +1,6 @@
import { parseRange } from 'semver-utils'
export default function guessPinnedVersionFromExistingSpec (spec: string) {
export default function whichVersionIsPinned (spec: string) {
if (spec.startsWith('workspace:')) spec = spec.substr('workspace:'.length)
if (spec === '*') return 'none'
const parsedRange = parseRange(spec)

View File

@@ -0,0 +1,11 @@
import whichVersionIsPinned from '@pnpm/which-version-is-pinned'
test.each([
['^1.0.0', 'major'],
['~1.0.0', 'minor'],
['1.0.0', 'patch'],
['*', 'none'],
['workspace:^1.0.0', 'major'],
])('whichVersionIsPinned()', (spec, expectedResult) => {
expect(whichVersionIsPinned(spec)).toEqual(expectedResult)
})

View File

@@ -0,0 +1,12 @@
{
"extends": "@pnpm/tsconfig",
"compilerOptions": {
"outDir": "lib",
"rootDir": "src"
},
"include": [
"src/**/*.ts",
"../../typings/**/*.d.ts"
],
"references": []
}

View File

@@ -0,0 +1,8 @@
{
"extends": "./tsconfig.json",
"include": [
"src/**/*.ts",
"test/**/*.ts",
"../../typings/**/*.d.ts"
]
}

21
pnpm-lock.yaml generated
View File

@@ -414,6 +414,7 @@ importers:
'@pnpm/symlink-dependency': workspace:4.0.8
'@pnpm/test-fixtures': workspace:*
'@pnpm/types': workspace:7.6.0
'@pnpm/which-version-is-pinned': workspace:0.0.0
'@types/fs-extra': ^9.0.5
'@types/is-ci': ^3.0.0
'@types/is-windows': ^1.0.0
@@ -432,7 +433,6 @@ importers:
graph-sequencer: 2.0.0
is-ci: ^3.0.0
is-inner-link: ^4.0.0
is-subdir: ^1.1.1
is-windows: ^1.0.2
load-json-file: ^6.2.0
ncp: ^2.0.0
@@ -449,7 +449,6 @@ importers:
resolve-link-target: ^2.0.0
run-groups: ^3.0.1
semver: ^7.3.4
semver-utils: ^1.1.4
sinon: ^11.1.1
symlink-dir: ^5.0.0
version-selector-type: ^3.0.0
@@ -487,12 +486,12 @@ importers:
'@pnpm/store-controller-types': link:../store-controller-types
'@pnpm/symlink-dependency': link:../symlink-dependency
'@pnpm/types': link:../types
'@pnpm/which-version-is-pinned': link:../which-version-is-pinned
'@zkochan/npm-package-arg': 2.0.1
'@zkochan/rimraf': 2.1.1
dependency-path: link:../dependency-path
graph-sequencer: 2.0.0
is-inner-link: 4.0.0
is-subdir: 1.2.0
load-json-file: 6.2.0
normalize-path: 3.0.0
p-every: 2.0.0
@@ -503,7 +502,6 @@ importers:
ramda: 0.27.1
run-groups: 3.0.1
semver: 7.3.5
semver-utils: 1.1.4
version-selector-type: 3.0.0
devDependencies:
'@pnpm/assert-project': link:../../privatePackages/assert-project
@@ -3067,11 +3065,14 @@ importers:
'@pnpm/resolver-base': workspace:8.1.1
'@pnpm/store-controller-types': workspace:11.0.7
'@pnpm/types': workspace:7.6.0
'@pnpm/which-version-is-pinned': workspace:0.0.0
'@types/ramda': 0.27.39
'@types/semver': ^7.3.4
dependency-path: workspace:8.0.6
encode-registry: ^3.0.0
get-npm-tarball-url: ^2.0.3
is-inner-link: ^4.0.0
is-subdir: ^1.1.1
path-exists: ^4.0.0
ramda: ^0.27.1
replace-string: ^3.1.0
@@ -3091,9 +3092,12 @@ importers:
'@pnpm/resolver-base': link:../resolver-base
'@pnpm/store-controller-types': link:../store-controller-types
'@pnpm/types': link:../types
'@pnpm/which-version-is-pinned': link:../which-version-is-pinned
dependency-path: link:../dependency-path
encode-registry: 3.0.0
get-npm-tarball-url: 2.0.3
is-inner-link: 4.0.0
is-subdir: 1.2.0
path-exists: 4.0.0
ramda: 0.27.1
replace-string: 3.1.0
@@ -3305,6 +3309,15 @@ importers:
devDependencies:
'@pnpm/types': 'link:'
packages/which-version-is-pinned:
specifiers:
'@pnpm/which-version-is-pinned': 'link:'
semver-utils: ^1.1.4
dependencies:
semver-utils: 1.1.4
devDependencies:
'@pnpm/which-version-is-pinned': 'link:'
packages/write-project-manifest:
specifiers:
'@pnpm/types': workspace:7.6.0