mirror of
https://github.com/pnpm/pnpm.git
synced 2025-12-23 23:29:17 -05:00
feat!: breaking config changes for v7 (#4253)
ref https://github.com/pnpm/pnpm/discussions/3536
This commit is contained in:
10
.changeset/big-carpets-fry.md
Normal file
10
.changeset/big-carpets-fry.md
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
"@pnpm/build-modules": major
|
||||
"@pnpm/config": major
|
||||
"@pnpm/core": major
|
||||
"@pnpm/headless": major
|
||||
"@pnpm/hoist": major
|
||||
"@pnpm/link-bins": major
|
||||
---
|
||||
|
||||
`extendNodePath` removed.
|
||||
5
.changeset/blue-lamps-poke.md
Normal file
5
.changeset/blue-lamps-poke.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"pnpm": major
|
||||
---
|
||||
|
||||
The root package is excluded by default, when running `pnpm -r exec|run|add` [#2769](https://github.com/pnpm/pnpm/issues/2769).
|
||||
9
.changeset/bright-baboons-repair.md
Normal file
9
.changeset/bright-baboons-repair.md
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
"pnpm": major
|
||||
---
|
||||
|
||||
Filtering by path is done by globs.
|
||||
|
||||
In pnpm v6, in order to pick packages under a certain directory, the following filter was used: `--filter=./apps`
|
||||
|
||||
In pnpm v7, a glob should be used: `--filter=./apps/**`
|
||||
9
.changeset/five-dingos-whisper.md
Normal file
9
.changeset/five-dingos-whisper.md
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
"pnpm": major
|
||||
---
|
||||
|
||||
The `NODE_PATH` env variable is not set in the command shims (the files in `node_modules/.bin`). This env variable was really long and frequently caused errors on Windows.
|
||||
|
||||
Also, the `extend-node-path` setting is removed.
|
||||
|
||||
Related PR: [#4253](https://github.com/pnpm/pnpm/pull/4253)
|
||||
5
.changeset/pink-laws-smell.md
Normal file
5
.changeset/pink-laws-smell.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"pnpm": major
|
||||
---
|
||||
|
||||
Side effects cache is turned on by default. To turn it off, use `side-effects-cache=true`.
|
||||
5
.changeset/slimy-dancers-cough.md
Normal file
5
.changeset/slimy-dancers-cough.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"pnpm": major
|
||||
---
|
||||
|
||||
The `npm_config_argv` env variable is not set for scripts [#4153](https://github.com/pnpm/pnpm/discussions/4153).
|
||||
@@ -20,7 +20,6 @@ export default async (
|
||||
childConcurrency?: number
|
||||
depsToBuild?: Set<string>
|
||||
depsStateCache: DepsStateCache
|
||||
extendNodePath?: boolean
|
||||
extraBinPaths?: string[]
|
||||
extraEnv?: Record<string, string>
|
||||
lockfileDir: string
|
||||
@@ -70,7 +69,6 @@ async function buildDependency (
|
||||
depPath: string,
|
||||
depGraph: DependenciesGraph,
|
||||
opts: {
|
||||
extendNodePath?: boolean
|
||||
extraBinPaths?: string[]
|
||||
extraEnv?: Record<string, string>
|
||||
depsStateCache: DepsStateCache
|
||||
@@ -192,7 +190,6 @@ export async function linkBinsOfDependencies (
|
||||
depNode: DependenciesGraphNode,
|
||||
depGraph: DependenciesGraph,
|
||||
opts: {
|
||||
extendNodePath?: boolean
|
||||
optional: boolean
|
||||
warn: (message: string) => void
|
||||
}
|
||||
@@ -230,11 +227,11 @@ export async function linkBinsOfDependencies (
|
||||
}))
|
||||
)
|
||||
|
||||
await linkBinsOfPackages(pkgs, binPath, { extendNodePath: opts.extendNodePath, warn: opts.warn })
|
||||
await linkBinsOfPackages(pkgs, binPath)
|
||||
|
||||
// link also the bundled dependencies` bins
|
||||
if (depNode.hasBundledDependencies) {
|
||||
const bundledModules = path.join(depNode.dir, 'node_modules')
|
||||
await linkBins(bundledModules, binPath, { extendNodePath: opts.extendNodePath, warn: opts.warn })
|
||||
await linkBins(bundledModules, binPath, { warn: opts.warn })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,6 @@
|
||||
"@pnpm/types": "workspace:7.9.0",
|
||||
"@zkochan/npm-conf": "2.0.2",
|
||||
"camelcase": "^6.2.0",
|
||||
"can-write-to-dir": "^1.1.1",
|
||||
"is-subdir": "^1.1.1",
|
||||
"normalize-registry-url": "2.0.0",
|
||||
"ramda": "^0.27.1",
|
||||
|
||||
@@ -145,7 +145,6 @@ export interface Config {
|
||||
|
||||
testPattern?: string[]
|
||||
changedFilesIgnorePattern?: string[]
|
||||
extendNodePath?: boolean
|
||||
rootProjectManifest?: ProjectManifest
|
||||
userConfig: Record<string, string>
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
import path from 'path'
|
||||
import isSubdir from 'is-subdir'
|
||||
|
||||
export default function findBestGlobalPrefixOnWindows (
|
||||
defaultNpmGlobalPrefix: string,
|
||||
env: { [key: string]: string | undefined }
|
||||
) {
|
||||
if (process.platform !== 'win32') return defaultNpmGlobalPrefix
|
||||
if (
|
||||
(env.LOCALAPPDATA != null && isSubdir(env.LOCALAPPDATA, defaultNpmGlobalPrefix)) ||
|
||||
(env.APPDATA != null && isSubdir(env.APPDATA, defaultNpmGlobalPrefix))
|
||||
) {
|
||||
return defaultNpmGlobalPrefix
|
||||
}
|
||||
if (env.APPDATA) return path.join(env.APPDATA, 'npm')
|
||||
return defaultNpmGlobalPrefix
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import path from 'path'
|
||||
import fs from 'fs'
|
||||
import os from 'os'
|
||||
import { LAYOUT_VERSION } from '@pnpm/constants'
|
||||
import PnpmError from '@pnpm/error'
|
||||
import globalBinDir from '@pnpm/global-bin-dir'
|
||||
@@ -9,13 +8,11 @@ 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'
|
||||
import { sync as canWriteToDir } from 'can-write-to-dir'
|
||||
import normalizeRegistryUrl from 'normalize-registry-url'
|
||||
import fromPairs from 'ramda/src/fromPairs'
|
||||
import realpathMissing from 'realpath-missing'
|
||||
import whichcb from 'which'
|
||||
import getScopeRegistries from './getScopeRegistries'
|
||||
import findBestGlobalPrefix from './findBestGlobalPrefix'
|
||||
import { getCacheDir, getConfigDir, getDataDir, getStateDir } from './dirs'
|
||||
import {
|
||||
Config,
|
||||
@@ -28,8 +25,6 @@ export { Config, UniversalOptions }
|
||||
|
||||
const npmDefaults = loadNpmConf.defaults
|
||||
|
||||
const PNPM_GLOBAL = 'pnpm-global'
|
||||
|
||||
async function which (cmd: string) {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
whichcb(cmd, (err, resolvedPath) => (err != null) ? reject(err) : resolve(resolvedPath!))
|
||||
@@ -46,7 +41,6 @@ export const types = Object.assign({
|
||||
dir: String,
|
||||
'enable-modules-dir': Boolean,
|
||||
'enable-pre-post-scripts': Boolean,
|
||||
'extend-node-path': Boolean,
|
||||
'fetch-timeout': Number,
|
||||
'fetching-concurrency': Number,
|
||||
filter: [String, Array],
|
||||
@@ -175,7 +169,6 @@ export default async (
|
||||
bail: true,
|
||||
color: 'auto',
|
||||
'enable-modules-dir': true,
|
||||
'extend-node-path': true,
|
||||
'fetch-retries': 2,
|
||||
'fetch-retry-factor': 10,
|
||||
'fetch-retry-maxtimeout': 60000,
|
||||
@@ -203,6 +196,7 @@ export default async (
|
||||
'save-peer': false,
|
||||
'save-workspace-protocol': true,
|
||||
'scripts-prepend-node-path': false,
|
||||
'side-effects-cache': true,
|
||||
symlink: true,
|
||||
'shared-workspace-lockfile': true,
|
||||
'shared-workspace-shrinkwrap': true,
|
||||
@@ -282,20 +276,8 @@ export default async (
|
||||
let globalDirRoot
|
||||
if (pnpmConfig['globalDir']) {
|
||||
globalDirRoot = pnpmConfig['globalDir']
|
||||
} else if (pnpmConfig.useBetaCli) {
|
||||
globalDirRoot = path.join(pnpmConfig.pnpmHomeDir, 'global-packages')
|
||||
} else {
|
||||
let npmGlobalPrefix: string = findBestGlobalPrefix(npmConfig.globalPrefix, process.env)
|
||||
const globalDirName = `${path.sep}${PNPM_GLOBAL}${path.sep}`
|
||||
if (npmGlobalPrefix.includes(globalDirName)) {
|
||||
npmGlobalPrefix = npmGlobalPrefix.substring(0, npmGlobalPrefix.indexOf(globalDirName))
|
||||
} else {
|
||||
const npmGlobalBinDir = process.platform === 'win32'
|
||||
? npmGlobalPrefix
|
||||
: path.resolve(npmGlobalPrefix, 'bin')
|
||||
knownGlobalBinDirCandidates.push(npmGlobalBinDir)
|
||||
}
|
||||
globalDirRoot = path.join(firstWithWriteAccess([npmGlobalPrefix, os.homedir()]), PNPM_GLOBAL)
|
||||
globalDirRoot = path.join(pnpmConfig.pnpmHomeDir, 'global-packages')
|
||||
}
|
||||
pnpmConfig.dir = path.join(globalDirRoot, LAYOUT_VERSION.toString())
|
||||
|
||||
@@ -318,7 +300,6 @@ export default async (
|
||||
pnpmConfig.saveProd = true
|
||||
pnpmConfig.saveDev = false
|
||||
pnpmConfig.saveOptional = false
|
||||
pnpmConfig.extendNodePath = false
|
||||
if ((pnpmConfig.hoistPattern != null) && (pnpmConfig.hoistPattern.length > 1 || pnpmConfig.hoistPattern[0] !== '*')) {
|
||||
if (opts.cliOptions['hoist-pattern']) {
|
||||
throw new PnpmError('CONFIG_CONFLICT_HOIST_PATTERN_WITH_GLOBAL',
|
||||
@@ -501,23 +482,3 @@ function getProcessEnv (env: string) {
|
||||
process.env[env.toUpperCase()] ??
|
||||
process.env[env.toLowerCase()]
|
||||
}
|
||||
|
||||
function firstWithWriteAccess (dirs: string[]) {
|
||||
const first = dirs.find((dir) => {
|
||||
try {
|
||||
return canWriteToDir(dir)
|
||||
} catch (err: any) { // eslint-disable-line
|
||||
if (err.code !== 'ENOENT') throw err
|
||||
}
|
||||
try {
|
||||
fs.mkdirSync(dir, { recursive: true })
|
||||
return true
|
||||
} catch (err: any) { // eslint-disable-line
|
||||
return false
|
||||
}
|
||||
})
|
||||
if (first == null) {
|
||||
throw new PnpmError('NO_SUITABLE_GLOBAL_DIR', `pnpm has no write access to global direcotry. Tried locations: ${dirs.join(', ')}`)
|
||||
}
|
||||
return first
|
||||
}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
import findBestGlobalPrefix from '../lib/findBestGlobalPrefix'
|
||||
|
||||
test('findBestGlobalPrefix()', () => {
|
||||
if (process.platform !== 'win32') {
|
||||
// skipping on non-windows
|
||||
return
|
||||
}
|
||||
|
||||
const env = {
|
||||
APPDATA: 'C:\\Users\\Imre\\AppData\\Roaming',
|
||||
LOCALAPPDATA: 'C:\\Users\\Imre\\AppData\\Local',
|
||||
}
|
||||
|
||||
expect(
|
||||
// keep npm global prefix if is inside AppData\Local
|
||||
findBestGlobalPrefix('C:\\Users\\Imre\\AppData\\Local\\nvs\\default', env)).toEqual(
|
||||
'C:\\Users\\Imre\\AppData\\Local\\nvs\\default'
|
||||
)
|
||||
|
||||
expect(
|
||||
// keep npm global prefix if is inside AppData\Roaming
|
||||
findBestGlobalPrefix('C:\\Users\\Imre\\AppData\\Roaming\\nvs\\default', env)).toEqual(
|
||||
'C:\\Users\\Imre\\AppData\\Roaming\\nvs\\default'
|
||||
)
|
||||
|
||||
expect(
|
||||
// prefer location in AppData\Roaming
|
||||
findBestGlobalPrefix('C:\\foo', env)).toEqual(
|
||||
'C:\\Users\\Imre\\AppData\\Roaming\\npm'
|
||||
)
|
||||
|
||||
expect(
|
||||
findBestGlobalPrefix('C:\\foo', {})).toEqual(
|
||||
'C:\\foo'
|
||||
)
|
||||
})
|
||||
@@ -62,7 +62,6 @@ test('correct settings on global install', async () => {
|
||||
},
|
||||
})
|
||||
expect(config.save).toBe(true)
|
||||
expect(config.extendNodePath).toBe(false)
|
||||
})
|
||||
|
||||
test('throw error if --shared-workspace-lockfile is used with --global', async () => {
|
||||
@@ -774,18 +773,3 @@ test('getConfig() sets sideEffectsCacheRead and sideEffectsCacheWrite when side-
|
||||
expect(config.sideEffectsCacheRead).toBeTruthy()
|
||||
expect(config.sideEffectsCacheWrite).toBeTruthy()
|
||||
})
|
||||
|
||||
test('getConfig() sets sideEffectsCacheRead and sideEffectsCacheWrite when side-effects-cache-readonly is set', async () => {
|
||||
const { config } = await getConfig({
|
||||
cliOptions: {
|
||||
'side-effects-cache-readonly': true,
|
||||
},
|
||||
packageManager: {
|
||||
name: 'pnpm',
|
||||
version: '1.0.0',
|
||||
},
|
||||
})
|
||||
expect(config).toBeDefined()
|
||||
expect(config.sideEffectsCacheRead).toBeTruthy()
|
||||
expect(config.sideEffectsCacheWrite).toBeFalsy()
|
||||
})
|
||||
|
||||
@@ -19,7 +19,6 @@ export interface StrictInstallOptions {
|
||||
frozenLockfile: boolean
|
||||
frozenLockfileIfExists: boolean
|
||||
enablePnp: boolean
|
||||
extendNodePath: boolean
|
||||
extraBinPaths: string[]
|
||||
useLockfile: boolean
|
||||
linkWorkspacePackagesDepth: number
|
||||
@@ -108,7 +107,6 @@ const defaults = async (opts: InstallOptions) => {
|
||||
depth: 0,
|
||||
enablePnp: false,
|
||||
engineStrict: false,
|
||||
extendNodePath: true,
|
||||
force: false,
|
||||
forceSharedLockfile: false,
|
||||
frozenLockfile: false,
|
||||
|
||||
@@ -764,7 +764,6 @@ const _installInContext: InstallFunction = async (projects, ctx, opts) => {
|
||||
dependenciesByProjectId,
|
||||
depsStateCache,
|
||||
force: opts.force,
|
||||
extendNodePath: opts.extendNodePath,
|
||||
hoistedDependencies: ctx.hoistedDependencies,
|
||||
hoistedModulesDir: ctx.hoistedModulesDir,
|
||||
hoistPattern: ctx.hoistPattern,
|
||||
@@ -823,7 +822,6 @@ const _installInContext: InstallFunction = async (projects, ctx, opts) => {
|
||||
childConcurrency: opts.childConcurrency,
|
||||
depsStateCache,
|
||||
depsToBuild: new Set(result.newDepPaths),
|
||||
extendNodePath: opts.extendNodePath,
|
||||
extraBinPaths: ctx.extraBinPaths,
|
||||
extraEnv,
|
||||
lockfileDir: ctx.lockfileDir,
|
||||
@@ -861,7 +859,6 @@ const _installInContext: InstallFunction = async (projects, ctx, opts) => {
|
||||
}, {})
|
||||
linkedPackages = await linkBins(project.modulesDir, project.binsDir, {
|
||||
allowExoticManifests: true,
|
||||
extendNodePath: opts.extendNodePath,
|
||||
projectManifest: project.manifest,
|
||||
nodeExecPathByAlias,
|
||||
warn: binWarn.bind(null, project.rootDir),
|
||||
@@ -891,8 +888,7 @@ const _installInContext: InstallFunction = async (projects, ctx, opts) => {
|
||||
)
|
||||
)
|
||||
.filter(({ manifest }) => manifest != null) as Array<{ location: string, manifest: DependencyManifest }>,
|
||||
project.binsDir,
|
||||
{ extendNodePath: opts.extendNodePath, warn: binWarn.bind(null, project.rootDir) }
|
||||
project.binsDir
|
||||
)
|
||||
}
|
||||
const projectToInstall = projects[index]
|
||||
|
||||
@@ -48,7 +48,6 @@ export default async function linkPackages (
|
||||
}
|
||||
force: boolean
|
||||
depsStateCache: DepsStateCache
|
||||
extendNodePath?: boolean
|
||||
hoistedDependencies: HoistedDependencies
|
||||
hoistedModulesDir: string
|
||||
hoistPattern?: string[]
|
||||
@@ -249,7 +248,6 @@ export default async function linkPackages (
|
||||
packages: omit(Array.from(opts.skipped), currentLockfile.packages),
|
||||
}
|
||||
newHoistedDependencies = await hoist({
|
||||
extendNodePath: opts.extendNodePath,
|
||||
lockfile: hoistLockfile,
|
||||
importerIds: projectIds,
|
||||
lockfileDir: opts.lockfileDir,
|
||||
|
||||
@@ -144,10 +144,7 @@ export default async function link (
|
||||
}
|
||||
|
||||
const linkToBin = maybeOpts?.linkToBin ?? path.join(destModules, '.bin')
|
||||
await linkBinsOfPackages(linkedPkgs.map((p) => ({ manifest: p.manifest, location: p.path })), linkToBin, {
|
||||
extendNodePath: opts.extendNodePath,
|
||||
warn: (message: string) => logger.info({ message, prefix: opts.dir }),
|
||||
})
|
||||
await linkBinsOfPackages(linkedPkgs.map((p) => ({ manifest: p.manifest, location: p.path })), linkToBin)
|
||||
|
||||
let newPkg!: ProjectManifest
|
||||
if (opts.targetDependenciesField) {
|
||||
|
||||
@@ -22,7 +22,6 @@ interface StrictLinkOptions {
|
||||
reporter: ReporterFunction
|
||||
targetDependenciesField?: DependenciesField
|
||||
dir: string
|
||||
extendNodePath: boolean
|
||||
|
||||
hoistPattern: string[] | undefined
|
||||
forceHoistPattern: boolean
|
||||
@@ -54,7 +53,6 @@ async function defaults (opts: LinkOptions) {
|
||||
return {
|
||||
binsDir: path.join(dir, 'node_modules', '.bin'),
|
||||
dir,
|
||||
extendNodePath: true,
|
||||
force: false,
|
||||
forceSharedLockfile: false,
|
||||
hoistPattern: undefined,
|
||||
|
||||
@@ -558,27 +558,6 @@ test('bin specified in the directories property linked to .bin folder', async ()
|
||||
await project.isExecutable('.bin/pkg-with-directories-bin')
|
||||
})
|
||||
|
||||
test('command shim is created withoud NODE_PATH', async () => {
|
||||
const project = prepareEmpty()
|
||||
|
||||
const manifest = await addDependenciesToPackage({}, ['rimraf@2.5.1'], await testDefaults({ fastUnpack: false, extendNodePath: false }))
|
||||
|
||||
{
|
||||
await project.isExecutable('.bin/rimraf')
|
||||
const cmdContent = await fs.readFile('node_modules/.bin/rimraf')
|
||||
expect(cmdContent).not.toContain('NODE_PATH')
|
||||
}
|
||||
|
||||
await rimraf('node_modules')
|
||||
await install(manifest, await testDefaults({ extendNodePath: true, fastUnpack: false, frozenLockfile: true }))
|
||||
|
||||
{
|
||||
await project.isExecutable('.bin/rimraf')
|
||||
const cmdContent = await fs.readFile('node_modules/.bin/rimraf')
|
||||
expect(cmdContent).not.toContain('NODE_PATH')
|
||||
}
|
||||
})
|
||||
|
||||
testOnNonWindows('building native addons', async () => {
|
||||
const project = prepareEmpty()
|
||||
|
||||
|
||||
@@ -94,7 +94,6 @@ export interface HeadlessOptions {
|
||||
}
|
||||
enablePnp?: boolean
|
||||
engineStrict: boolean
|
||||
extendNodePath?: boolean
|
||||
extraBinPaths?: string[]
|
||||
ignoreScripts: boolean
|
||||
ignorePackageManifest?: boolean
|
||||
@@ -288,7 +287,6 @@ export default async (opts: HeadlessOptions) => {
|
||||
if (opts.nodeLinker === 'hoisted' && hierarchy && prevGraph) {
|
||||
await linkHoistedModules(opts.storeController, graph, prevGraph, hierarchy, {
|
||||
depsStateCache,
|
||||
extendNodePath: opts.extendNodePath,
|
||||
force: opts.force,
|
||||
lockfileDir: opts.lockfileDir,
|
||||
sideEffectsCacheRead: opts.sideEffectsCacheRead,
|
||||
@@ -338,7 +336,6 @@ export default async (opts: HeadlessOptions) => {
|
||||
packages: omit(Array.from(skipped), filteredLockfile.packages),
|
||||
}
|
||||
newHoistedDependencies = await hoist({
|
||||
extendNodePath: opts.extendNodePath,
|
||||
lockfile: hoistLockfile,
|
||||
importerIds,
|
||||
lockfileDir,
|
||||
@@ -352,7 +349,7 @@ export default async (opts: HeadlessOptions) => {
|
||||
newHoistedDependencies = {}
|
||||
}
|
||||
|
||||
await linkAllBins(graph, { extendNodePath: opts.extendNodePath, optional: opts.include.optionalDependencies, warn })
|
||||
await linkAllBins(graph, { optional: opts.include.optionalDependencies, warn })
|
||||
|
||||
if ((currentLockfile != null) && !equals(importerIds.sort(), Object.keys(filteredLockfile.importers).sort())) {
|
||||
Object.assign(filteredLockfile.packages, currentLockfile.packages)
|
||||
@@ -410,7 +407,6 @@ export default async (opts: HeadlessOptions) => {
|
||||
await buildModules(graph, Array.from(directNodes), {
|
||||
childConcurrency: opts.childConcurrency,
|
||||
extraBinPaths,
|
||||
extendNodePath: opts.extendNodePath,
|
||||
extraEnv,
|
||||
depsStateCache,
|
||||
lockfileDir,
|
||||
@@ -432,7 +428,7 @@ export default async (opts: HeadlessOptions) => {
|
||||
if (!opts.ignorePackageManifest) {
|
||||
await Promise.all(opts.projects.map(async (project) => {
|
||||
if (opts.publicHoistPattern?.length && path.relative(opts.lockfileDir, project.rootDir) === '') {
|
||||
await linkBinsOfImporter(project, { extendNodePath: opts.extendNodePath })
|
||||
await linkBinsOfImporter(project)
|
||||
} else {
|
||||
const directPkgDirs = Object.values(directDependenciesByImporterId[project.id])
|
||||
await linkBinsOfPackages(
|
||||
@@ -445,11 +441,7 @@ export default async (opts: HeadlessOptions) => {
|
||||
)
|
||||
)
|
||||
.filter(({ manifest }) => manifest != null) as Array<{ location: string, manifest: DependencyManifest }>,
|
||||
project.binsDir,
|
||||
{
|
||||
extendNodePath: opts.extendNodePath,
|
||||
warn: (message: string) => logger.info({ message, prefix: project.rootDir }),
|
||||
}
|
||||
project.binsDir
|
||||
)
|
||||
}
|
||||
}))
|
||||
@@ -542,15 +534,11 @@ async function linkBinsOfImporter (
|
||||
manifest: ProjectManifest
|
||||
modulesDir: string
|
||||
rootDir: string
|
||||
},
|
||||
opts: {
|
||||
extendNodePath?: boolean
|
||||
}
|
||||
) {
|
||||
const warn = (message: string) => logger.info({ message, prefix: rootDir })
|
||||
return linkBins(modulesDir, binsDir, {
|
||||
allowExoticManifests: true,
|
||||
extendNodePath: opts.extendNodePath,
|
||||
projectManifest: manifest,
|
||||
warn,
|
||||
})
|
||||
@@ -687,7 +675,6 @@ async function linkAllPkgs (
|
||||
async function linkAllBins (
|
||||
depGraph: DependenciesGraph,
|
||||
opts: {
|
||||
extendNodePath?: boolean
|
||||
optional: boolean
|
||||
warn: (message: string) => void
|
||||
}
|
||||
@@ -709,7 +696,7 @@ async function linkAllBins (
|
||||
const pkgSnapshots = props<string, DependenciesGraphNode>(Object.values(childrenToLink), depGraph)
|
||||
|
||||
if (pkgSnapshots.includes(undefined as any)) { // eslint-disable-line
|
||||
await linkBins(depNode.modules, binPath, { extendNodePath: opts.extendNodePath, warn: opts.warn })
|
||||
await linkBins(depNode.modules, binPath, { warn: opts.warn })
|
||||
} else {
|
||||
const pkgs = await Promise.all(
|
||||
pkgSnapshots
|
||||
@@ -720,13 +707,13 @@ async function linkAllBins (
|
||||
}))
|
||||
)
|
||||
|
||||
await linkBinsOfPackages(pkgs, binPath, { extendNodePath: opts.extendNodePath, warn: opts.warn })
|
||||
await linkBinsOfPackages(pkgs, binPath)
|
||||
}
|
||||
|
||||
// link also the bundled dependencies` bins
|
||||
if (depNode.hasBundledDependencies) {
|
||||
const bundledModules = path.join(depNode.dir, 'node_modules')
|
||||
await linkBins(bundledModules, binPath, { extendNodePath: opts.extendNodePath, warn: opts.warn })
|
||||
await linkBins(bundledModules, binPath, { warn: opts.warn })
|
||||
}
|
||||
}))
|
||||
)
|
||||
|
||||
@@ -26,7 +26,6 @@ export default async function linkHoistedModules (
|
||||
hierarchy: DepHierarchy,
|
||||
opts: {
|
||||
depsStateCache: DepsStateCache
|
||||
extendNodePath?: boolean
|
||||
force: boolean
|
||||
lockfileDir: string
|
||||
sideEffectsCacheRead: boolean
|
||||
@@ -82,7 +81,6 @@ async function linkAllPkgsInOrder (
|
||||
parentDir: string,
|
||||
opts: {
|
||||
depsStateCache: DepsStateCache
|
||||
extendNodePath?: boolean
|
||||
force: boolean
|
||||
lockfileDir: string
|
||||
sideEffectsCacheRead: boolean
|
||||
@@ -125,7 +123,6 @@ async function linkAllPkgsInOrder (
|
||||
const binsDir = path.join(modulesDir, '.bin')
|
||||
await linkBins(modulesDir, binsDir, {
|
||||
allowExoticManifests: true,
|
||||
extendNodePath: opts.extendNodePath,
|
||||
warn: opts.warn,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ const hoistLogger = logger('hoist')
|
||||
|
||||
export default async function hoistByLockfile (
|
||||
opts: {
|
||||
extendNodePath?: boolean
|
||||
lockfile: Lockfile
|
||||
lockfileDir: string
|
||||
importerIds?: string[]
|
||||
@@ -67,7 +66,7 @@ export default async function hoistByLockfile (
|
||||
// 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, { extendNodePath: opts.extendNodePath })
|
||||
await linkAllBins(opts.privateHoistedModulesDir)
|
||||
|
||||
return hoistedDependencies
|
||||
}
|
||||
@@ -87,14 +86,14 @@ function createGetAliasHoistType (
|
||||
}
|
||||
}
|
||||
|
||||
async function linkAllBins (modulesDir: string, opts: { extendNodePath?: boolean }) {
|
||||
async function linkAllBins (modulesDir: string) {
|
||||
const bin = path.join(modulesDir, '.bin')
|
||||
const warn: WarnFunction = (message, code) => {
|
||||
if (code === 'BINARIES_CONFLICT') return
|
||||
logger.info({ message, prefix: path.join(modulesDir, '../..') })
|
||||
}
|
||||
try {
|
||||
await linkBins(modulesDir, bin, { allowExoticManifests: true, extendNodePath: opts.extendNodePath, warn })
|
||||
await linkBins(modulesDir, bin, { allowExoticManifests: true, warn })
|
||||
} catch (err: any) { // eslint-disable-line
|
||||
// Some packages generate their commands with lifecycle hooks.
|
||||
// At this stage, such commands are not generated yet.
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { promises as fs } from 'fs'
|
||||
import Module from 'module'
|
||||
import path from 'path'
|
||||
import PnpmError from '@pnpm/error'
|
||||
import logger, { globalWarn } from '@pnpm/logger'
|
||||
@@ -17,7 +16,6 @@ import pSettle from 'p-settle'
|
||||
import { KeyValuePair } from 'ramda'
|
||||
import fromPairs from 'ramda/src/fromPairs'
|
||||
import isEmpty from 'ramda/src/isEmpty'
|
||||
import union from 'ramda/src/union'
|
||||
import unnest from 'ramda/src/unnest'
|
||||
import partition from 'ramda/src/partition'
|
||||
import fixBin from 'bin-links/lib/fix-bin'
|
||||
@@ -36,7 +34,6 @@ export default async (
|
||||
binsDir: string,
|
||||
opts: {
|
||||
allowExoticManifests?: boolean
|
||||
extendNodePath?: boolean
|
||||
nodeExecPathByAlias?: Record<string, string>
|
||||
projectManifest?: ProjectManifest
|
||||
warn: WarnFunction
|
||||
@@ -71,7 +68,7 @@ export default async (
|
||||
)
|
||||
|
||||
const cmdsToLink = directDependencies != null ? preferDirectCmds(allCmds) : allCmds
|
||||
return linkBins(cmdsToLink, binsDir, opts)
|
||||
return linkBins(cmdsToLink, binsDir)
|
||||
}
|
||||
|
||||
function preferDirectCmds (allCmds: Array<CommandInfo & { isDirectDependency?: boolean }>) {
|
||||
@@ -89,11 +86,7 @@ export async function linkBinsOfPackages (
|
||||
nodeExecPath?: string
|
||||
location: string
|
||||
}>,
|
||||
binsTarget: string,
|
||||
opts: {
|
||||
extendNodePath?: boolean
|
||||
warn: WarnFunction
|
||||
}
|
||||
binsTarget: string
|
||||
): Promise<string[]> {
|
||||
if (pkgs.length === 0) return []
|
||||
|
||||
@@ -105,7 +98,7 @@ export async function linkBinsOfPackages (
|
||||
.filter((cmds: Command[]) => cmds.length)
|
||||
)
|
||||
|
||||
return linkBins(allCmds, binsTarget, opts)
|
||||
return linkBins(allCmds, binsTarget)
|
||||
}
|
||||
|
||||
type CommandInfo = Command & {
|
||||
@@ -117,10 +110,7 @@ type CommandInfo = Command & {
|
||||
|
||||
async function linkBins (
|
||||
allCmds: CommandInfo[],
|
||||
binsDir: string,
|
||||
opts: {
|
||||
extendNodePath?: boolean
|
||||
}
|
||||
binsDir: string
|
||||
): Promise<string[]> {
|
||||
if (allCmds.length === 0) return [] as string[]
|
||||
|
||||
@@ -128,7 +118,7 @@ async function linkBins (
|
||||
|
||||
const [cmdsWithOwnName, cmdsWithOtherNames] = partition(({ ownName }) => ownName, allCmds)
|
||||
|
||||
const results1 = await pSettle(cmdsWithOwnName.map(async (cmd) => linkBin(cmd, binsDir, opts)))
|
||||
const results1 = await pSettle(cmdsWithOwnName.map(async (cmd) => linkBin(cmd, binsDir)))
|
||||
|
||||
const usedNames = fromPairs(cmdsWithOwnName.map((cmd) => [cmd.name, cmd.name] as KeyValuePair<string, string>))
|
||||
const results2 = await pSettle(cmdsWithOtherNames.map(async (cmd) => {
|
||||
@@ -142,7 +132,7 @@ async function linkBins (
|
||||
return Promise.resolve(undefined)
|
||||
}
|
||||
usedNames[cmd.name] = cmd.pkgName
|
||||
return linkBin(cmd, binsDir, opts)
|
||||
return linkBin(cmd, binsDir)
|
||||
}))
|
||||
|
||||
// We want to create all commands that we can create before throwing an exception
|
||||
@@ -200,21 +190,12 @@ async function getPackageBinsFromManifest (manifest: DependencyManifest, pkgDir:
|
||||
}))
|
||||
}
|
||||
|
||||
async function linkBin (cmd: CommandInfo, binsDir: string, opts?: { extendNodePath?: boolean }) {
|
||||
async function linkBin (cmd: CommandInfo, binsDir: string) {
|
||||
const externalBinPath = path.join(binsDir, cmd.name)
|
||||
|
||||
try {
|
||||
let nodePath: string[] | undefined
|
||||
if (opts?.extendNodePath !== false) {
|
||||
nodePath = await getBinNodePaths(cmd.path)
|
||||
const binsParentDir = path.dirname(binsDir)
|
||||
if (path.relative(cmd.path, binsParentDir) !== '') {
|
||||
nodePath = union(nodePath, await getBinNodePaths(binsParentDir))
|
||||
}
|
||||
}
|
||||
await cmdShim(cmd.path, externalBinPath, {
|
||||
createPwshFile: cmd.makePowerShellShim,
|
||||
nodePath,
|
||||
nodeExecPath: cmd.nodeExecPath,
|
||||
})
|
||||
} catch (err: any) { // eslint-disable-line
|
||||
@@ -231,16 +212,6 @@ async function linkBin (cmd: CommandInfo, binsDir: string, opts?: { extendNodePa
|
||||
}
|
||||
}
|
||||
|
||||
async function getBinNodePaths (target: string): Promise<string[]> {
|
||||
const targetDir = path.dirname(target)
|
||||
const targetRealPath = await fs.realpath(targetDir)
|
||||
|
||||
return union(
|
||||
Module['_nodeModulePaths'](targetRealPath),
|
||||
Module['_nodeModulePaths'](targetDir)
|
||||
)
|
||||
}
|
||||
|
||||
async function safeReadPkgJson (pkgDir: string): Promise<DependencyManifest | null> {
|
||||
try {
|
||||
return await readPackageJsonFromDir(pkgDir) as DependencyManifest
|
||||
|
||||
@@ -146,7 +146,6 @@ test('linkBins() does not link own bins', async () => {
|
||||
test('linkBinsOfPackages()', async () => {
|
||||
const binTarget = tempy.directory()
|
||||
const simpleFixture = f.prepare('simple-fixture')
|
||||
const warn = jest.fn()
|
||||
|
||||
await linkBinsOfPackages(
|
||||
[
|
||||
@@ -155,11 +154,9 @@ test('linkBinsOfPackages()', async () => {
|
||||
manifest: (await import(path.join(simpleFixture, 'node_modules/simple/package.json'))).default,
|
||||
},
|
||||
],
|
||||
binTarget,
|
||||
{ warn }
|
||||
binTarget
|
||||
)
|
||||
|
||||
expect(warn).not.toHaveBeenCalled()
|
||||
expect(await fs.readdir(binTarget)).toEqual(getExpectedBins(['simple']))
|
||||
const binLocation = path.join(binTarget, 'simple')
|
||||
expect(await exists(binLocation)).toBe(true)
|
||||
@@ -200,7 +197,6 @@ test('linkBins() resolves conflicts. Prefer packages that use their name as bin
|
||||
test('linkBinsOfPackages() resolves conflicts. Prefer packages that use their name as bin name', async () => {
|
||||
const binTarget = tempy.directory()
|
||||
const binNameConflictsFixture = f.prepare('bin-name-conflicts')
|
||||
const warn = jest.fn()
|
||||
|
||||
const modulesPath = path.join(binNameConflictsFixture, 'node_modules')
|
||||
|
||||
@@ -215,8 +211,7 @@ test('linkBinsOfPackages() resolves conflicts. Prefer packages that use their na
|
||||
manifest: (await import(path.join(modulesPath, 'foo', 'package.json'))).default,
|
||||
},
|
||||
],
|
||||
binTarget,
|
||||
{ warn }
|
||||
binTarget
|
||||
)
|
||||
|
||||
expect(binsConflictLogger.debug).toHaveBeenCalledWith({
|
||||
|
||||
@@ -108,10 +108,6 @@ export default async function run (inputArgv: string[]) {
|
||||
process.exitCode = 1
|
||||
return
|
||||
}
|
||||
if (!config.useBetaCli) {
|
||||
process.env['npm_config_argv'] = JSON.stringify(argv)
|
||||
config.rawConfig.argv = process.env['npm_config_argv']
|
||||
}
|
||||
|
||||
let write: (text: string) => void = process.stdout.write.bind(process.stdout)
|
||||
// chalk reads the FORCE_COLOR env variable
|
||||
@@ -194,7 +190,7 @@ export default async function run (inputArgv: string[]) {
|
||||
const relativeWSDirPath = () => path.relative(process.cwd(), wsDir) || '.'
|
||||
if (config.workspaceRoot) {
|
||||
filters.push({ filter: `{${relativeWSDirPath()}}`, followProdDepsOnly: false })
|
||||
} else if (config.useBetaCli && (cmd === 'run' || cmd === 'exec' || cmd === 'add' || cmd === 'test')) {
|
||||
} else if (cmd === 'run' || cmd === 'exec' || cmd === 'add' || cmd === 'test') {
|
||||
filters.push({ filter: `!{${relativeWSDirPath()}}`, followProdDepsOnly: false })
|
||||
}
|
||||
|
||||
@@ -204,7 +200,7 @@ export default async function run (inputArgv: string[]) {
|
||||
workspaceDir: wsDir,
|
||||
testPattern: config.testPattern,
|
||||
changedFilesIgnorePattern: config.changedFilesIgnorePattern,
|
||||
useGlobDirFiltering: config.useBetaCli,
|
||||
useGlobDirFiltering: true,
|
||||
})
|
||||
config.selectedProjectsGraph = filterResults.selectedProjectsGraph
|
||||
if (isEmpty(config.selectedProjectsGraph)) {
|
||||
|
||||
@@ -14,8 +14,7 @@ test('global installation', async () => {
|
||||
const global = path.resolve('..', 'global')
|
||||
await fs.mkdir(global)
|
||||
|
||||
const env = { NPM_CONFIG_PREFIX: global }
|
||||
if (process.env.APPDATA) env['APPDATA'] = global
|
||||
const env = { XDG_DATA_HOME: global }
|
||||
|
||||
await execPnpm(['install', '--global', 'is-positive'], { env })
|
||||
|
||||
@@ -23,7 +22,7 @@ test('global installation', async () => {
|
||||
// https://github.com/pnpm/pnpm/issues/808
|
||||
await execPnpm(['install', '--global', 'is-negative'], { env })
|
||||
|
||||
const globalPrefix = path.join(global, `pnpm-global/${LAYOUT_VERSION}`)
|
||||
const globalPrefix = path.join(global, `pnpm/global-packages/${LAYOUT_VERSION}`)
|
||||
|
||||
const { default: isPositive } = await import(path.join(globalPrefix, 'node_modules', 'is-positive'))
|
||||
expect(typeof isPositive).toBe('function')
|
||||
@@ -48,14 +47,12 @@ test('always install latest when doing global installation without spec', async
|
||||
const global = path.resolve('..', 'global')
|
||||
await fs.mkdir(global)
|
||||
|
||||
const env = { NPM_CONFIG_PREFIX: global }
|
||||
|
||||
if (process.env.APPDATA) env['APPDATA'] = global
|
||||
const env = { XDG_DATA_HOME: global }
|
||||
|
||||
await execPnpm(['install', '-g', 'peer-c@1'], { env })
|
||||
await execPnpm(['install', '-g', 'peer-c'], { env })
|
||||
|
||||
const globalPrefix = path.join(global, `pnpm-global/${LAYOUT_VERSION}`)
|
||||
const globalPrefix = path.join(global, `pnpm/global-packages/${LAYOUT_VERSION}`)
|
||||
|
||||
process.chdir(globalPrefix)
|
||||
|
||||
@@ -73,10 +70,9 @@ test('run lifecycle events of global packages in correct working directory', asy
|
||||
const global = path.resolve('..', 'global')
|
||||
await fs.mkdir(global)
|
||||
|
||||
const env = { NPM_CONFIG_PREFIX: global }
|
||||
if (process.env.APPDATA) env['APPDATA'] = global
|
||||
const env = { XDG_DATA_HOME: global }
|
||||
|
||||
await execPnpm(['install', '-g', 'postinstall-calls-pnpm@1.0.0'], { env })
|
||||
|
||||
expect(await exists(path.join(global, `pnpm-global/${LAYOUT_VERSION}/node_modules/postinstall-calls-pnpm/created-by-postinstall`))).toBeTruthy()
|
||||
expect(await exists(path.join(global, `pnpm/global-packages/${LAYOUT_VERSION}/node_modules/postinstall-calls-pnpm/created-by-postinstall`))).toBeTruthy()
|
||||
})
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { promises as fs } from 'fs'
|
||||
import path from 'path'
|
||||
import prepare from '@pnpm/prepare'
|
||||
import { PackageManifest } from '@pnpm/types'
|
||||
@@ -100,46 +99,6 @@ test('prepare is executed after argumentless installation', () => {
|
||||
expect(result.stdout.toString()).toContain('Hello world!')
|
||||
})
|
||||
|
||||
test('lifecycle events don\'t have when config is set', async () => {
|
||||
prepare({
|
||||
dependencies: {
|
||||
'write-lifecycle-env': '^1.0.0',
|
||||
},
|
||||
scripts: {
|
||||
postinstall: 'write-lifecycle-env',
|
||||
},
|
||||
})
|
||||
await fs.writeFile('.npmrc', 'use-beta-cli=true', 'utf8')
|
||||
|
||||
execPnpmSync(['install'])
|
||||
|
||||
const lifecycleEnv = await loadJsonFile<object>('env.json')
|
||||
|
||||
expect(lifecycleEnv['npm_config_argv']).toStrictEqual(undefined)
|
||||
})
|
||||
|
||||
test('lifecycle events have proper npm_config_argv', async () => {
|
||||
prepare({
|
||||
dependencies: {
|
||||
'write-lifecycle-env': '^1.0.0',
|
||||
},
|
||||
scripts: {
|
||||
postinstall: 'write-lifecycle-env',
|
||||
},
|
||||
})
|
||||
await fs.writeFile('.npmrc', 'use-beta-cli=false', 'utf8')
|
||||
|
||||
execPnpmSync(['install'])
|
||||
|
||||
const lifecycleEnv = await loadJsonFile<object>('env.json')
|
||||
|
||||
expect(JSON.parse(lifecycleEnv['npm_config_argv'])).toStrictEqual({
|
||||
cooked: ['install'],
|
||||
original: ['install'],
|
||||
remain: ['install'],
|
||||
})
|
||||
})
|
||||
|
||||
test('dependency should not be added to package.json and lockfile if it was not built successfully', async () => {
|
||||
const project = prepare({ name: 'foo', version: '1.0.0' })
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { promises as fs } from 'fs'
|
||||
import { promises as fs, writeFileSync } from 'fs'
|
||||
import path from 'path'
|
||||
import { WANTED_LOCKFILE } from '@pnpm/constants'
|
||||
import { Lockfile } from '@pnpm/lockfile-types'
|
||||
@@ -80,7 +80,7 @@ test('write to stderr when --use-stderr is used', async () => {
|
||||
test('install with package-lock=false in .npmrc', async () => {
|
||||
const project = prepare()
|
||||
|
||||
await fs.writeFile('.npmrc', 'package-lock=false', 'utf8')
|
||||
writeFileSync('.npmrc', 'package-lock=false', 'utf8')
|
||||
|
||||
await execPnpm(['add', 'is-positive'])
|
||||
|
||||
@@ -238,10 +238,17 @@ test('`pnpm add` should fail if no package name was provided', () => {
|
||||
expect(stdout.toString()).toContain('`pnpm add` requires the package name')
|
||||
})
|
||||
|
||||
test('`pnpm recursive add` should fail if no package name was provided', () => {
|
||||
prepare()
|
||||
test('`pnpm -r add` should fail if no package name was provided', () => {
|
||||
preparePackages([
|
||||
{
|
||||
name: 'project',
|
||||
version: '1.0.0',
|
||||
},
|
||||
])
|
||||
|
||||
const { status, stdout } = execPnpmSync(['recursive', 'add'])
|
||||
writeFileSync('pnpm-workspace.yaml', '', 'utf8')
|
||||
|
||||
const { status, stdout } = execPnpmSync(['-r', 'add'])
|
||||
|
||||
expect(status).toBe(1)
|
||||
expect(stdout.toString()).toContain('`pnpm add` requires the package name')
|
||||
|
||||
@@ -24,8 +24,7 @@ skipOnWindows('self-update stops the store server', async () => {
|
||||
const global = path.resolve('global')
|
||||
await fs.mkdir(global)
|
||||
|
||||
const env = { NPM_CONFIG_PREFIX: global }
|
||||
if (process.env.APPDATA) env['APPDATA'] = global
|
||||
const env = { XDG_DATA_HOME: global }
|
||||
|
||||
await execPnpm(['install', '-g', 'pnpm', '--store-dir', path.resolve('..', 'store')], { env })
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ import { promises as fs } from 'fs'
|
||||
import path from 'path'
|
||||
import { LAYOUT_VERSION } from '@pnpm/constants'
|
||||
import { tempDir } from '@pnpm/prepare'
|
||||
import isWindows from 'is-windows'
|
||||
import { execPnpmSync } from './utils'
|
||||
|
||||
test('pnpm root', async () => {
|
||||
@@ -22,16 +21,10 @@ test('pnpm root -g', async () => {
|
||||
const global = path.resolve('global')
|
||||
await fs.mkdir(global)
|
||||
|
||||
const env = { NPM_CONFIG_PREFIX: global }
|
||||
if (process.env.APPDATA) env['APPDATA'] = global
|
||||
const env = { XDG_DATA_HOME: global }
|
||||
|
||||
const result = execPnpmSync(['root', '-g'], { env })
|
||||
|
||||
expect(result.status).toBe(0)
|
||||
|
||||
if (isWindows()) {
|
||||
expect(result.stdout.toString()).toBe(path.join(global, `pnpm-global/${LAYOUT_VERSION}/node_modules`) + '\n')
|
||||
} else {
|
||||
expect(result.stdout.toString()).toBe(path.join(global, `pnpm-global/${LAYOUT_VERSION}/node_modules`) + '\n')
|
||||
}
|
||||
expect(result.stdout.toString()).toBe(path.join(global, `pnpm/global-packages/${LAYOUT_VERSION}/node_modules`) + '\n')
|
||||
})
|
||||
|
||||
2
pnpm-lock.yaml
generated
2
pnpm-lock.yaml
generated
@@ -350,7 +350,6 @@ importers:
|
||||
'@types/which': ^2.0.0
|
||||
'@zkochan/npm-conf': 2.0.2
|
||||
camelcase: ^6.2.0
|
||||
can-write-to-dir: ^1.1.1
|
||||
is-subdir: ^1.1.1
|
||||
normalize-registry-url: 2.0.0
|
||||
ramda: ^0.27.1
|
||||
@@ -366,7 +365,6 @@ importers:
|
||||
'@pnpm/types': link:../types
|
||||
'@zkochan/npm-conf': 2.0.2
|
||||
camelcase: 6.3.0
|
||||
can-write-to-dir: 1.1.1
|
||||
is-subdir: 1.2.0
|
||||
normalize-registry-url: 2.0.0
|
||||
ramda: 0.27.2
|
||||
|
||||
Reference in New Issue
Block a user