feat(core): overrides, packageExtensions, and neverBuiltDependencies are options (#4050)

This commit is contained in:
Zoltan Kochan
2021-11-30 18:01:11 +02:00
committed by GitHub
parent 112d713952
commit 8a99a01ff6
23 changed files with 152 additions and 121 deletions

View File

@@ -0,0 +1,5 @@
---
"@pnpm/plugin-commands-installation": major
---
Pass `packageExtensions`, `overrides`, and `neverBuiltDependencies` to the core API. Take this information from `rootProjectManifest`, which should be passed in via the options.

View File

@@ -0,0 +1,5 @@
---
"@pnpm/core": major
---
`packageExtensions`, `overrides`, and `neverBuiltDependencies` are passed through as options to the core API. These settings are not read from the root manifest's `package.json`.

View File

@@ -0,0 +1,5 @@
---
"@pnpm/config": minor
---
Read the root project manifest and write it to the config object.

View File

@@ -36,6 +36,7 @@
"@pnpm/error": "workspace:2.0.0",
"@pnpm/global-bin-dir": "workspace:3.0.0",
"@pnpm/pnpmfile": "workspace:1.2.0",
"@pnpm/read-project-manifest": "workspace:2.0.7",
"@pnpm/types": "workspace:7.6.0",
"@zkochan/npm-conf": "2.0.2",
"camelcase": "^6.2.0",

View File

@@ -1,5 +1,6 @@
import {
Project,
ProjectManifest,
ProjectsGraph,
Registries,
} from '@pnpm/types'
@@ -140,6 +141,7 @@ export interface Config {
testPattern?: string[]
changedFilesIgnorePattern?: string[]
extendNodePath?: boolean
rootProjectManifest?: ProjectManifest
}
export interface ConfigWithDeprecatedSettings extends Config {

View File

@@ -5,6 +5,7 @@ import { LAYOUT_VERSION } from '@pnpm/constants'
import PnpmError from '@pnpm/error'
import globalBinDir from '@pnpm/global-bin-dir'
import { requireHooks } from '@pnpm/pnpmfile'
import { safeReadProjectManifestOnly } from '@pnpm/read-project-manifest'
import camelcase from 'camelcase'
import loadNpmConf from '@zkochan/npm-conf'
import npmTypes from '@zkochan/npm-conf/lib/types'
@@ -483,6 +484,7 @@ export default async (
if (!pnpmConfig.ignorePnpmfile) {
pnpmConfig.hooks = requireHooks(pnpmConfig.lockfileDir ?? pnpmConfig.dir, pnpmConfig)
}
pnpmConfig.rootProjectManifest = await safeReadProjectManifestOnly(pnpmConfig.lockfileDir ?? pnpmConfig.dir) ?? undefined
return { config: pnpmConfig, warnings }
}

View File

@@ -24,6 +24,9 @@
{
"path": "../pnpmfile"
},
{
"path": "../read-project-manifest"
},
{
"path": "../types"
}

View File

@@ -6,6 +6,7 @@ import normalizeRegistries, { DEFAULT_REGISTRIES } from '@pnpm/normalize-registr
import { WorkspacePackages } from '@pnpm/resolver-base'
import { StoreController } from '@pnpm/store-controller-types'
import {
PackageExtension,
ReadPackageHook,
Registries,
} from '@pnpm/types'
@@ -44,8 +45,10 @@ export interface StrictInstallOptions {
rawConfig: object
verifyStoreIntegrity: boolean
engineStrict: boolean
neverBuiltDependencies: string[]
nodeExecPath?: string
nodeVersion: string
packageExtensions: Record<string, PackageExtension>
packageManager: {
name: string
version: string
@@ -67,6 +70,7 @@ export interface StrictInstallOptions {
unsafePerm: boolean
registries: Registries
tag: string
overrides: Record<string, string>
ownLifecycleHooksStdio: 'inherit' | 'pipe'
workspacePackages: WorkspacePackages
pruneStore: boolean
@@ -120,9 +124,12 @@ const defaults = async (opts: InstallOptions) => {
},
lockfileDir: opts.lockfileDir ?? opts.dir ?? process.cwd(),
lockfileOnly: false,
neverBuiltDependencies: [] as string[],
nodeVersion: process.version,
overrides: {},
ownLifecycleHooksStdio: 'inherit',
ignorePackageManifest: false,
packageExtensions: {},
packageManager,
preferFrozenLockfile: true,
preferWorkspacePackages: false,

View File

@@ -166,19 +166,11 @@ export async function mutateModules (
// When running install/update on a subset of projects, the root project might not be included,
// so reading its manifest explicitly here.
await safeReadProjectManifestOnly(opts.lockfileDir)
// We read Yarn's resolutions field for compatibility
// but we really replace the version specs to any other version spec, not only to exact versions,
// so we cannot call it resolutions
const overrides = (rootProjectManifest != null)
? rootProjectManifest.pnpm?.overrides ?? rootProjectManifest.resolutions
: undefined
const neverBuiltDependencies = rootProjectManifest?.pnpm?.neverBuiltDependencies ?? []
const packageExtensions = rootProjectManifest?.pnpm?.packageExtensions
opts.hooks.readPackage = createReadPackageHook({
readPackageHook: opts.hooks.readPackage,
overrides,
overrides: opts.overrides,
lockfileDir: opts.lockfileDir,
packageExtensions,
packageExtensions: opts.packageExtensions,
})
const ctx = await getContext(projects, opts)
const pruneVirtualStore = ctx.modulesFile?.prunedAt && opts.modulesCacheMaxAge > 0
@@ -225,15 +217,15 @@ export async function mutateModules (
}
)
}
const packageExtensionsChecksum = isEmpty(packageExtensions ?? {}) ? undefined : createObjectChecksum(packageExtensions!)
const packageExtensionsChecksum = isEmpty(opts.packageExtensions ?? {}) ? undefined : createObjectChecksum(opts.packageExtensions!)
let needsFullResolution = !maybeOpts.ignorePackageManifest && (
!equals(ctx.wantedLockfile.overrides ?? {}, overrides ?? {}) ||
!equals((ctx.wantedLockfile.neverBuiltDependencies ?? []).sort(), (neverBuiltDependencies ?? []).sort()) ||
!equals(ctx.wantedLockfile.overrides ?? {}, opts.overrides ?? {}) ||
!equals((ctx.wantedLockfile.neverBuiltDependencies ?? []).sort(), (opts.neverBuiltDependencies ?? []).sort()) ||
ctx.wantedLockfile.packageExtensionsChecksum !== packageExtensionsChecksum) ||
opts.fixLockfile
if (needsFullResolution) {
ctx.wantedLockfile.overrides = overrides
ctx.wantedLockfile.neverBuiltDependencies = neverBuiltDependencies
ctx.wantedLockfile.overrides = opts.overrides
ctx.wantedLockfile.neverBuiltDependencies = opts.neverBuiltDependencies
ctx.wantedLockfile.packageExtensionsChecksum = packageExtensionsChecksum
}
const frozenLockfile = opts.frozenLockfile ||
@@ -496,8 +488,6 @@ export async function mutateModules (
currentLockfileIsUpToDate: !ctx.existsWantedLockfile || ctx.currentLockfileIsUpToDate,
makePartialCurrentLockfile,
needsFullResolution,
neverBuiltDependencies,
overrides,
pruneVirtualStore,
updateLockfileMinorVersion: true,
})

View File

@@ -446,9 +446,9 @@ test('scripts have access to unlisted bins when hoisting is used', async () => {
test('selectively ignore scripts in some dependencies', async () => {
const project = prepareEmpty()
const neverBuiltDependencies = ['pre-and-postinstall-scripts-example']
const manifest = await addDependenciesToPackage({ pnpm: { neverBuiltDependencies } },
const manifest = await addDependenciesToPackage({},
['pre-and-postinstall-scripts-example', 'install-script-example'],
await testDefaults({ fastUnpack: false })
await testDefaults({ fastUnpack: false, neverBuiltDependencies })
)
expect(await exists('node_modules/pre-and-postinstall-scripts-example/generated-by-preinstall.js')).toBeFalsy()
@@ -462,7 +462,7 @@ test('selectively ignore scripts in some dependencies', async () => {
await rimraf('node_modules')
await install(manifest, await testDefaults({ fastUnpack: false, frozenLockfile: true }))
await install(manifest, await testDefaults({ fastUnpack: false, frozenLockfile: true, neverBuiltDependencies }))
expect(await exists('node_modules/pre-and-postinstall-scripts-example/generated-by-preinstall.js')).toBeFalsy()
expect(await exists('node_modules/pre-and-postinstall-scripts-example/generated-by-postinstall.js')).toBeFalsy()
@@ -484,7 +484,6 @@ test('lockfile is updated if neverBuiltDependencies is changed', async () => {
}
const neverBuiltDependencies = ['pre-and-postinstall-scripts-example']
manifest.pnpm = { neverBuiltDependencies }
await mutateModules([
{
buildIndex: 0,
@@ -492,7 +491,7 @@ test('lockfile is updated if neverBuiltDependencies is changed', async () => {
mutation: 'install',
rootDir: process.cwd(),
},
], await testDefaults())
], await testDefaults({ neverBuiltDependencies }))
{
const lockfile = await project.readLockfile()

View File

@@ -1174,16 +1174,6 @@ test('resolve a subdependency from the workspace and use it as a peer', async ()
test('resolve a subdependency from the workspace, when it uses the workspace protocol', async () => {
preparePackages([
{
location: '.',
package: {
pnpm: {
overrides: {
'dep-of-pkg-with-1-dep': 'workspace:*',
},
},
},
},
{
location: 'project',
package: { name: 'project' },
@@ -1229,7 +1219,14 @@ test('resolve a subdependency from the workspace, when it uses the workspace pro
},
},
}
await mutateModules(importers, await testDefaults({ linkWorkspacePackagesDepth: -1, workspacePackages }))
const overrides = {
'dep-of-pkg-with-1-dep': 'workspace:*',
}
await mutateModules(importers, await testDefaults({
linkWorkspacePackagesDepth: -1,
overrides,
workspacePackages,
}))
const project = assertProject(process.cwd())
@@ -1241,6 +1238,7 @@ test('resolve a subdependency from the workspace, when it uses the workspace pro
// Testing that headless installation does not fail with links in subdeps
await mutateModules(importers, await testDefaults({
frozenLockfile: true,
overrides,
workspacePackages,
}))
})

View File

@@ -6,21 +6,21 @@ import {
testDefaults,
} from '../utils'
test('versions are replaced with versions specified through pnpm.overrides field', async () => {
test('versions are replaced with versions specified through overrides option', async () => {
const project = prepareEmpty()
await addDistTag({ package: 'bar', version: '100.0.0', distTag: 'latest' })
await addDistTag({ package: 'foo', version: '100.0.0', distTag: 'latest' })
const manifest = await addDependenciesToPackage({
pnpm: {
overrides: {
'foobarqar>foo': 'npm:qar@100.0.0',
'bar@^100.0.0': '100.1.0',
'dep-of-pkg-with-1-dep': '101.0.0',
},
},
}, ['pkg-with-1-dep@100.0.0', 'foobar@100.0.0', 'foobarqar@1.0.0'], await testDefaults())
const overrides = {
'foobarqar>foo': 'npm:qar@100.0.0',
'bar@^100.0.0': '100.1.0',
'dep-of-pkg-with-1-dep': '101.0.0',
}
const manifest = await addDependenciesToPackage({},
['pkg-with-1-dep@100.0.0', 'foobar@100.0.0', 'foobarqar@1.0.0'],
await testDefaults({ overrides })
)
{
const lockfile = await project.readLockfile()
@@ -44,12 +44,12 @@ test('versions are replaced with versions specified through pnpm.overrides field
mutation: 'install',
rootDir: process.cwd(),
},
], { ...await testDefaults(), ignorePackageManifest: true })
], { ...await testDefaults(), ignorePackageManifest: true, overrides })
// The lockfile is updated if the overrides are changed
manifest.pnpm!.overrides!['bar@^100.0.0'] = '100.0.0'
overrides['bar@^100.0.0'] = '100.0.0'
// A direct dependency may be overriden as well
manifest.pnpm!.overrides!['foobarqar'] = '1.0.1'
overrides['foobarqar'] = '1.0.1'
await mutateModules([
{
buildIndex: 0,
@@ -57,7 +57,7 @@ test('versions are replaced with versions specified through pnpm.overrides field
mutation: 'install',
rootDir: process.cwd(),
},
], await testDefaults())
], await testDefaults({ overrides }))
{
const lockfile = await project.readLockfile()
@@ -81,7 +81,7 @@ test('versions are replaced with versions specified through pnpm.overrides field
mutation: 'install',
rootDir: process.cwd(),
},
], await testDefaults({ frozenLockfile: true }))
], await testDefaults({ frozenLockfile: true, overrides }))
{
const lockfile = await project.readLockfile()
@@ -95,7 +95,7 @@ test('versions are replaced with versions specified through pnpm.overrides field
expect(lockfile.overrides).toStrictEqual(currentLockfile.overrides)
}
manifest.pnpm!.overrides!['bar@^100.0.0'] = '100.0.1'
overrides['bar@^100.0.0'] = '100.0.1'
await expect(
mutateModules([
{
@@ -104,54 +104,10 @@ test('versions are replaced with versions specified through pnpm.overrides field
mutation: 'install',
rootDir: process.cwd(),
},
], await testDefaults({ frozenLockfile: true }))
], await testDefaults({ frozenLockfile: true, overrides }))
).rejects.toThrow(
new PnpmError('FROZEN_LOCKFILE_WITH_OUTDATED_LOCKFILE',
'Cannot perform a frozen installation because the lockfile needs updates'
)
)
})
test('versions are replaced with versions specified through "resolutions" field (for Yarn compatibility)', async () => {
const project = prepareEmpty()
await addDistTag({ package: 'bar', version: '100.0.0', distTag: 'latest' })
const manifest = await addDependenciesToPackage({
resolutions: {
'bar@^100.0.0': '100.1.0',
'dep-of-pkg-with-1-dep': '101.0.0',
},
}, ['pkg-with-1-dep@100.0.0', 'foobar@100.0.0'], await testDefaults())
{
const lockfile = await project.readLockfile()
expect(lockfile.packages).toHaveProperty(['/dep-of-pkg-with-1-dep/101.0.0'])
expect(lockfile.packages).toHaveProperty(['/bar/100.1.0'])
expect(lockfile.overrides).toStrictEqual({
'bar@^100.0.0': '100.1.0',
'dep-of-pkg-with-1-dep': '101.0.0',
})
}
// The lockfile is updated if the resolutions are changed
manifest.resolutions!['bar@^100.0.0'] = '100.0.0'
await mutateModules([
{
buildIndex: 0,
manifest,
mutation: 'install',
rootDir: process.cwd(),
},
], await testDefaults())
{
const lockfile = await project.readLockfile()
expect(lockfile.packages).toHaveProperty(['/dep-of-pkg-with-1-dep/101.0.0'])
expect(lockfile.packages).toHaveProperty(['/bar/100.0.0'])
expect(lockfile.overrides).toStrictEqual({
'bar@^100.0.0': '100.0.0',
'dep-of-pkg-with-1-dep': '101.0.0',
})
}
})

View File

@@ -6,20 +6,21 @@ import {
testDefaults,
} from '../utils'
test('manifests are extended with fields specified by pnpm.packageExtensions', async () => {
test('manifests are extended with fields specified by packageExtensions', async () => {
const project = prepareEmpty()
const manifest = await addDependenciesToPackage({
pnpm: {
packageExtensions: {
'is-positive': {
dependencies: {
bar: '100.1.0',
},
},
const packageExtensions = {
'is-positive': {
dependencies: {
bar: '100.1.0',
},
},
}, ['is-positive@1.0.0'], await testDefaults())
}
const manifest = await addDependenciesToPackage(
{},
['is-positive@1.0.0'],
await testDefaults({ packageExtensions })
)
{
const lockfile = await project.readLockfile()
@@ -36,7 +37,7 @@ test('manifests are extended with fields specified by pnpm.packageExtensions', a
}
// The lockfile is updated if the overrides are changed
manifest.pnpm!.packageExtensions!['is-positive'].dependencies!['foobar'] = '100.0.0'
packageExtensions['is-positive'].dependencies!['foobar'] = '100.0.0'
await mutateModules([
{
buildIndex: 0,
@@ -44,7 +45,7 @@ test('manifests are extended with fields specified by pnpm.packageExtensions', a
mutation: 'install',
rootDir: process.cwd(),
},
], await testDefaults())
], await testDefaults({ packageExtensions }))
{
const lockfile = await project.readLockfile()
@@ -68,7 +69,7 @@ test('manifests are extended with fields specified by pnpm.packageExtensions', a
mutation: 'install',
rootDir: process.cwd(),
},
], await testDefaults({ frozenLockfile: true }))
], await testDefaults({ frozenLockfile: true, packageExtensions }))
{
const lockfile = await project.readLockfile()
@@ -84,7 +85,7 @@ test('manifests are extended with fields specified by pnpm.packageExtensions', a
expect(lockfile.packageExtensionsChecksum).toStrictEqual(currentLockfile.packageExtensionsChecksum)
}
manifest.pnpm!.packageExtensions!['is-positive'].dependencies!['bar'] = '100.0.1'
packageExtensions['is-positive'].dependencies!['bar'] = '100.0.1'
await expect(
mutateModules([
{
@@ -93,7 +94,7 @@ test('manifests are extended with fields specified by pnpm.packageExtensions', a
mutation: 'install',
rootDir: process.cwd(),
},
], await testDefaults({ frozenLockfile: true }))
], await testDefaults({ frozenLockfile: true, packageExtensions }))
).rejects.toThrow(
new PnpmError('FROZEN_LOCKFILE_WITH_OUTDATED_LOCKFILE',
'Cannot perform a frozen installation because the lockfile needs updates'

View File

@@ -0,0 +1,15 @@
import { ProjectManifest } from '@pnpm/types'
export default function getOptionsFromRootManifest (manifest: ProjectManifest) {
// We read Yarn's resolutions field for compatibility
// but we really replace the version specs to any other version spec, not only to exact versions,
// so we cannot call it resolutions
const overrides = manifest.pnpm?.overrides ?? manifest.resolutions
const neverBuiltDependencies = manifest.pnpm?.neverBuiltDependencies ?? []
const packageExtensions = manifest.pnpm?.packageExtensions
return {
overrides,
neverBuiltDependencies,
packageExtensions,
}
}

View File

@@ -21,6 +21,7 @@ import { parse as parseYarnLock } from '@yarnpkg/lockfile'
import * as yarnCore from '@yarnpkg/core'
import { parseSyml } from '@yarnpkg/parsers'
import exists from 'path-exists'
import getOptionsFromRootManifest from '../getOptionsFromRootManifest'
import recursive from '../recursive'
import { yarnLockFileKeyNormalizer } from './yarnUtil'
@@ -143,14 +144,16 @@ export async function handler (
}
const store = await createOrConnectStoreController(opts)
const manifest = await readProjectManifestOnly(opts.dir)
const installOpts = {
...opts,
...getOptionsFromRootManifest(manifest),
lockfileOnly: true,
preferredVersions,
storeController: store.ctrl,
storeDir: store.dir,
}
await install(await readProjectManifestOnly(opts.dir), installOpts)
await install(manifest, installOpts)
}
async function readYarnLockFile (dir: string) {
@@ -279,4 +282,4 @@ function getYarnLockfileType (
return lockFileContents.includes('__metadata')
? YarnLockType.yarn2
: YarnLockType.yarn
}
}

View File

@@ -18,6 +18,7 @@ import {
import logger from '@pnpm/logger'
import { sequenceGraph } from '@pnpm/sort-packages'
import isSubdir from 'is-subdir'
import getOptionsFromRootManifest from './getOptionsFromRootManifest'
import getPinnedVersion from './getPinnedVersion'
import getSaveType from './getSaveType'
import getNodeExecPath from './nodeExecPath'
@@ -161,9 +162,18 @@ when running add/update with the --workspace option')
workspacePackages = arrayOfWorkspacePackagesToMap(allProjects)
}
let { manifest, writeProjectManifest } = await tryReadProjectManifest(opts.dir, opts)
if (manifest === null) {
if (opts.update) {
throw new PnpmError('NO_IMPORTER_MANIFEST', 'No package.json found')
}
manifest = {}
}
const store = await createOrConnectStoreController(opts)
const installOpts = {
...opts,
...getOptionsFromRootManifest(manifest),
forceHoistPattern,
forcePublicHoistPattern,
// In case installation is done in a multi-package repository
@@ -184,14 +194,6 @@ when running add/update with the --workspace option')
}
}
let { manifest, writeProjectManifest } = await tryReadProjectManifest(opts.dir, opts)
if (manifest === null) {
if (opts.update) {
throw new PnpmError('NO_IMPORTER_MANIFEST', 'No package.json found')
}
manifest = {}
}
const updateMatch = opts.update && (params.length > 0) ? createMatcher(params) : null
if (updateMatch != null) {
params = matchDependencies(updateMatch, manifest, includeDirect)

View File

@@ -27,6 +27,7 @@ import pick from 'ramda/src/pick'
import partition from 'ramda/src/partition'
import renderHelp from 'render-help'
import * as installCommand from './install'
import getOptionsFromRootManifest from './getOptionsFromRootManifest'
import getSaveType from './getSaveType'
const isWindows = process.platform === 'win32' || global['FAKE_WINDOWS']
@@ -140,6 +141,7 @@ export async function handler (
await install(
await readProjectManifestOnly(dir, opts), {
...config,
...getOptionsFromRootManifest(config.rootProjectManifest ?? {}),
include: {
dependencies: config.production !== false,
devDependencies: config.dev !== false,

View File

@@ -5,6 +5,7 @@ import { createOrConnectStoreController, CreateStoreControllerOptions } from '@p
import { InstallOptions, mutateModules } from '@pnpm/core'
import pick from 'ramda/src/pick'
import renderHelp from 'render-help'
import getOptionsFromRootManifest from './getOptionsFromRootManifest'
export const rcOptionsTypes = cliOptionsTypes
@@ -44,19 +45,21 @@ export function help () {
}
export async function handler (
opts: Pick<Config, 'dev' | 'engineStrict' | 'optional' | 'production'> & CreateStoreControllerOptions
opts: Pick<Config, 'dev' | 'engineStrict' | 'optional' | 'production' | 'rootProjectManifest'> & CreateStoreControllerOptions
) {
const store = await createOrConnectStoreController(opts)
const manifest = await readProjectManifestOnly(process.cwd(), opts)
return mutateModules([
{
buildIndex: 0,
manifest: await readProjectManifestOnly(process.cwd(), opts),
manifest,
mutation: 'install',
pruneDirectDependencies: true,
rootDir: process.cwd(),
},
], {
...opts,
...getOptionsFromRootManifest(opts.rootProjectManifest ?? {}),
include: {
dependencies: opts.production !== false,
devDependencies: opts.dev !== false,

View File

@@ -34,6 +34,7 @@ import mem from 'mem'
import pFilter from 'p-filter'
import pLimit from 'p-limit'
import readIniFile from 'read-ini-file'
import getOptionsFromRootManifest from './getOptionsFromRootManifest'
import { createWorkspaceSpecs, updateToWorkspacePackagesFromManifest } from './updateWorkspaceDependencies'
import updateToLatestSpecsFromManifest, { createLatestSpecs } from './updateToLatestSpecsFromManifest'
import getSaveType from './getSaveType'
@@ -122,6 +123,7 @@ export default async function recursive (
: {}
const targetDependenciesField = getSaveType(opts)
const installOpts = Object.assign(opts, {
...getOptionsFromRootManifest(manifestsByPath[opts.lockfileDir ?? opts.dir]?.manifest ?? {}),
linkWorkspacePackagesDepth: opts.linkWorkspacePackages === 'deep' ? Infinity : opts.linkWorkspacePackages ? 0 : -1,
ownLifecycleHooksStdio: 'pipe',
peer: opts.savePeer,
@@ -356,6 +358,7 @@ export default async function recursive (
{
...installOpts,
...localConfig,
...getOptionsFromRootManifest(manifest),
bin: path.join(rootDir, 'node_modules', '.bin'),
dir: rootDir,
hooks,

View File

@@ -17,6 +17,7 @@ import {
import pick from 'ramda/src/pick'
import without from 'ramda/src/without'
import renderHelp from 'render-help'
import getOptionsFromRootManifest from './getOptionsFromRootManifest'
import getSaveType from './getSaveType'
import recursive from './recursive'
@@ -140,6 +141,7 @@ export async function handler (
| 'production'
| 'rawLocalConfig'
| 'registries'
| 'rootProjectManifest'
| 'saveDev'
| 'saveOptional'
| 'saveProd'
@@ -162,6 +164,7 @@ export async function handler (
}
const store = await createOrConnectStoreController(opts)
const removeOpts = Object.assign(opts, {
...getOptionsFromRootManifest(opts.rootProjectManifest ?? {}),
storeController: store.ctrl,
storeDir: store.dir,
include,

View File

@@ -4,6 +4,7 @@ import { Config } from '@pnpm/config'
import { createOrConnectStoreController, CreateStoreControllerOptions } from '@pnpm/store-connection-manager'
import { mutateModules } from '@pnpm/core'
import renderHelp from 'render-help'
import getOptionsFromRootManifest from './getOptionsFromRootManifest'
import { cliOptionsTypes, rcOptionsTypes } from './install'
import recursive from './recursive'
@@ -51,6 +52,7 @@ export async function handler (
| 'selectedProjectsGraph'
| 'rawLocalConfig'
| 'registries'
| 'rootProjectManifest'
| 'pnpmfile'
| 'workspaceDir'
> & {
@@ -64,6 +66,7 @@ export async function handler (
}
const store = await createOrConnectStoreController(opts)
const unlinkOpts = Object.assign(opts, {
...getOptionsFromRootManifest(opts.rootProjectManifest ?? {}),
globalBin: opts.bin,
storeController: store.ctrl,
storeDir: store.dir,

View File

@@ -0,0 +1,21 @@
import getOptionsFromRootManifest from '@pnpm/plugin-commands-installation/lib/getOptionsFromRootManifest'
test('getOptionsFromRootManifest() should read "resolutions" field for compatibility with Yarn', () => {
const options = getOptionsFromRootManifest({
resolutions: {
foo: '1.0.0',
},
})
expect(options.overrides).toStrictEqual({ foo: '1.0.0' })
})
test('getOptionsFromRootManifest() should read "overrides" field', () => {
const options = getOptionsFromRootManifest({
pnpm: {
overrides: {
foo: '1.0.0',
},
},
})
expect(options.overrides).toStrictEqual({ foo: '1.0.0' })
})

2
pnpm-lock.yaml generated
View File

@@ -330,6 +330,7 @@ importers:
'@pnpm/global-bin-dir': workspace:3.0.0
'@pnpm/pnpmfile': workspace:1.2.0
'@pnpm/prepare': workspace:0.0.28
'@pnpm/read-project-manifest': workspace:2.0.7
'@pnpm/types': workspace:7.6.0
'@types/ramda': 0.27.39
'@types/which': ^2.0.0
@@ -347,6 +348,7 @@ importers:
'@pnpm/error': link:../error
'@pnpm/global-bin-dir': link:../global-bin-dir
'@pnpm/pnpmfile': link:../pnpmfile
'@pnpm/read-project-manifest': link:../read-project-manifest
'@pnpm/types': link:../types
'@zkochan/npm-conf': 2.0.2
camelcase: 6.2.1