mirror of
https://github.com/pnpm/pnpm.git
synced 2025-12-23 23:29:17 -05:00
7
.changeset/eight-poets-hug.md
Normal file
7
.changeset/eight-poets-hug.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"@pnpm/read-projects-context": major
|
||||
---
|
||||
|
||||
`hoistedDependencies` is returned instead of `hoistedAliases`.
|
||||
|
||||
`currentPublicHoistPattern` is returned instead of `shamefullyHoist`.
|
||||
5
.changeset/few-moose-tease.md
Normal file
5
.changeset/few-moose-tease.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@pnpm/types": minor
|
||||
---
|
||||
|
||||
Added a new type: HoistedDependencies.
|
||||
5
.changeset/fluffy-wasps-sort.md
Normal file
5
.changeset/fluffy-wasps-sort.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@pnpm/matcher": patch
|
||||
---
|
||||
|
||||
When no patterns are passed in, create a matcher that always returns `false`.
|
||||
5
.changeset/fresh-rules-collect.md
Normal file
5
.changeset/fresh-rules-collect.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@pnpm/hoist": major
|
||||
---
|
||||
|
||||
Breaking changes in the API.
|
||||
7
.changeset/nervous-turtles-pull.md
Normal file
7
.changeset/nervous-turtles-pull.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"@pnpm/modules-cleaner": major
|
||||
---
|
||||
|
||||
Replaced `hoistedAliases` with `hoistedDependencies`.
|
||||
|
||||
Added `publicHoistedModulesDir` option.
|
||||
6
.changeset/red-seas-enjoy.md
Normal file
6
.changeset/red-seas-enjoy.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@pnpm/config": minor
|
||||
"@pnpm/plugin-commands-installation": minor
|
||||
---
|
||||
|
||||
Added a new setting: `public-hoist-pattern`. This setting can be overwritten by `--[no-]shamefully-hoist`. The default value of `public-hoist-pattern` is `types/*`.
|
||||
5
.changeset/shy-doors-approve.md
Normal file
5
.changeset/shy-doors-approve.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"supi": minor
|
||||
---
|
||||
|
||||
`shamefullyHoist` replaced by `publicHoistPattern` and `forcePublicHoistPattern`.
|
||||
7
.changeset/swift-forks-invent.md
Normal file
7
.changeset/swift-forks-invent.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"@pnpm/headless": major
|
||||
---
|
||||
|
||||
`hoistedAliases` replaced with `hoistedDependencies`.
|
||||
|
||||
`shamefullyHoist` replaced with `publicHoistPattern`.
|
||||
9
.changeset/two-houses-smoke.md
Normal file
9
.changeset/two-houses-smoke.md
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
"@pnpm/get-context": major
|
||||
---
|
||||
|
||||
`hoistedAliases` replaced with `hoistedDependencies`.
|
||||
|
||||
`shamefullyHoist` replaced with `publicHoistPattern`.
|
||||
|
||||
`forceShamefullyHoist` replaced with `forcePublicHoistPattern`.
|
||||
9
.changeset/warm-plums-ring.md
Normal file
9
.changeset/warm-plums-ring.md
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
"@pnpm/headless": major
|
||||
"@pnpm/modules-yaml": major
|
||||
"supi": minor
|
||||
---
|
||||
|
||||
Breaking changes to the `node_modules/.modules.yaml` file:
|
||||
* `hoistedAliases` replaced with `hoistedDependencies`.
|
||||
* `shamefullyHoist` replaced with `publicHoistPattern`.
|
||||
@@ -99,6 +99,7 @@ export interface Config {
|
||||
pnpmfile: string,
|
||||
packageImportMethod?: 'auto' | 'hardlink' | 'copy' | 'clone',
|
||||
hoistPattern?: string[],
|
||||
publicHoistPattern?: string[],
|
||||
useStoreServer?: boolean,
|
||||
useRunningStoreServer?: boolean,
|
||||
workspaceConcurrency: number,
|
||||
|
||||
@@ -60,6 +60,7 @@ export const types = Object.assign({
|
||||
'prefer-frozen-shrinkwrap': Boolean,
|
||||
'prefer-offline': Boolean,
|
||||
'production': [null, true],
|
||||
'public-hoist-pattern': Array,
|
||||
'publish-branch': String,
|
||||
'reporter': String,
|
||||
'save-peer': Boolean,
|
||||
@@ -146,10 +147,10 @@ export default async (
|
||||
'link-workspace-packages': true,
|
||||
'package-lock': npmDefaults['package-lock'],
|
||||
'pending': false,
|
||||
'public-hoist-pattern': ['@types/*'],
|
||||
'registry': npmDefaults.registry,
|
||||
'save-peer': false,
|
||||
'save-workspace-protocol': true,
|
||||
'shamefully-hoist': false,
|
||||
'shared-workspace-lockfile': true,
|
||||
'shared-workspace-shrinkwrap': true,
|
||||
'shrinkwrap': npmDefaults.shrinkwrap,
|
||||
@@ -311,6 +312,14 @@ export default async (
|
||||
if (pnpmConfig['hoist'] === false) {
|
||||
delete pnpmConfig.hoistPattern
|
||||
}
|
||||
switch (pnpmConfig.shamefullyHoist) {
|
||||
case false:
|
||||
delete pnpmConfig.publicHoistPattern
|
||||
break
|
||||
case true:
|
||||
pnpmConfig.publicHoistPattern = ['*']
|
||||
break
|
||||
}
|
||||
if (typeof pnpmConfig['color'] === 'boolean') {
|
||||
switch (pnpmConfig['color']) {
|
||||
case true:
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
import readProjectsContext from '@pnpm/read-projects-context'
|
||||
import {
|
||||
DEPENDENCIES_FIELDS,
|
||||
HoistedDependencies,
|
||||
ProjectManifest,
|
||||
ReadPackageHook,
|
||||
Registries,
|
||||
@@ -27,7 +28,7 @@ export interface PnpmContext<T> {
|
||||
existsCurrentLockfile: boolean,
|
||||
existsWantedLockfile: boolean,
|
||||
extraBinPaths: string[],
|
||||
hoistedAliases: {[depPath: string]: string[]}
|
||||
hoistedDependencies: HoistedDependencies,
|
||||
include: IncludedDependencies,
|
||||
modulesFile: Modules | null,
|
||||
pendingBuilds: string[],
|
||||
@@ -38,9 +39,9 @@ export interface PnpmContext<T> {
|
||||
rootModulesDir: string,
|
||||
hoistPattern: string[] | undefined,
|
||||
hoistedModulesDir: string,
|
||||
publicHoistPattern: string[] | undefined,
|
||||
lockfileDir: string,
|
||||
virtualStoreDir: string,
|
||||
shamefullyHoist: boolean,
|
||||
skipped: Set<string>,
|
||||
storeDir: string,
|
||||
wantedLockfile: Lockfile,
|
||||
@@ -75,8 +76,8 @@ export default async function getContext<T> (
|
||||
hoistPattern?: string[] | undefined,
|
||||
forceHoistPattern?: boolean,
|
||||
|
||||
shamefullyHoist?: boolean,
|
||||
forceShamefullyHoist?: boolean,
|
||||
publicHoistPattern?: string[] | undefined,
|
||||
forcePublicHoistPattern?: boolean,
|
||||
}
|
||||
): Promise<PnpmContext<T>> {
|
||||
const modulesDir = opts.modulesDir ?? 'node_modules'
|
||||
@@ -86,6 +87,7 @@ export default async function getContext<T> (
|
||||
if (importersContext.modules) {
|
||||
const { purged } = await validateModules(importersContext.modules, importersContext.projects, {
|
||||
currentHoistPattern: importersContext.currentHoistPattern,
|
||||
currentPublicHoistPattern: importersContext.currentPublicHoistPattern,
|
||||
forceNewModules: opts.forceNewModules === true,
|
||||
include: opts.include,
|
||||
lockfileDir: opts.lockfileDir,
|
||||
@@ -97,8 +99,8 @@ export default async function getContext<T> (
|
||||
forceHoistPattern: opts.forceHoistPattern,
|
||||
hoistPattern: opts.hoistPattern,
|
||||
|
||||
forceShamefullyHoist: opts.forceShamefullyHoist,
|
||||
shamefullyHoist: opts.shamefullyHoist,
|
||||
forcePublicHoistPattern: opts.forcePublicHoistPattern,
|
||||
publicHoistPattern: opts.publicHoistPattern,
|
||||
})
|
||||
if (purged) {
|
||||
importersContext = await readProjectsContext(projects, {
|
||||
@@ -126,28 +128,26 @@ export default async function getContext<T> (
|
||||
const extraBinPaths = [
|
||||
...opts.extraBinPaths || [],
|
||||
]
|
||||
const shamefullyHoist = Boolean(typeof importersContext.shamefullyHoist === 'undefined' ? opts.shamefullyHoist : importersContext.shamefullyHoist)
|
||||
if (opts.hoistPattern && !shamefullyHoist) {
|
||||
extraBinPaths.unshift(path.join(virtualStoreDir, 'node_modules/.bin'))
|
||||
const hoistedModulesDir = path.join(virtualStoreDir, 'node_modules')
|
||||
if (opts.hoistPattern?.length) {
|
||||
extraBinPaths.unshift(path.join(hoistedModulesDir, '.bin'))
|
||||
}
|
||||
const hoistedModulesDir = shamefullyHoist
|
||||
? importersContext.rootModulesDir : path.join(virtualStoreDir, 'node_modules')
|
||||
const ctx: PnpmContext<T> = {
|
||||
extraBinPaths,
|
||||
hoistedAliases: importersContext.hoistedAliases,
|
||||
hoistedDependencies: importersContext.hoistedDependencies,
|
||||
hoistedModulesDir,
|
||||
hoistPattern: opts.hoistPattern,
|
||||
hoistPattern: importersContext.currentHoistPattern ?? opts.hoistPattern,
|
||||
include: opts.include || importersContext.include,
|
||||
lockfileDir: opts.lockfileDir,
|
||||
modulesFile: importersContext.modules,
|
||||
pendingBuilds: importersContext.pendingBuilds,
|
||||
projects: importersContext.projects,
|
||||
publicHoistPattern: importersContext.currentPublicHoistPattern ?? opts.publicHoistPattern,
|
||||
registries: {
|
||||
...opts.registries,
|
||||
...importersContext.registries,
|
||||
},
|
||||
rootModulesDir: importersContext.rootModulesDir,
|
||||
shamefullyHoist,
|
||||
skipped: importersContext.skipped,
|
||||
storeDir: opts.storeDir,
|
||||
virtualStoreDir,
|
||||
@@ -174,6 +174,7 @@ async function validateModules (
|
||||
}>,
|
||||
opts: {
|
||||
currentHoistPattern?: string[],
|
||||
currentPublicHoistPattern?: string[],
|
||||
forceNewModules: boolean,
|
||||
include?: IncludedDependencies,
|
||||
lockfileDir: string,
|
||||
@@ -185,44 +186,30 @@ async function validateModules (
|
||||
hoistPattern?: string[] | undefined,
|
||||
forceHoistPattern?: boolean,
|
||||
|
||||
shamefullyHoist?: boolean | undefined,
|
||||
forceShamefullyHoist?: boolean,
|
||||
publicHoistPattern?: string[] | undefined,
|
||||
forcePublicHoistPattern?: boolean,
|
||||
}
|
||||
): Promise<{ purged: boolean }> {
|
||||
const rootProject = projects.find(({ id }) => id === '.')
|
||||
if (opts.forceShamefullyHoist && modules.shamefullyHoist !== opts.shamefullyHoist) {
|
||||
if (opts.forcePublicHoistPattern && !R.equals(modules.publicHoistPattern, opts.publicHoistPattern)) {
|
||||
if (opts.forceNewModules && rootProject) {
|
||||
await purgeModulesDirsOfImporter(rootProject)
|
||||
return { purged: true }
|
||||
}
|
||||
if (modules.shamefullyHoist) {
|
||||
throw new PnpmError(
|
||||
'SHAMEFULLY_HOIST_WANTED',
|
||||
'This modules directory was created using the --shamefully-hoist option.'
|
||||
+ ' You must add that option, or else run "pnpm install" to recreate the modules directory.'
|
||||
)
|
||||
}
|
||||
throw new PnpmError(
|
||||
'SHAMEFULLY_HOIST_NOT_WANTED',
|
||||
'This modules directory was created without the --shamefully-hoist option.'
|
||||
+ ' You must remove that option, or else "pnpm install" to recreate the modules directory.'
|
||||
'PUBLIC_HOIST_PATTERN_DIFF',
|
||||
'This modules directory was created using a different public-hoist-pattern value.'
|
||||
+ ' Run "pnpm install" to recreate the modules directory.'
|
||||
)
|
||||
}
|
||||
let purged = false
|
||||
if (opts.forceHoistPattern && rootProject) {
|
||||
try {
|
||||
if (!R.equals(opts.currentHoistPattern, (opts.hoistPattern || undefined))) {
|
||||
if (opts.currentHoistPattern) {
|
||||
throw new PnpmError(
|
||||
'HOISTING_WANTED',
|
||||
'This modules directory was created using the --hoist-pattern option.'
|
||||
+ ' You must add this option, or else add the --force option to recreate the modules directory.'
|
||||
)
|
||||
}
|
||||
throw new PnpmError(
|
||||
'HOISTING_NOT_WANTED',
|
||||
'This modules directory was created without the --hoist-pattern option.'
|
||||
+ ' You must remove that option, or else run "pnpm install" to recreate the modules directory.'
|
||||
'HOIST_PATTERN_DIFF',
|
||||
'This modules directory was created using a different hoist-pattern value.'
|
||||
+ ' Run "pnpm install" to recreate the modules directory.'
|
||||
)
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -297,7 +284,7 @@ export interface PnpmSingleContext {
|
||||
existsCurrentLockfile: boolean,
|
||||
existsWantedLockfile: boolean,
|
||||
extraBinPaths: string[],
|
||||
hoistedAliases: {[depPath: string]: string[]},
|
||||
hoistedDependencies: HoistedDependencies,
|
||||
hoistedModulesDir: string,
|
||||
hoistPattern: string[] | undefined,
|
||||
manifest: ProjectManifest,
|
||||
@@ -307,11 +294,11 @@ export interface PnpmSingleContext {
|
||||
include: IncludedDependencies,
|
||||
modulesFile: Modules | null,
|
||||
pendingBuilds: string[],
|
||||
publicHoistPattern: string[] | undefined,
|
||||
registries: Registries,
|
||||
rootModulesDir: string,
|
||||
lockfileDir: string,
|
||||
virtualStoreDir: string,
|
||||
shamefullyHoist: boolean,
|
||||
skipped: Set<string>,
|
||||
storeDir: string,
|
||||
wantedLockfile: Lockfile,
|
||||
@@ -339,20 +326,20 @@ export async function getContextForSingleImporter (
|
||||
hoistPattern?: string[] | undefined,
|
||||
forceHoistPattern?: boolean,
|
||||
|
||||
shamefullyHoist?: boolean,
|
||||
forceShamefullyHoist?: boolean,
|
||||
publicHoistPattern?: string[] | undefined,
|
||||
forcePublicHoistPattern?: boolean,
|
||||
},
|
||||
alreadyPurged: boolean = false
|
||||
): Promise<PnpmSingleContext> {
|
||||
const {
|
||||
currentHoistPattern,
|
||||
hoistedAliases,
|
||||
currentPublicHoistPattern,
|
||||
hoistedDependencies,
|
||||
projects,
|
||||
include,
|
||||
modules,
|
||||
pendingBuilds,
|
||||
registries,
|
||||
shamefullyHoist,
|
||||
skipped,
|
||||
rootModulesDir,
|
||||
} = await readProjectsContext(
|
||||
@@ -377,6 +364,7 @@ export async function getContextForSingleImporter (
|
||||
if (modules && !alreadyPurged) {
|
||||
const { purged } = await validateModules(modules, projects, {
|
||||
currentHoistPattern,
|
||||
currentPublicHoistPattern,
|
||||
forceNewModules: opts.forceNewModules === true,
|
||||
include: opts.include,
|
||||
lockfileDir: opts.lockfileDir,
|
||||
@@ -388,8 +376,8 @@ export async function getContextForSingleImporter (
|
||||
forceHoistPattern: opts.forceHoistPattern,
|
||||
hoistPattern: opts.hoistPattern,
|
||||
|
||||
forceShamefullyHoist: opts.forceShamefullyHoist,
|
||||
shamefullyHoist: opts.shamefullyHoist,
|
||||
forcePublicHoistPattern: opts.forcePublicHoistPattern,
|
||||
publicHoistPattern: opts.publicHoistPattern,
|
||||
})
|
||||
if (purged) {
|
||||
return getContextForSingleImporter(manifest, opts, true)
|
||||
@@ -400,17 +388,15 @@ export async function getContextForSingleImporter (
|
||||
const extraBinPaths = [
|
||||
...opts.extraBinPaths || [],
|
||||
]
|
||||
const sHoist = Boolean(typeof shamefullyHoist === 'undefined' ? opts.shamefullyHoist : shamefullyHoist)
|
||||
if (opts.hoistPattern && !sHoist) {
|
||||
extraBinPaths.unshift(path.join(virtualStoreDir, 'node_modules/.bin'))
|
||||
const hoistedModulesDir = path.join(virtualStoreDir, 'node_modules')
|
||||
if (opts.hoistPattern?.length) {
|
||||
extraBinPaths.unshift(path.join(hoistedModulesDir, '.bin'))
|
||||
}
|
||||
const hoistedModulesDir = sHoist
|
||||
? rootModulesDir : path.join(virtualStoreDir, 'node_modules')
|
||||
const ctx: PnpmSingleContext = {
|
||||
extraBinPaths,
|
||||
hoistedAliases,
|
||||
hoistedDependencies,
|
||||
hoistedModulesDir,
|
||||
hoistPattern: opts.hoistPattern,
|
||||
hoistPattern: currentHoistPattern ?? opts.hoistPattern,
|
||||
importerId,
|
||||
include: opts.include || include,
|
||||
lockfileDir: opts.lockfileDir,
|
||||
@@ -419,12 +405,12 @@ export async function getContextForSingleImporter (
|
||||
modulesFile: modules,
|
||||
pendingBuilds,
|
||||
prefix: opts.dir,
|
||||
publicHoistPattern: currentPublicHoistPattern ?? opts.publicHoistPattern,
|
||||
registries: {
|
||||
...opts.registries,
|
||||
...registries,
|
||||
},
|
||||
rootModulesDir,
|
||||
shamefullyHoist: sHoist,
|
||||
skipped,
|
||||
storeDir,
|
||||
virtualStoreDir,
|
||||
|
||||
@@ -83,7 +83,6 @@
|
||||
"@pnpm/link-bins": "workspace:5.3.4",
|
||||
"@pnpm/lockfile-file": "workspace:3.0.9",
|
||||
"@pnpm/lockfile-utils": "workspace:2.0.13",
|
||||
"@pnpm/matcher": "workspace:1.0.2",
|
||||
"@pnpm/modules-cleaner": "workspace:9.0.2",
|
||||
"@pnpm/modules-yaml": "workspace:7.0.0",
|
||||
"@pnpm/package-requester": "workspace:12.0.4",
|
||||
|
||||
@@ -37,7 +37,6 @@ import logger, {
|
||||
LogBase,
|
||||
streamParser,
|
||||
} from '@pnpm/logger'
|
||||
import matcher from '@pnpm/matcher'
|
||||
import { prune } from '@pnpm/modules-cleaner'
|
||||
import {
|
||||
IncludedDependencies,
|
||||
@@ -51,7 +50,7 @@ import {
|
||||
StoreController,
|
||||
} from '@pnpm/store-controller-types'
|
||||
import symlinkDependency, { symlinkDirectRootDependency } from '@pnpm/symlink-dependency'
|
||||
import { DependencyManifest, ProjectManifest, Registries } from '@pnpm/types'
|
||||
import { DependencyManifest, HoistedDependencies, ProjectManifest, Registries } from '@pnpm/types'
|
||||
import dp = require('dependency-path')
|
||||
import fs = require('mz/fs')
|
||||
import pLimit = require('p-limit')
|
||||
@@ -84,12 +83,12 @@ export interface HeadlessOptions {
|
||||
pruneDirectDependencies?: boolean,
|
||||
rootDir: string,
|
||||
}>,
|
||||
hoistedAliases: {[depPath: string]: string[]}
|
||||
hoistedDependencies: HoistedDependencies,
|
||||
hoistPattern?: string[],
|
||||
publicHoistPattern?: string[],
|
||||
lockfileDir: string,
|
||||
modulesDir?: string,
|
||||
virtualStoreDir?: string,
|
||||
shamefullyHoist: boolean,
|
||||
storeController: StoreController,
|
||||
sideEffectsCacheRead: boolean,
|
||||
sideEffectsCacheWrite: boolean,
|
||||
@@ -128,8 +127,8 @@ export default async (opts: HeadlessOptions) => {
|
||||
const rootModulesDir = await realpathMissing(path.join(lockfileDir, relativeModulesDir))
|
||||
const virtualStoreDir = pathAbsolute(opts.virtualStoreDir ?? path.join(relativeModulesDir, '.pnpm'), lockfileDir)
|
||||
const currentLockfile = opts.currentLockfile || await readCurrentLockfile(virtualStoreDir, { ignoreIncompatible: false })
|
||||
const hoistedModulesDir = opts.shamefullyHoist
|
||||
? rootModulesDir : path.join(virtualStoreDir, 'node_modules')
|
||||
const hoistedModulesDir = path.join(virtualStoreDir, 'node_modules')
|
||||
const publicHoistedModulesDir = rootModulesDir
|
||||
|
||||
for (const { id, manifest, rootDir } of opts.projects) {
|
||||
if (!satisfiesPackageManifest(wantedLockfile, manifest, id)) {
|
||||
@@ -162,11 +161,12 @@ export default async (opts: HeadlessOptions) => {
|
||||
{
|
||||
currentLockfile,
|
||||
dryRun: false,
|
||||
hoistedAliases: opts.hoistedAliases,
|
||||
hoistedDependencies: opts.hoistedDependencies,
|
||||
hoistedModulesDir: opts.hoistPattern && hoistedModulesDir || undefined,
|
||||
include: opts.include,
|
||||
lockfileDir,
|
||||
pruneStore: opts.pruneStore,
|
||||
publicHoistedModulesDir: opts.publicHoistPattern && publicHoistedModulesDir || undefined,
|
||||
registries: opts.registries,
|
||||
skipped,
|
||||
storeController: opts.storeController,
|
||||
@@ -240,18 +240,20 @@ export default async (opts: HeadlessOptions) => {
|
||||
})
|
||||
}
|
||||
|
||||
const rootImporterWithFlatModules = opts.hoistPattern && opts.projects.find(({ id }) => id === '.')
|
||||
let newHoistedAliases!: {[depPath: string]: string[]}
|
||||
const rootImporterWithFlatModules = (opts.hoistPattern || opts.publicHoistPattern) && opts.projects.find(({ id }) => id === '.')
|
||||
let newHoistedDependencies!: HoistedDependencies
|
||||
if (rootImporterWithFlatModules) {
|
||||
newHoistedAliases = await hoist(matcher(opts.hoistPattern!), {
|
||||
newHoistedDependencies = await hoist({
|
||||
lockfile: filteredLockfile,
|
||||
lockfileDir,
|
||||
modulesDir: hoistedModulesDir,
|
||||
registries: opts.registries,
|
||||
privateHoistedModulesDir: hoistedModulesDir,
|
||||
privateHoistPattern: opts.hoistPattern ?? [],
|
||||
publicHoistedModulesDir,
|
||||
publicHoistPattern: opts.publicHoistPattern ?? [],
|
||||
virtualStoreDir,
|
||||
})
|
||||
} else {
|
||||
newHoistedAliases = {}
|
||||
newHoistedDependencies = {}
|
||||
}
|
||||
|
||||
await Promise.all(opts.projects.map(async ({ rootDir, id, manifest, modulesDir }) => {
|
||||
@@ -302,7 +304,7 @@ export default async (opts: HeadlessOptions) => {
|
||||
})
|
||||
}
|
||||
const extraBinPaths = [...opts.extraBinPaths || []]
|
||||
if (opts.hoistPattern && !opts.shamefullyHoist) {
|
||||
if (opts.hoistPattern) {
|
||||
extraBinPaths.unshift(path.join(virtualStoreDir, 'node_modules/.bin'))
|
||||
}
|
||||
await buildModules(graph, Array.from(directNodes), {
|
||||
@@ -327,14 +329,14 @@ export default async (opts: HeadlessOptions) => {
|
||||
}
|
||||
await writeCurrentLockfile(virtualStoreDir, filteredLockfile)
|
||||
await writeModulesYaml(rootModulesDir, {
|
||||
hoistedAliases: newHoistedAliases,
|
||||
hoistedDependencies: newHoistedDependencies,
|
||||
hoistPattern: opts.hoistPattern,
|
||||
included: opts.include,
|
||||
layoutVersion: LAYOUT_VERSION,
|
||||
packageManager: `${opts.packageManager.name}@${opts.packageManager.version}`,
|
||||
pendingBuilds: opts.pendingBuilds,
|
||||
publicHoistPattern: opts.publicHoistPattern,
|
||||
registries: opts.registries,
|
||||
shamefullyHoist: opts.shamefullyHoist || false,
|
||||
skipped: Array.from(skipped),
|
||||
storeDir: opts.storeDir,
|
||||
virtualStoreDir,
|
||||
|
||||
@@ -532,17 +532,17 @@ test('installing with hoistPattern=*', async (t) => {
|
||||
|
||||
const modules = await project.readModulesManifest()
|
||||
|
||||
t.deepEqual(modules!.hoistedAliases['/balanced-match/1.0.0'], ['balanced-match'], 'hoisted field populated in .modules.yaml')
|
||||
t.deepEqual(modules!.hoistedDependencies['/balanced-match/1.0.0'], { 'balanced-match': 'private' }, 'hoisted field populated in .modules.yaml')
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('installing with hoistPattern=* and shamefullyHoist=true', async (t) => {
|
||||
test('installing with publicHoistPattern=*', async (t) => {
|
||||
const prefix = path.join(fixtures, 'simple-shamefully-flatten')
|
||||
await rimraf(path.join(prefix, 'node_modules'))
|
||||
const reporter = sinon.spy()
|
||||
|
||||
await headless(await testDefaults({ lockfileDir: prefix, reporter, hoistPattern: '*', shamefullyHoist: true }))
|
||||
await headless(await testDefaults({ lockfileDir: prefix, reporter, publicHoistPattern: '*' }))
|
||||
|
||||
const project = assertProject(t, prefix)
|
||||
t.ok(project.requireModule('is-positive'), 'prod dep installed')
|
||||
@@ -591,7 +591,7 @@ test('installing with hoistPattern=* and shamefullyHoist=true', async (t) => {
|
||||
|
||||
const modules = await project.readModulesManifest()
|
||||
|
||||
t.deepEqual(modules!.hoistedAliases['/balanced-match/1.0.0'], ['balanced-match'], 'hoisted field populated in .modules.yaml')
|
||||
t.deepEqual(modules!.hoistedDependencies['/balanced-match/1.0.0'], { 'balanced-match': 'public' }, 'hoisted field populated in .modules.yaml')
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
@@ -39,9 +39,6 @@
|
||||
{
|
||||
"path": "../lockfile-utils"
|
||||
},
|
||||
{
|
||||
"path": "../matcher"
|
||||
},
|
||||
{
|
||||
"path": "../modules-cleaner"
|
||||
},
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
"@pnpm/lockfile-types": "workspace:2.0.1",
|
||||
"@pnpm/lockfile-utils": "workspace:2.0.13",
|
||||
"@pnpm/lockfile-walker": "workspace:3.0.1",
|
||||
"@pnpm/matcher": "workspace:^1.0.2",
|
||||
"@pnpm/pkgid-to-filename": "3.0.0",
|
||||
"@pnpm/symlink-dependency": "workspace:3.0.6",
|
||||
"@pnpm/types": "workspace:6.0.0",
|
||||
|
||||
@@ -6,20 +6,22 @@ import {
|
||||
} from '@pnpm/lockfile-utils'
|
||||
import lockfileWalker, { LockfileWalkerStep } from '@pnpm/lockfile-walker'
|
||||
import logger from '@pnpm/logger'
|
||||
import matcher from '@pnpm/matcher'
|
||||
import pkgIdToFilename from '@pnpm/pkgid-to-filename'
|
||||
import symlinkDependency from '@pnpm/symlink-dependency'
|
||||
import { Registries } from '@pnpm/types'
|
||||
import { HoistedDependencies } from '@pnpm/types'
|
||||
import * as dp from 'dependency-path'
|
||||
import path = require('path')
|
||||
import R = require('ramda')
|
||||
|
||||
export default async function hoistByLockfile (
|
||||
match: (dependencyName: string) => boolean,
|
||||
opts: {
|
||||
lockfile: Lockfile,
|
||||
lockfileDir: string,
|
||||
modulesDir: string,
|
||||
registries: Registries,
|
||||
privateHoistPattern: string[],
|
||||
privateHoistedModulesDir: string,
|
||||
publicHoistPattern: string[],
|
||||
publicHoistedModulesDir: string,
|
||||
virtualStoreDir: string,
|
||||
}
|
||||
) {
|
||||
@@ -40,56 +42,72 @@ export default async function hoistByLockfile (
|
||||
}, {}),
|
||||
depPath: '',
|
||||
depth: -1,
|
||||
location: '',
|
||||
},
|
||||
...await getDependencies(
|
||||
step,
|
||||
0,
|
||||
{
|
||||
lockfileDir: opts.lockfileDir,
|
||||
registries: opts.registries,
|
||||
virtualStoreDir: opts.virtualStoreDir,
|
||||
}
|
||||
),
|
||||
...await getDependencies(step, 0),
|
||||
]
|
||||
|
||||
const aliasesByDependencyPath = await hoistGraph(deps, opts.lockfile.importers['.']?.specifiers ?? {}, {
|
||||
dryRun: false,
|
||||
match,
|
||||
modulesDir: opts.modulesDir,
|
||||
const getAliasHoistType = createGetAliasHoistType(opts.publicHoistPattern, opts.privateHoistPattern)
|
||||
|
||||
const hoistedDependencies = await hoistGraph(deps, opts.lockfile.importers['.']?.specifiers ?? {}, {
|
||||
getAliasHoistType,
|
||||
})
|
||||
|
||||
const bin = path.join(opts.modulesDir, '.bin')
|
||||
await symlinkHoistedDependencies(hoistedDependencies, {
|
||||
lockfile: opts.lockfile,
|
||||
lockfileDir: opts.lockfileDir,
|
||||
privateHoistedModulesDir: opts.privateHoistedModulesDir,
|
||||
publicHoistedModulesDir: opts.publicHoistedModulesDir,
|
||||
virtualStoreDir: opts.virtualStoreDir,
|
||||
})
|
||||
|
||||
// Here we only link the bins of the privately hoisted modules.
|
||||
// The bins of the publicly hoisted modules will be linked together with
|
||||
// the bins of the project's direct dependencies.
|
||||
// This is possible because the publicly hoisted modules
|
||||
// are in the same directory as the regular dependencies.
|
||||
await linkAllBins(opts.privateHoistedModulesDir)
|
||||
|
||||
return hoistedDependencies
|
||||
}
|
||||
|
||||
type GetAliasHoistType = (alias: string) => 'private' | 'public' | false
|
||||
|
||||
function createGetAliasHoistType (
|
||||
publicHoistPattern: string[],
|
||||
privateHoistPattern: string[]
|
||||
): GetAliasHoistType {
|
||||
const publicMatcher = matcher(publicHoistPattern)
|
||||
const privateMatcher = matcher(privateHoistPattern)
|
||||
return (alias: string) => {
|
||||
if (publicMatcher(alias)) return 'public'
|
||||
if (privateMatcher(alias)) return 'private'
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
async function linkAllBins (modulesDir: string) {
|
||||
const bin = path.join(modulesDir, '.bin')
|
||||
const warn: WarnFunction = (message, code) => {
|
||||
if (code === 'BINARIES_CONFLICT') return
|
||||
logger.warn({ message, prefix: path.join(opts.modulesDir, '../..') })
|
||||
logger.warn({ message, prefix: path.join(modulesDir, '../..') })
|
||||
}
|
||||
try {
|
||||
await linkBins(opts.modulesDir, bin, { allowExoticManifests: true, warn })
|
||||
await linkBins(modulesDir, bin, { allowExoticManifests: true, warn })
|
||||
} catch (err) {
|
||||
// Some packages generate their commands with lifecycle hooks.
|
||||
// At this stage, such commands are not generated yet.
|
||||
// For now, we don't hoist such generated commands.
|
||||
// Related issue: https://github.com/pnpm/pnpm/issues/2071
|
||||
}
|
||||
|
||||
return aliasesByDependencyPath
|
||||
}
|
||||
|
||||
async function getDependencies (
|
||||
step: LockfileWalkerStep,
|
||||
depth: number,
|
||||
opts: {
|
||||
registries: Registries,
|
||||
lockfileDir: string,
|
||||
virtualStoreDir: string,
|
||||
}
|
||||
depth: number
|
||||
): Promise<Dependency[]> {
|
||||
const deps: Dependency[] = []
|
||||
const nextSteps: LockfileWalkerStep[] = []
|
||||
for (const { pkgSnapshot, depPath, next } of step.dependencies) {
|
||||
const pkgName = nameVerFromPkgSnapshot(depPath, pkgSnapshot).name
|
||||
const modules = path.join(opts.virtualStoreDir, pkgIdToFilename(depPath, opts.lockfileDir), 'node_modules')
|
||||
const allDeps = {
|
||||
...pkgSnapshot.dependencies,
|
||||
...pkgSnapshot.optionalDependencies,
|
||||
@@ -101,7 +119,6 @@ async function getDependencies (
|
||||
}, {}),
|
||||
depPath,
|
||||
depth,
|
||||
location: path.join(modules, pkgName),
|
||||
})
|
||||
|
||||
nextSteps.push(next())
|
||||
@@ -115,13 +132,12 @@ async function getDependencies (
|
||||
|
||||
return (
|
||||
await Promise.all(
|
||||
nextSteps.map((nextStep) => getDependencies(nextStep, depth + 1, opts))
|
||||
nextSteps.map((nextStep) => getDependencies(nextStep, depth + 1))
|
||||
)
|
||||
).reduce((acc, deps) => [...acc, ...deps], deps)
|
||||
}
|
||||
|
||||
export interface Dependency {
|
||||
location: string,
|
||||
children: {[alias: string]: string},
|
||||
depPath: string,
|
||||
depth: number,
|
||||
@@ -131,50 +147,60 @@ async function hoistGraph (
|
||||
depNodes: Dependency[],
|
||||
currentSpecifiers: {[alias: string]: string},
|
||||
opts: {
|
||||
match: (dependencyName: string) => boolean,
|
||||
modulesDir: string,
|
||||
dryRun: boolean,
|
||||
getAliasHoistType: GetAliasHoistType,
|
||||
}
|
||||
): Promise<{[alias: string]: string[]}> {
|
||||
): Promise<HoistedDependencies> {
|
||||
const hoistedAliases = new Set(R.keys(currentSpecifiers))
|
||||
const aliasesByDependencyPath: {[depPath: string]: string[]} = {}
|
||||
const hoistedDependencies: HoistedDependencies = {}
|
||||
|
||||
await Promise.all(depNodes
|
||||
depNodes
|
||||
// sort by depth and then alphabetically
|
||||
.sort((a, b) => {
|
||||
const depthDiff = a.depth - b.depth
|
||||
return depthDiff === 0 ? a.depPath.localeCompare(b.depPath) : depthDiff
|
||||
})
|
||||
// build the alias map and the id map
|
||||
.map((depNode) => {
|
||||
.forEach((depNode) => {
|
||||
for (const childAlias of Object.keys(depNode.children)) {
|
||||
if (!opts.match(childAlias)) continue
|
||||
const hoist = opts.getAliasHoistType(childAlias)
|
||||
if (!hoist) continue
|
||||
// if this alias has already been taken, skip it
|
||||
if (hoistedAliases.has(childAlias)) {
|
||||
continue
|
||||
}
|
||||
hoistedAliases.add(childAlias)
|
||||
const childPath = depNode.children[childAlias]
|
||||
if (!aliasesByDependencyPath[childPath]) {
|
||||
aliasesByDependencyPath[childPath] = []
|
||||
if (!hoistedDependencies[childPath]) {
|
||||
hoistedDependencies[childPath] = {}
|
||||
}
|
||||
aliasesByDependencyPath[childPath].push(childAlias)
|
||||
hoistedDependencies[childPath][childAlias] = hoist
|
||||
}
|
||||
return depNode
|
||||
})
|
||||
.map(async (depNode) => {
|
||||
const pkgAliases = aliasesByDependencyPath[depNode.depPath]
|
||||
if (!pkgAliases) {
|
||||
return
|
||||
}
|
||||
// TODO when putting logs back in for hoisted packages, you've to put back the condition inside the map,
|
||||
// TODO look how it is done in linkPackages
|
||||
if (!opts.dryRun) {
|
||||
await Promise.all(pkgAliases.map(async (pkgAlias) => {
|
||||
await symlinkDependency(depNode.location, opts.modulesDir, pkgAlias)
|
||||
|
||||
return hoistedDependencies
|
||||
}
|
||||
|
||||
async function symlinkHoistedDependencies (
|
||||
hoistedDependencies: HoistedDependencies,
|
||||
opts: {
|
||||
lockfile: Lockfile,
|
||||
lockfileDir: string,
|
||||
privateHoistedModulesDir: string,
|
||||
publicHoistedModulesDir: string,
|
||||
virtualStoreDir: string,
|
||||
}
|
||||
) {
|
||||
await Promise.all(
|
||||
Object.entries(hoistedDependencies)
|
||||
.map(async ([depPath, pkgAliases]) => {
|
||||
const pkgName = nameVerFromPkgSnapshot(depPath, opts.lockfile.packages![depPath]).name
|
||||
const modules = path.join(opts.virtualStoreDir, pkgIdToFilename(depPath, opts.lockfileDir), 'node_modules')
|
||||
const depLocation = path.join(modules, pkgName)
|
||||
await Promise.all(Object.entries(pkgAliases).map(async ([pkgAlias, hoistType]) => {
|
||||
const targetDir = hoistType === 'public'
|
||||
? opts.publicHoistedModulesDir : opts.privateHoistedModulesDir
|
||||
await symlinkDependency(depLocation, targetDir, pkgAlias)
|
||||
}))
|
||||
}
|
||||
}))
|
||||
|
||||
return aliasesByDependencyPath
|
||||
))
|
||||
}
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
{
|
||||
"path": "../lockfile-walker"
|
||||
},
|
||||
{
|
||||
"path": "../matcher"
|
||||
},
|
||||
{
|
||||
"path": "../symlink-dependency"
|
||||
},
|
||||
|
||||
@@ -2,7 +2,10 @@ import escapeStringRegexp = require('escape-string-regexp')
|
||||
|
||||
export default function matcher (patterns: string[] | string) {
|
||||
if (typeof patterns === 'string') return matcherFromPattern(patterns)
|
||||
if (patterns.length === 0) return matcherFromPattern(patterns[0])
|
||||
switch (patterns.length) {
|
||||
case 0: return () => false
|
||||
case 1: return matcherFromPattern(patterns[0])
|
||||
}
|
||||
const matchArr = patterns.map(matcherFromPattern)
|
||||
return (input: string) => matchArr.some((match) => match(input))
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import { StoreController } from '@pnpm/store-controller-types'
|
||||
import {
|
||||
DependenciesField,
|
||||
DEPENDENCIES_FIELDS,
|
||||
HoistedDependencies,
|
||||
Registries,
|
||||
} from '@pnpm/types'
|
||||
import rimraf = require('@zkochan/rimraf')
|
||||
@@ -35,8 +36,9 @@ export default async function prune (
|
||||
opts: {
|
||||
dryRun?: boolean,
|
||||
include: { [dependenciesField in DependenciesField]: boolean },
|
||||
hoistedAliases: {[depPath: string]: string[]},
|
||||
hoistedDependencies: HoistedDependencies,
|
||||
hoistedModulesDir?: string,
|
||||
publicHoistedModulesDir?: string,
|
||||
wantedLockfile: Lockfile,
|
||||
currentLockfile: Lockfile,
|
||||
pruneStore?: boolean,
|
||||
@@ -114,13 +116,18 @@ export default async function prune (
|
||||
|
||||
if (!opts.dryRun) {
|
||||
if (orphanDepPaths.length) {
|
||||
if (opts.currentLockfile.packages && opts.hoistedModulesDir) {
|
||||
const modulesDir = opts.hoistedModulesDir
|
||||
if (
|
||||
opts.currentLockfile.packages &&
|
||||
opts.hoistedModulesDir &&
|
||||
opts.publicHoistedModulesDir
|
||||
) {
|
||||
const binsDir = path.join(opts.hoistedModulesDir, '.bin')
|
||||
const prefix = path.join(opts.virtualStoreDir, '../..')
|
||||
await Promise.all(orphanDepPaths.map(async (orphanDepPath) => {
|
||||
if (opts.hoistedAliases[orphanDepPath]) {
|
||||
await Promise.all(opts.hoistedAliases[orphanDepPath].map((alias) => {
|
||||
if (opts.hoistedDependencies[orphanDepPath]) {
|
||||
await Promise.all(Object.entries(opts.hoistedDependencies[orphanDepPath]).map(([alias, hoistType]) => {
|
||||
const modulesDir = hoistType === 'public'
|
||||
? opts.publicHoistedModulesDir! : opts.hoistedModulesDir!
|
||||
return removeDirectDependency({
|
||||
name: alias,
|
||||
}, {
|
||||
@@ -131,7 +138,7 @@ export default async function prune (
|
||||
})
|
||||
}))
|
||||
}
|
||||
delete opts.hoistedAliases[orphanDepPath]
|
||||
delete opts.hoistedDependencies[orphanDepPath]
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { DependenciesField, Registries } from '@pnpm/types'
|
||||
import { DependenciesField, HoistedDependencies, Registries } from '@pnpm/types'
|
||||
import isWindows = require('is-windows')
|
||||
import path = require('path')
|
||||
import readYamlFile from 'read-yaml-file'
|
||||
@@ -13,14 +13,16 @@ export type IncludedDependencies = {
|
||||
}
|
||||
|
||||
export interface Modules {
|
||||
hoistedAliases: {[depPath: string]: string[]}
|
||||
hoistPattern?: string[]
|
||||
hoistedAliases?: {[depPath: string]: string[]}, // for backward compatibility
|
||||
hoistedDependencies: HoistedDependencies,
|
||||
hoistPattern?: string[],
|
||||
included: IncludedDependencies,
|
||||
layoutVersion: number,
|
||||
packageManager: string,
|
||||
pendingBuilds: string[],
|
||||
registries?: Registries, // nullable for backward compatibility
|
||||
shamefullyHoist: boolean,
|
||||
shamefullyHoist?: boolean, // for backward compatibility
|
||||
publicHoistPattern?: string[]
|
||||
skipped: string[],
|
||||
storeDir: string,
|
||||
virtualStoreDir: string,
|
||||
@@ -28,23 +30,58 @@ export interface Modules {
|
||||
|
||||
export async function read (modulesDir: string): Promise<Modules | null> {
|
||||
const modulesYamlPath = path.join(modulesDir, MODULES_FILENAME)
|
||||
let modules!: Modules
|
||||
try {
|
||||
const modules = await readYamlFile<Modules>(modulesYamlPath)
|
||||
if (!modules.virtualStoreDir) {
|
||||
modules.virtualStoreDir = path.join(modulesDir, '.pnpm')
|
||||
} else if (!path.isAbsolute(modules.virtualStoreDir)) {
|
||||
modules.virtualStoreDir = path.join(modulesDir, modules.virtualStoreDir)
|
||||
}
|
||||
return modules
|
||||
modules = await readYamlFile<Modules>(modulesYamlPath)
|
||||
} catch (err) {
|
||||
if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {
|
||||
throw err
|
||||
}
|
||||
return null
|
||||
}
|
||||
if (!modules.virtualStoreDir) {
|
||||
modules.virtualStoreDir = path.join(modulesDir, '.pnpm')
|
||||
} else if (!path.isAbsolute(modules.virtualStoreDir)) {
|
||||
modules.virtualStoreDir = path.join(modulesDir, modules.virtualStoreDir)
|
||||
}
|
||||
switch (modules.shamefullyHoist) {
|
||||
case true:
|
||||
if (!modules.publicHoistPattern) {
|
||||
modules.publicHoistPattern = ['*']
|
||||
}
|
||||
if (modules.hoistedAliases && !modules.hoistedDependencies) {
|
||||
modules.hoistedDependencies = {}
|
||||
for (const depPath of Object.keys(modules.hoistedAliases)) {
|
||||
modules.hoistedDependencies[depPath] = {}
|
||||
for (const alias of modules.hoistedAliases[depPath]) {
|
||||
modules.hoistedDependencies[depPath][alias] = 'public'
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
case false:
|
||||
if (!modules.publicHoistPattern) {
|
||||
modules.publicHoistPattern = []
|
||||
}
|
||||
if (modules.hoistedAliases && !modules.hoistedDependencies) {
|
||||
modules.hoistedDependencies = {}
|
||||
for (const depPath of Object.keys(modules.hoistedAliases)) {
|
||||
modules.hoistedDependencies[depPath] = {}
|
||||
for (const alias of modules.hoistedAliases[depPath]) {
|
||||
modules.hoistedDependencies[depPath][alias] = 'private'
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
return modules
|
||||
}
|
||||
|
||||
const YAML_OPTS = { sortKeys: true }
|
||||
const YAML_OPTS = {
|
||||
noCompatMode: true,
|
||||
noRefs: true,
|
||||
sortKeys: true,
|
||||
}
|
||||
|
||||
export function write (
|
||||
modulesDir: string,
|
||||
@@ -57,6 +94,11 @@ export function write (
|
||||
if (!saveModules.hoistPattern) {
|
||||
// Because the YAML writer fails on undefined fields
|
||||
delete saveModules.hoistPattern
|
||||
}
|
||||
if (!saveModules.publicHoistPattern) {
|
||||
delete saveModules.publicHoistPattern
|
||||
}
|
||||
if (!saveModules.hoistedAliases || !saveModules.hoistPattern && !saveModules.publicHoistPattern) {
|
||||
delete saveModules.hoistedAliases
|
||||
}
|
||||
// We should store the absolute virtual store directory path on Windows
|
||||
|
||||
23
packages/modules-yaml/test/fixtures/old-no-shamefully-hoist/.modules.yaml
vendored
Normal file
23
packages/modules-yaml/test/fixtures/old-no-shamefully-hoist/.modules.yaml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
hoistPattern:
|
||||
- '*'
|
||||
hoistedAliases:
|
||||
/accepts/1.3.7:
|
||||
- accepts
|
||||
/array-flatten/1.1.1:
|
||||
- array-flatten
|
||||
/body-parser/1.19.0:
|
||||
- body-parser
|
||||
included:
|
||||
dependencies: true
|
||||
devDependencies: true
|
||||
optionalDependencies: true
|
||||
layoutVersion: 4
|
||||
packageManager: pnpm@5.1.8
|
||||
pendingBuilds: []
|
||||
registries:
|
||||
default: 'https://registry.npmjs.org/'
|
||||
shamefullyHoist: false
|
||||
skipped: []
|
||||
storeDir: /home/zoli/.pnpm-store/v3
|
||||
virtualStoreDir: .pnpm
|
||||
|
||||
23
packages/modules-yaml/test/fixtures/old-shamefully-hoist/.modules.yaml
vendored
Normal file
23
packages/modules-yaml/test/fixtures/old-shamefully-hoist/.modules.yaml
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
hoistPattern:
|
||||
- '*'
|
||||
hoistedAliases:
|
||||
/accepts/1.3.7:
|
||||
- accepts
|
||||
/array-flatten/1.1.1:
|
||||
- array-flatten
|
||||
/body-parser/1.19.0:
|
||||
- body-parser
|
||||
included:
|
||||
dependencies: true
|
||||
devDependencies: true
|
||||
optionalDependencies: true
|
||||
layoutVersion: 4
|
||||
packageManager: pnpm@5.1.8
|
||||
pendingBuilds: []
|
||||
registries:
|
||||
default: 'https://registry.npmjs.org/'
|
||||
shamefullyHoist: true
|
||||
skipped: []
|
||||
storeDir: /home/zoli/.pnpm-store/v3
|
||||
virtualStoreDir: .pnpm
|
||||
|
||||
@@ -9,7 +9,7 @@ import tempy = require('tempy')
|
||||
test('write() and read()', async (t) => {
|
||||
const modulesDir = tempy.directory()
|
||||
const modulesYaml = {
|
||||
hoistedAliases: {},
|
||||
hoistedDependencies: {},
|
||||
included: {
|
||||
dependencies: true,
|
||||
devDependencies: true,
|
||||
@@ -18,6 +18,7 @@ test('write() and read()', async (t) => {
|
||||
layoutVersion: 1,
|
||||
packageManager: 'pnpm@2',
|
||||
pendingBuilds: [],
|
||||
publicHoistPattern: [],
|
||||
registries: {
|
||||
default: 'https://registry.npmjs.org/',
|
||||
},
|
||||
@@ -27,7 +28,6 @@ test('write() and read()', async (t) => {
|
||||
virtualStoreDir: path.join(modulesDir, '.pnpm'),
|
||||
}
|
||||
await write(modulesDir, modulesYaml)
|
||||
delete modulesYaml.hoistedAliases
|
||||
t.deepEqual(await read(modulesDir), modulesYaml)
|
||||
|
||||
const raw = await readYamlFile(path.join(modulesDir, '.modules.yaml'))
|
||||
@@ -36,3 +36,25 @@ test('write() and read()', async (t) => {
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('backward compatible read of .modules.yaml created with shamefully-hoist=true', async (t) => {
|
||||
const modulesYaml = await read(path.join(__dirname, 'fixtures/old-shamefully-hoist'))
|
||||
t.deepEqual(modulesYaml.publicHoistPattern, ['*'])
|
||||
t.deepEqual(modulesYaml.hoistedDependencies, {
|
||||
'/accepts/1.3.7': { accepts: 'public' },
|
||||
'/array-flatten/1.1.1': { 'array-flatten': 'public' },
|
||||
'/body-parser/1.19.0': { 'body-parser': 'public' },
|
||||
})
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('backward compatible read of .modules.yaml created with shamefully-hoist=false', async (t) => {
|
||||
const modulesYaml = await read(path.join(__dirname, 'fixtures/old-no-shamefully-hoist'))
|
||||
t.deepEqual(modulesYaml.publicHoistPattern, [])
|
||||
t.deepEqual(modulesYaml.hoistedDependencies, {
|
||||
'/accepts/1.3.7': { accepts: 'private' },
|
||||
'/array-flatten/1.1.1': { 'array-flatten': 'private' },
|
||||
'/body-parser/1.19.0': { 'body-parser': 'private' },
|
||||
})
|
||||
t.end()
|
||||
})
|
||||
|
||||
@@ -33,6 +33,7 @@ export function rcOptionsTypes () {
|
||||
'pnpmfile',
|
||||
'prefer-offline',
|
||||
'production',
|
||||
'public-hoist-pattern',
|
||||
'registry',
|
||||
'reporter',
|
||||
'save-dev',
|
||||
|
||||
@@ -34,6 +34,7 @@ export function rcOptionsTypes () {
|
||||
'prefer-frozen-lockfile',
|
||||
'prefer-offline',
|
||||
'production',
|
||||
'public-hoist-pattern',
|
||||
'registry',
|
||||
'reporter',
|
||||
'shamefully-flatten',
|
||||
@@ -132,7 +133,7 @@ export function help () {
|
||||
name: '--no-hoist',
|
||||
},
|
||||
{
|
||||
description: 'The subdeps will be hoisted into the root node_modules. Your code will have access to them',
|
||||
description: 'All the subdeps will be hoisted into the root node_modules. Your code will have access to them',
|
||||
name: '--shamefully-hoist',
|
||||
},
|
||||
{
|
||||
@@ -142,6 +143,10 @@ export function help () {
|
||||
by any dependencies, so it is an emulation of a flat node_modules`,
|
||||
name: '--hoist-pattern <pattern>',
|
||||
},
|
||||
{
|
||||
description: `Hoist all dependencies matching the pattern to the root of the modules directory`,
|
||||
name: '--public-hoist-pattern <pattern>',
|
||||
},
|
||||
OPTIONS.storeDir,
|
||||
OPTIONS.virtualStoreDir,
|
||||
{
|
||||
|
||||
@@ -144,8 +144,10 @@ export default async function handler (
|
||||
storeDir: store.dir,
|
||||
workspacePackages,
|
||||
|
||||
forceHoistPattern: typeof opts.rawLocalConfig['hoist-pattern'] !== 'undefined' || typeof opts.rawLocalConfig['hoist'] !== 'undefined',
|
||||
forceShamefullyHoist: typeof opts.rawLocalConfig['shamefully-hoist'] !== 'undefined',
|
||||
forceHoistPattern: typeof opts.rawLocalConfig['hoist-pattern'] !== 'undefined'
|
||||
|| typeof opts.rawLocalConfig['hoist'] !== 'undefined',
|
||||
forcePublicHoistPattern: typeof opts.rawLocalConfig['shamefully-hoist'] !== 'undefined'
|
||||
|| typeof opts.rawLocalConfig['public-hoist-pattern'] !== 'undefined',
|
||||
}
|
||||
if (!opts.ignorePnpmfile) {
|
||||
installOpts['hooks'] = requireHooks(opts.lockfileDir || dir, opts)
|
||||
|
||||
@@ -172,14 +172,14 @@ export async function rebuild (
|
||||
|
||||
await writeModulesYaml(ctx.rootModulesDir, {
|
||||
...ctx.modulesFile,
|
||||
hoistedAliases: ctx.hoistedAliases,
|
||||
hoistedDependencies: ctx.hoistedDependencies,
|
||||
hoistPattern: ctx.hoistPattern,
|
||||
included: ctx.include,
|
||||
layoutVersion: LAYOUT_VERSION,
|
||||
packageManager: `${opts.packageManager.name}@${opts.packageManager.version}`,
|
||||
pendingBuilds: ctx.pendingBuilds,
|
||||
publicHoistPattern: ctx.publicHoistPattern,
|
||||
registries: ctx.registries,
|
||||
shamefullyHoist: ctx.shamefullyHoist,
|
||||
skipped: Array.from(ctx.skipped),
|
||||
storeDir: ctx.storeDir,
|
||||
virtualStoreDir: ctx.virtualStoreDir,
|
||||
|
||||
@@ -112,10 +112,10 @@ test('command does not fail when deprecated options are used', async (t) => {
|
||||
t.ok(stdout.toString().includes("Deprecated options: 'lock', 'independent-leaves'"))
|
||||
})
|
||||
|
||||
test('adding new dep does not fail if node_modules was created with --hoist-pattern=eslint-* and --shamefully-hoist', async (t: tape.Test) => {
|
||||
test('adding new dep does not fail if node_modules was created with --public-hoist-pattern=eslint-*', async (t: tape.Test) => {
|
||||
const project = prepare(t)
|
||||
|
||||
await execPnpm(['add', 'is-positive', '--hoist-pattern=eslint-*', '--shamefully-hoist'])
|
||||
await execPnpm(['add', 'is-positive', '--public-hoist-pattern=eslint-*'])
|
||||
|
||||
t.equal(execPnpmSync(['add', 'is-negative', '--no-hoist']).status, 1)
|
||||
t.equal(execPnpmSync(['add', 'is-negative', '--no-shamefully-hoist']).status, 1)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { getLockfileImporterId } from '@pnpm/lockfile-file'
|
||||
import { Modules, read as readModulesYaml } from '@pnpm/modules-yaml'
|
||||
import normalizeRegistries from '@pnpm/normalize-registries'
|
||||
import { DependenciesField, Registries } from '@pnpm/types'
|
||||
import { DependenciesField, HoistedDependencies, Registries } from '@pnpm/types'
|
||||
import path = require('path')
|
||||
import realpathMissing = require('realpath-missing')
|
||||
|
||||
@@ -19,8 +19,9 @@ export default async function <T>(
|
||||
}
|
||||
): Promise<{
|
||||
currentHoistPattern?: string[],
|
||||
currentPublicHoistPattern?: string[],
|
||||
hoist?: boolean,
|
||||
hoistedAliases: { [depPath: string]: string[] },
|
||||
hoistedDependencies: HoistedDependencies,
|
||||
projects: Array<{
|
||||
id: string,
|
||||
} & T & Required<ProjectOptions>>,
|
||||
@@ -29,16 +30,16 @@ export default async function <T>(
|
||||
pendingBuilds: string[],
|
||||
registries: Registries | null | undefined,
|
||||
rootModulesDir: string,
|
||||
shamefullyHoist?: boolean,
|
||||
skipped: Set<string>,
|
||||
}> {
|
||||
const relativeModulesDir = opts.modulesDir ?? 'node_modules'
|
||||
const rootModulesDir = await realpathMissing(path.join(opts.lockfileDir, relativeModulesDir))
|
||||
const modules = await readModulesYaml(rootModulesDir)
|
||||
return {
|
||||
currentHoistPattern: modules?.hoistPattern || undefined,
|
||||
currentHoistPattern: modules?.hoistPattern,
|
||||
currentPublicHoistPattern: modules?.publicHoistPattern,
|
||||
hoist: !modules ? undefined : Boolean(modules.hoistPattern),
|
||||
hoistedAliases: modules?.hoistedAliases || {},
|
||||
hoistedDependencies: modules?.hoistedDependencies ?? {},
|
||||
include: modules?.included || { dependencies: true, devDependencies: true, optionalDependencies: true },
|
||||
modules,
|
||||
pendingBuilds: modules?.pendingBuilds || [],
|
||||
@@ -56,7 +57,6 @@ export default async function <T>(
|
||||
})),
|
||||
registries: modules?.registries && normalizeRegistries(modules.registries),
|
||||
rootModulesDir,
|
||||
shamefullyHoist: modules?.shamefullyHoist || undefined,
|
||||
skipped: new Set(modules?.skipped || []),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
"@pnpm/lockfile-utils": "workspace:2.0.13",
|
||||
"@pnpm/lockfile-walker": "workspace:3.0.1",
|
||||
"@pnpm/manifest-utils": "workspace:1.0.1",
|
||||
"@pnpm/matcher": "workspace:1.0.2",
|
||||
"@pnpm/modules-cleaner": "workspace:9.0.2",
|
||||
"@pnpm/modules-yaml": "workspace:7.0.0",
|
||||
"@pnpm/normalize-registries": "workspace:1.0.1",
|
||||
|
||||
@@ -193,7 +193,7 @@ export async function mutateModules (
|
||||
engineStrict: opts.engineStrict,
|
||||
extraBinPaths: opts.extraBinPaths,
|
||||
force: opts.force,
|
||||
hoistedAliases: ctx.hoistedAliases,
|
||||
hoistedDependencies: ctx.hoistedDependencies,
|
||||
hoistPattern: ctx.hoistPattern,
|
||||
ignoreScripts: opts.ignoreScripts,
|
||||
include: opts.include,
|
||||
@@ -212,9 +212,9 @@ export async function mutateModules (
|
||||
pruneDirectDependencies?: boolean,
|
||||
}>,
|
||||
pruneStore: opts.pruneStore,
|
||||
publicHoistPattern: ctx.publicHoistPattern,
|
||||
rawConfig: opts.rawConfig,
|
||||
registries: opts.registries,
|
||||
shamefullyHoist: ctx.shamefullyHoist,
|
||||
sideEffectsCacheRead: opts.sideEffectsCacheRead,
|
||||
sideEffectsCacheWrite: opts.sideEffectsCacheWrite,
|
||||
skipped: ctx.skipped,
|
||||
@@ -693,7 +693,7 @@ async function installInContext (
|
||||
currentLockfile: ctx.currentLockfile,
|
||||
dryRun: opts.lockfileOnly,
|
||||
force: opts.force,
|
||||
hoistedAliases: ctx.hoistedAliases,
|
||||
hoistedDependencies: ctx.hoistedDependencies,
|
||||
hoistedModulesDir: ctx.hoistedModulesDir,
|
||||
hoistPattern: ctx.hoistPattern,
|
||||
include: opts.include,
|
||||
@@ -701,7 +701,9 @@ async function installInContext (
|
||||
makePartialCurrentLockfile: opts.makePartialCurrentLockfile,
|
||||
outdatedDependencies,
|
||||
pruneStore: opts.pruneStore,
|
||||
publicHoistPattern: ctx.publicHoistPattern,
|
||||
registries: ctx.registries,
|
||||
rootModulesDir: ctx.rootModulesDir,
|
||||
sideEffectsCacheRead: opts.sideEffectsCacheRead,
|
||||
skipped: ctx.skipped,
|
||||
storeController: opts.storeController,
|
||||
@@ -799,14 +801,14 @@ async function installInContext (
|
||||
}
|
||||
return writeModulesYaml(ctx.rootModulesDir, {
|
||||
...ctx.modulesFile,
|
||||
hoistedAliases: result.newHoistedAliases,
|
||||
hoistedDependencies: result.newHoistedDependencies,
|
||||
hoistPattern: ctx.hoistPattern,
|
||||
included: ctx.include,
|
||||
layoutVersion: LAYOUT_VERSION,
|
||||
packageManager: `${opts.packageManager.name}@${opts.packageManager.version}`,
|
||||
pendingBuilds: ctx.pendingBuilds,
|
||||
publicHoistPattern: ctx.publicHoistPattern,
|
||||
registries: ctx.registries,
|
||||
shamefullyHoist: ctx.shamefullyHoist,
|
||||
skipped: Array.from(ctx.skipped),
|
||||
storeDir: ctx.storeDir,
|
||||
virtualStoreDir: ctx.virtualStoreDir,
|
||||
|
||||
@@ -14,13 +14,16 @@ import {
|
||||
import hoist from '@pnpm/hoist'
|
||||
import { Lockfile } from '@pnpm/lockfile-file'
|
||||
import logger from '@pnpm/logger'
|
||||
import matcher from '@pnpm/matcher'
|
||||
import { prune } from '@pnpm/modules-cleaner'
|
||||
import { IncludedDependencies } from '@pnpm/modules-yaml'
|
||||
import { DependenciesTree, LinkedDependency } from '@pnpm/resolve-dependencies'
|
||||
import { StoreController } from '@pnpm/store-controller-types'
|
||||
import symlinkDependency, { symlinkDirectRootDependency } from '@pnpm/symlink-dependency'
|
||||
import { ProjectManifest, Registries } from '@pnpm/types'
|
||||
import {
|
||||
HoistedDependencies,
|
||||
ProjectManifest,
|
||||
Registries,
|
||||
} from '@pnpm/types'
|
||||
import fs = require('mz/fs')
|
||||
import pLimit = require('p-limit')
|
||||
import path = require('path')
|
||||
@@ -60,15 +63,17 @@ export default async function linkPackages (
|
||||
currentLockfile: Lockfile,
|
||||
dryRun: boolean,
|
||||
force: boolean,
|
||||
hoistedAliases: {[depPath: string]: string[]},
|
||||
hoistedDependencies: HoistedDependencies,
|
||||
hoistedModulesDir: string,
|
||||
hoistPattern?: string[],
|
||||
publicHoistPattern?: string[],
|
||||
include: IncludedDependencies,
|
||||
lockfileDir: string,
|
||||
makePartialCurrentLockfile: boolean,
|
||||
outdatedDependencies: {[pkgId: string]: string},
|
||||
pruneStore: boolean,
|
||||
registries: Registries,
|
||||
rootModulesDir: string,
|
||||
sideEffectsCacheRead: boolean,
|
||||
skipped: Set<string>,
|
||||
storeController: StoreController,
|
||||
@@ -83,7 +88,7 @@ export default async function linkPackages (
|
||||
currentLockfile: Lockfile,
|
||||
depGraph: DependenciesGraph,
|
||||
newDepPaths: string[],
|
||||
newHoistedAliases: {[depPath: string]: string[]},
|
||||
newHoistedDependencies: HoistedDependencies,
|
||||
removedDepPaths: Set<string>,
|
||||
wantedLockfile: Lockfile,
|
||||
}> {
|
||||
@@ -148,11 +153,12 @@ export default async function linkPackages (
|
||||
const removedDepPaths = await prune(projects, {
|
||||
currentLockfile: opts.currentLockfile,
|
||||
dryRun: opts.dryRun,
|
||||
hoistedAliases: opts.hoistedAliases,
|
||||
hoistedDependencies: opts.hoistedDependencies,
|
||||
hoistedModulesDir: opts.hoistPattern && opts.hoistedModulesDir || undefined,
|
||||
include: opts.include,
|
||||
lockfileDir: opts.lockfileDir,
|
||||
pruneStore: opts.pruneStore,
|
||||
publicHoistedModulesDir: opts.publicHoistPattern && opts.rootModulesDir || undefined,
|
||||
registries: opts.registries,
|
||||
skipped: opts.skipped,
|
||||
storeController: opts.storeController,
|
||||
@@ -303,15 +309,19 @@ export default async function linkPackages (
|
||||
currentLockfile = newCurrentLockfile
|
||||
}
|
||||
|
||||
let newHoistedAliases: Record<string, string[]> = {}
|
||||
if (opts.hoistPattern && (newDepPaths.length > 0 || removedDepPaths.size > 0)) {
|
||||
newHoistedAliases = await hoist(matcher(opts.hoistPattern!), {
|
||||
let newHoistedDependencies!: HoistedDependencies
|
||||
if ((opts.hoistPattern || opts.publicHoistPattern) && (newDepPaths.length > 0 || removedDepPaths.size > 0)) {
|
||||
newHoistedDependencies = await hoist({
|
||||
lockfile: currentLockfile,
|
||||
lockfileDir: opts.lockfileDir,
|
||||
modulesDir: opts.hoistedModulesDir,
|
||||
registries: opts.registries,
|
||||
privateHoistedModulesDir: opts.hoistedModulesDir,
|
||||
privateHoistPattern: opts.hoistPattern ?? [],
|
||||
publicHoistedModulesDir: opts.rootModulesDir,
|
||||
publicHoistPattern: opts.publicHoistPattern ?? [],
|
||||
virtualStoreDir: opts.virtualStoreDir,
|
||||
})
|
||||
} else {
|
||||
newHoistedDependencies = {}
|
||||
}
|
||||
|
||||
if (!opts.dryRun) {
|
||||
@@ -333,7 +343,7 @@ export default async function linkPackages (
|
||||
currentLockfile,
|
||||
depGraph,
|
||||
newDepPaths,
|
||||
newHoistedAliases,
|
||||
newHoistedDependencies,
|
||||
removedDepPaths,
|
||||
wantedLockfile: newWantedLockfile,
|
||||
}
|
||||
|
||||
@@ -110,10 +110,11 @@ export default async function link (
|
||||
],
|
||||
{
|
||||
currentLockfile,
|
||||
hoistedAliases: ctx.hoistedAliases,
|
||||
hoistedDependencies: ctx.hoistedDependencies,
|
||||
hoistedModulesDir: opts.hoistPattern && ctx.hoistedModulesDir || undefined,
|
||||
include: ctx.include,
|
||||
lockfileDir: opts.lockfileDir,
|
||||
publicHoistedModulesDir: opts.publicHoistPattern && ctx.rootModulesDir || undefined,
|
||||
registries: ctx.registries,
|
||||
skipped: ctx.skipped,
|
||||
storeController: opts.storeController,
|
||||
|
||||
@@ -26,8 +26,8 @@ interface StrictLinkOptions {
|
||||
hoistPattern: string[] | undefined,
|
||||
forceHoistPattern: boolean,
|
||||
|
||||
shamefullyHoist: boolean,
|
||||
forceShamefullyHoist: boolean,
|
||||
publicHoistPattern: string[] | undefined,
|
||||
forcePublicHoistPattern: boolean,
|
||||
}
|
||||
|
||||
export type LinkOptions = Partial<StrictLinkOptions> &
|
||||
@@ -57,7 +57,6 @@ async function defaults (opts: LinkOptions) {
|
||||
hoistPattern: undefined,
|
||||
lockfileDir: opts.lockfileDir || dir,
|
||||
registries: DEFAULT_REGISTRIES,
|
||||
shamefullyHoist: false,
|
||||
storeController: opts.storeController,
|
||||
storeDir: opts.storeDir,
|
||||
useLockfile: true,
|
||||
|
||||
@@ -32,12 +32,12 @@ test('should hoist dependencies', async (t) => {
|
||||
await project.isExecutable('.pnpm/node_modules/.bin/mime')
|
||||
})
|
||||
|
||||
test('should shamefully hoist dependencies', async (t) => {
|
||||
test('should hoist dependencies to the root of node_modules when publicHoistPattern is used', async (t) => {
|
||||
const project = prepareEmpty(t)
|
||||
|
||||
await addDependenciesToPackage({},
|
||||
['express', '@foo/has-dep-from-same-scope'],
|
||||
await testDefaults({ fastUnpack: false, hoistPattern: '*', shamefullyHoist: true }))
|
||||
await testDefaults({ fastUnpack: false, publicHoistPattern: '*' }))
|
||||
|
||||
await project.has('express')
|
||||
await project.has('debug')
|
||||
@@ -50,6 +50,24 @@ test('should shamefully hoist dependencies', async (t) => {
|
||||
await project.isExecutable('.bin/mime')
|
||||
})
|
||||
|
||||
test('should hoist some dependencies to the root of node_modules when publicHoistPattern is used and others to the virtual store directory', async (t) => {
|
||||
const project = prepareEmpty(t)
|
||||
|
||||
await addDependenciesToPackage({},
|
||||
['express', '@foo/has-dep-from-same-scope'],
|
||||
await testDefaults({ fastUnpack: false, hoistPattern: '*', publicHoistPattern: '@foo/*' }))
|
||||
|
||||
await project.has('express')
|
||||
await project.has('.pnpm/node_modules/debug')
|
||||
await project.has('.pnpm/node_modules/cookie')
|
||||
await project.has('.pnpm/node_modules/mime')
|
||||
await project.has('@foo/has-dep-from-same-scope')
|
||||
await project.has('@foo/no-deps')
|
||||
|
||||
// should also hoist bins
|
||||
await project.isExecutable('.pnpm/node_modules/.bin/mime')
|
||||
})
|
||||
|
||||
test('should hoist dependencies by pattern', async (t) => {
|
||||
const project = prepareEmpty(t)
|
||||
|
||||
@@ -113,7 +131,7 @@ test('should rehoist when uninstalling a package', async (t: tape.Test) => {
|
||||
|
||||
const modules = await project.readModulesManifest()
|
||||
t.ok(modules)
|
||||
t.deepEqual(modules!.hoistedAliases[`/debug/2.6.9`], ['debug'], 'new hoisted debug added to .modules.yaml')
|
||||
t.deepEqual(modules!.hoistedDependencies[`/debug/2.6.9`], { debug: 'private' }, 'new hoisted debug added to .modules.yaml')
|
||||
})
|
||||
|
||||
test('should rehoist after running a general install', async (t) => {
|
||||
@@ -167,8 +185,7 @@ test('hoistPattern=* throws exception when executed on node_modules installed w/
|
||||
}))
|
||||
t.fail('installation should have failed')
|
||||
} catch (err) {
|
||||
t.equal(err['code'], 'ERR_PNPM_HOISTING_NOT_WANTED') // tslint:disable-line:no-string-literal
|
||||
t.ok(err.message.indexOf('This modules directory was created without the --hoist-pattern option.') === 0)
|
||||
t.equal(err['code'], 'ERR_PNPM_HOIST_PATTERN_DIFF') // tslint:disable-line:no-string-literal
|
||||
}
|
||||
})
|
||||
|
||||
@@ -185,8 +202,7 @@ test('hoistPattern=undefined throws exception when executed on node_modules inst
|
||||
})
|
||||
t.fail('installation should have failed')
|
||||
} catch (err) {
|
||||
t.equal(err['code'], 'ERR_PNPM_HOISTING_WANTED') // tslint:disable-line:no-string-literal
|
||||
t.ok(err.message.indexOf('This modules directory was created using the --hoist-pattern option.') === 0)
|
||||
t.equal(err['code'], 'ERR_PNPM_HOIST_PATTERN_DIFF') // tslint:disable-line:no-string-literal
|
||||
}
|
||||
|
||||
// Instatll doesn't fail if the value of hoistPattern isn't forced
|
||||
@@ -210,7 +226,7 @@ test('hoist by alias', async (t: tape.Test) => {
|
||||
|
||||
const modules = await project.readModulesManifest()
|
||||
t.ok(modules)
|
||||
t.deepEqual(modules!.hoistedAliases, { [`/dep-of-pkg-with-1-dep/100.1.0`]: [ 'dep' ] }, '.modules.yaml updated correctly')
|
||||
t.deepEqual(modules!.hoistedDependencies, { [`/dep-of-pkg-with-1-dep/100.1.0`]: { dep: 'private' } }, '.modules.yaml updated correctly')
|
||||
})
|
||||
|
||||
test('should remove aliased hoisted dependencies', async (t) => {
|
||||
@@ -238,7 +254,7 @@ test('should remove aliased hoisted dependencies', async (t) => {
|
||||
|
||||
const modules = await project.readModulesManifest()
|
||||
t.ok(modules)
|
||||
t.deepEqual(modules!.hoistedAliases, {}, '.modules.yaml updated correctly')
|
||||
t.deepEqual(modules!.hoistedDependencies, {}, '.modules.yaml updated correctly')
|
||||
})
|
||||
|
||||
test('should update .modules.yaml when pruning if we are flattening', async (t) => {
|
||||
@@ -254,7 +270,7 @@ test('should update .modules.yaml when pruning if we are flattening', async (t)
|
||||
|
||||
const modules = await project.readModulesManifest()
|
||||
t.ok(modules)
|
||||
t.deepEqual(modules!.hoistedAliases, {}, '.modules.yaml updated correctly')
|
||||
t.deepEqual(modules!.hoistedDependencies, {}, '.modules.yaml updated correctly')
|
||||
})
|
||||
|
||||
test('should rehoist after pruning', async (t) => {
|
||||
@@ -432,9 +448,9 @@ test('hoist when updating in one of the workspace projects', async (t) => {
|
||||
const rootModules = assertProject(t, process.cwd())
|
||||
{
|
||||
const modulesManifest = await rootModules.readModulesManifest()
|
||||
t.deepEqual(modulesManifest?.hoistedAliases, {
|
||||
[`/dep-of-pkg-with-1-dep/100.0.0`]: ['dep-of-pkg-with-1-dep'],
|
||||
[`/foo/100.0.0`]: ['foo'],
|
||||
t.deepEqual(modulesManifest?.hoistedDependencies, {
|
||||
[`/dep-of-pkg-with-1-dep/100.0.0`]: { 'dep-of-pkg-with-1-dep': 'private' },
|
||||
[`/foo/100.0.0`]: { 'foo': 'private' },
|
||||
})
|
||||
}
|
||||
|
||||
@@ -460,8 +476,8 @@ test('hoist when updating in one of the workspace projects', async (t) => {
|
||||
|
||||
{
|
||||
const modulesManifest = await rootModules.readModulesManifest()
|
||||
t.deepEqual(modulesManifest?.hoistedAliases, {
|
||||
[`/dep-of-pkg-with-1-dep/100.0.0`]: ['dep-of-pkg-with-1-dep'],
|
||||
t.deepEqual(modulesManifest?.hoistedDependencies, {
|
||||
[`/dep-of-pkg-with-1-dep/100.0.0`]: { 'dep-of-pkg-with-1-dep': 'private' },
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -474,7 +490,7 @@ test('should recreate node_modules with hoisting', async (t: tape.Test) => {
|
||||
{
|
||||
const modulesManifest = await project.readModulesManifest()
|
||||
t.notOk(modulesManifest.hoistPattern)
|
||||
t.notOk(modulesManifest.hoistedAliases)
|
||||
t.deepEqual(modulesManifest.hoistedDependencies, {})
|
||||
}
|
||||
|
||||
await mutateModules([
|
||||
@@ -491,6 +507,6 @@ test('should recreate node_modules with hoisting', async (t: tape.Test) => {
|
||||
{
|
||||
const modulesManifest = await project.readModulesManifest()
|
||||
t.ok(modulesManifest.hoistPattern)
|
||||
t.ok(modulesManifest.hoistedAliases)
|
||||
t.ok(Object.keys(modulesManifest.hoistedDependencies).length > 0)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -51,9 +51,6 @@
|
||||
{
|
||||
"path": "../manifest-utils"
|
||||
},
|
||||
{
|
||||
"path": "../matcher"
|
||||
},
|
||||
{
|
||||
"path": "../modules-cleaner"
|
||||
},
|
||||
|
||||
@@ -11,3 +11,5 @@ export interface Registries {
|
||||
default: string,
|
||||
[scope: string]: string,
|
||||
}
|
||||
|
||||
export type HoistedDependencies = Record<string, Record<string, 'public' | 'private'>>
|
||||
|
||||
6
pnpm-lock.yaml
generated
6
pnpm-lock.yaml
generated
@@ -612,7 +612,6 @@ importers:
|
||||
'@pnpm/link-bins': 'link:../link-bins'
|
||||
'@pnpm/lockfile-file': 'link:../lockfile-file'
|
||||
'@pnpm/lockfile-utils': 'link:../lockfile-utils'
|
||||
'@pnpm/matcher': 'link:../matcher'
|
||||
'@pnpm/modules-cleaner': 'link:../modules-cleaner'
|
||||
'@pnpm/modules-yaml': 'link:../modules-yaml'
|
||||
'@pnpm/package-requester': 'link:../package-requester'
|
||||
@@ -670,7 +669,6 @@ importers:
|
||||
'@pnpm/lockfile-file': 'workspace:3.0.9'
|
||||
'@pnpm/lockfile-utils': 'workspace:2.0.13'
|
||||
'@pnpm/logger': 3.2.2
|
||||
'@pnpm/matcher': 'workspace:1.0.2'
|
||||
'@pnpm/modules-cleaner': 'workspace:9.0.2'
|
||||
'@pnpm/modules-yaml': 'workspace:7.0.0'
|
||||
'@pnpm/package-requester': 'workspace:12.0.4'
|
||||
@@ -713,6 +711,7 @@ importers:
|
||||
'@pnpm/lockfile-types': 'link:../lockfile-types'
|
||||
'@pnpm/lockfile-utils': 'link:../lockfile-utils'
|
||||
'@pnpm/lockfile-walker': 'link:../lockfile-walker'
|
||||
'@pnpm/matcher': 'link:../matcher'
|
||||
'@pnpm/pkgid-to-filename': 3.0.0
|
||||
'@pnpm/symlink-dependency': 'link:../symlink-dependency'
|
||||
'@pnpm/types': 'link:../types'
|
||||
@@ -728,6 +727,7 @@ importers:
|
||||
'@pnpm/lockfile-utils': 'workspace:2.0.13'
|
||||
'@pnpm/lockfile-walker': 'workspace:3.0.1'
|
||||
'@pnpm/logger': 3.2.2
|
||||
'@pnpm/matcher': 'workspace:^1.0.2'
|
||||
'@pnpm/pkgid-to-filename': 3.0.0
|
||||
'@pnpm/symlink-dependency': 'workspace:3.0.6'
|
||||
'@pnpm/types': 'workspace:6.0.0'
|
||||
@@ -2576,7 +2576,6 @@ importers:
|
||||
'@pnpm/lockfile-utils': 'link:../lockfile-utils'
|
||||
'@pnpm/lockfile-walker': 'link:../lockfile-walker'
|
||||
'@pnpm/manifest-utils': 'link:../manifest-utils'
|
||||
'@pnpm/matcher': 'link:../matcher'
|
||||
'@pnpm/modules-cleaner': 'link:../modules-cleaner'
|
||||
'@pnpm/modules-yaml': 'link:../modules-yaml'
|
||||
'@pnpm/normalize-registries': 'link:../normalize-registries'
|
||||
@@ -2678,7 +2677,6 @@ importers:
|
||||
'@pnpm/lockfile-walker': 'workspace:3.0.1'
|
||||
'@pnpm/logger': 3.2.2
|
||||
'@pnpm/manifest-utils': 'workspace:1.0.1'
|
||||
'@pnpm/matcher': 'workspace:1.0.2'
|
||||
'@pnpm/modules-cleaner': 'workspace:9.0.2'
|
||||
'@pnpm/modules-yaml': 'workspace:7.0.0'
|
||||
'@pnpm/normalize-registries': 'workspace:1.0.1'
|
||||
|
||||
Reference in New Issue
Block a user