Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@yarnpkg/pnpify

Package Overview
Dependencies
Maintainers
5
Versions
141
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@yarnpkg/pnpify - npm Package Compare versions

Comparing version 2.0.0-rc.18 to 2.0.0-rc.19

20

lib/buildNodeModulesTree.d.ts

@@ -7,2 +7,12 @@ import { PortablePath, Filename } from '@yarnpkg/fslib';

}
export declare type NodeModulesBaseNode = {
dirList: Set<Filename>;
};
export declare type NodeModulesPackageNode = {
locator: LocatorKey;
target: PortablePath;
linkType: LinkType;
dirList?: undefined;
aliases: string[];
};
/**

@@ -17,11 +27,3 @@ * Node modules tree - a map of every folder within the node_modules, along with their

*/
export declare type NodeModulesTree = Map<PortablePath, {
dirList: Set<Filename>;
} | {
dirList?: undefined;
locator: LocatorKey;
target: PortablePath;
linkType: LinkType;
aliases: string[];
}>;
export declare type NodeModulesTree = Map<PortablePath, NodeModulesBaseNode | NodeModulesPackageNode>;
export interface NodeModulesTreeOptions {

@@ -28,0 +30,0 @@ pnpifyFs?: boolean;

@@ -36,3 +36,3 @@ "use strict";

const packageTree = buildPackageTree(pnp);
const hoistedTree = hoist_1.hoist(packageTree, { check: false });
const hoistedTree = hoist_1.hoist(packageTree);
return populateNodeModulesTree(pnp, hoistedTree, options);

@@ -53,2 +53,10 @@ };

}
for (const val of map.values()) {
// Sort locations by depth first and then alphabetically for determinism
val.locations = val.locations.sort((loc1, loc2) => {
const len1 = loc1.split(fslib_1.ppath.delimiter).length;
const len2 = loc2.split(fslib_1.ppath.delimiter).length;
return len1 !== len2 ? len2 - len1 : loc2.localeCompare(loc1);
});
}
return map;

@@ -66,3 +74,7 @@ };

const topPkg = pnp.getPackageInformation(pnp.topLevel);
if (topPkg === null)
throw new Error(`Assertion failed: Expected the top-level package to have been registered`);
const topLocator = pnp.findPackageLocator(topPkg.packageLocation);
if (topLocator === null)
throw new Error(`Assertion failed: Expected the top-level package to have a physical locator`);
const topLocatorKey = stringifyLocator(topLocator);

@@ -81,15 +93,22 @@ for (const locator of pnpRoots) {

const nodes = new Map();
const addPackageToTree = (pkg, locator, parent) => {
const addPackageToTree = (pkg, locator, parent, parentPkg) => {
const locatorKey = stringifyLocator(locator);
let node = nodes.get(locatorKey);
const isSeen = !!node;
if (locator === topLocator)
if (!isSeen && locatorKey === topLocatorKey) {
node = packageTree;
nodes.set(locatorKey, packageTree);
}
if (!node) {
const { name, reference } = locator;
// TODO: remove this code when `packagePeers` will not contain regular dependencies
const peerNames = new Set();
for (const peerName of pkg.packagePeers)
if (pkg.packageDependencies.get(peerName) === parentPkg.packageDependencies.get(peerName))
peerNames.add(peerName);
node = {
name: name,
reference: reference,
name,
reference,
dependencies: new Set(),
peerNames: pkg.packagePeers,
peerNames,
};

@@ -101,10 +120,12 @@ nodes.set(locatorKey, node);

for (const [name, referencish] of pkg.packageDependencies) {
if (referencish !== null) {
if (referencish !== null && !node.peerNames.has(name)) {
const depLocator = pnp.getLocator(name, referencish);
const pkgLocator = pnp.getLocator(name.replace('$wsroot$', ''), referencish);
const depPkg = pnp.getPackageInformation(pkgLocator);
if (depPkg === null)
throw new Error(`Assertion failed: Expected the package to have been registered`);
// Skip package self-references
if (stringifyLocator(depLocator) !== locatorKey) {
addPackageToTree(depPkg, depLocator, node);
}
if (stringifyLocator(depLocator) === locatorKey)
continue;
addPackageToTree(depPkg, depLocator, node, pkg);
}

@@ -114,3 +135,3 @@ }

};
addPackageToTree(topPkg, topLocator, packageTree);
addPackageToTree(topPkg, topLocator, packageTree, topPkg);
return packageTree;

@@ -133,2 +154,4 @@ };

const info = pnp.getPackageInformation(pkgLocator);
if (info === null)
throw new Error(`Assertion failed: Expected the package to be registered`);
let linkType;

@@ -146,3 +169,5 @@ let target;

else {
const truePath = pnp.resolveVirtual && locator.reference && locator.reference.startsWith('virtual:') ? pnp.resolveVirtual(info.packageLocation) : info.packageLocation;
const truePath = pnp.resolveVirtual && locator.reference && locator.reference.startsWith('virtual:')
? pnp.resolveVirtual(info.packageLocation)
: info.packageLocation;
target = fslib_1.npath.toPortablePath(truePath || info.packageLocation);

@@ -160,3 +185,9 @@ linkType = info.linkType;

const [nameOrScope, name] = locator.name.split('/');
return name ? { scope: fslib_1.toFilename(nameOrScope), name: fslib_1.toFilename(name) } : { scope: null, name: fslib_1.toFilename(nameOrScope) };
return name ? {
scope: fslib_1.toFilename(nameOrScope),
name: fslib_1.toFilename(name),
} : {
scope: null,
name: fslib_1.toFilename(nameOrScope),
};
};

@@ -172,3 +203,5 @@ const seenNodes = new Set();

const { name, scope } = getPackageName(locator);
const packageNameParts = scope ? [scope, name] : [name];
const packageNameParts = scope
? [scope, name]
: [name];
const nodeModulesDirPath = fslib_1.ppath.join(locationPrefix, NODE_MODULES);

@@ -175,0 +208,0 @@ const nodeModulesLocation = fslib_1.ppath.join(nodeModulesDirPath, ...packageNameParts);

@@ -34,7 +34,11 @@ #!/usr/bin/env node

let currProjectRoot = null;
let isCJS = '';
while (nextProjectRoot !== currProjectRoot) {
currProjectRoot = nextProjectRoot;
nextProjectRoot = fslib_1.ppath.dirname(currProjectRoot);
if (fslib_1.xfs.existsSync(fslib_1.ppath.join(currProjectRoot, `.pnp.js`))) {
if (fslib_1.xfs.existsSync(fslib_1.ppath.join(currProjectRoot, `.pnp.js`)))
break;
if (fslib_1.xfs.existsSync(fslib_1.ppath.join(currProjectRoot, `.pnp.cjs`))) {
isCJS = 'c';
break;
}

@@ -44,3 +48,3 @@ }

throw new Error(`This tool can only be used with projects using Yarn Plug'n'Play`);
const pnpPath = fslib_1.ppath.join(currProjectRoot, `.pnp.js`);
const pnpPath = fslib_1.ppath.join(currProjectRoot, `.pnp.${isCJS}js`);
const pnpApi = dynamicRequire_1.dynamicRequire(pnpPath);

@@ -47,0 +51,0 @@ generateSdk_1.generateSdk(pnpApi).catch(error => {

@@ -69,3 +69,3 @@ "use strict";

throw new Error(`Assertion failed: Package ${this.name} isn't a dependency of the top-level`);
const manifest = dynamicRequire_1.dynamicRequire(`${this.name}/package.json`);
const manifest = dynamicRequire_1.dynamicRequire(fslib_1.npath.join(pkgInformation.packageLocation, `package.json`));
await fslib_1.xfs.mkdirpPromise(fslib_1.ppath.dirname(absWrapperPath));

@@ -76,2 +76,3 @@ await fslib_1.xfs.writeFilePromise(absWrapperPath, JSON.stringify({

main: manifest.main,
type: `commonjs`,
}, null, 2));

@@ -109,2 +110,3 @@ }

await wrapper.writeFile(`lib/tsserver.js`);
await wrapper.writeFile(`lib/typescript.js`);
await addVSCodeWorkspaceSettings(pnpApi, {

@@ -111,0 +113,0 @@ [`typescript.tsdk`]: fslib_1.npath.fromPortablePath(fslib_1.ppath.dirname(wrapper.getProjectPathTo(`lib/tsserver.js`))),

@@ -14,3 +14,4 @@ declare type PackageName = string;

declare type HoistOptions = {
check: boolean;
check?: boolean;
debugLevel?: number;
};

@@ -27,3 +28,3 @@ /**

*/
export declare const hoist: (tree: HoisterTree, options?: HoistOptions) => HoisterResult;
export declare const hoist: (tree: HoisterTree, opts?: HoistOptions) => HoisterResult;
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const makeLocator = (name, reference) => `${name}@${reference}`;
const makePhysicalLocator = (name, reference) => {
const makeIdent = (name, reference) => {
const hashIdx = reference.indexOf('#');

@@ -20,47 +20,49 @@ // Strip virtual reference part, we don't need it for hoisting purposes

*/
exports.hoist = (tree, options = { check: false }) => {
exports.hoist = (tree, opts = {}) => {
const debugLevel = opts.debugLevel || Number(process.env.NM_DEBUG_LEVEL || -1);
const check = opts.check || debugLevel >= 9;
const options = { check, debugLevel };
if (options.debugLevel >= 0)
console.time('hoist');
const treeCopy = cloneTree(tree);
const ancestorMap = buildAncestorMap(treeCopy);
hoistTo(treeCopy, treeCopy, ancestorMap, options);
hoistTo(treeCopy, treeCopy, new Set([treeCopy.locator]), new Map(), ancestorMap, options);
if (options.debugLevel >= 0)
console.timeEnd('hoist');
if (options.debugLevel >= 3) {
const identList = Array.from(ancestorMap.keys());
identList.sort((key1, key2) => ancestorMap.get(key2).size - ancestorMap.get(key1).size);
console.log('Package popularity:');
for (const ident of identList) {
console.log(ident, '→', ancestorMap.get(ident).size);
}
}
if (options.debugLevel >= 1) {
const checkLog = selfCheck(treeCopy);
if (checkLog) {
throw new Error(`${checkLog}, after hoisting finished:\n${dumpDepTree(treeCopy)}`);
}
}
if (options.debugLevel >= 2)
console.log(dumpDepTree(treeCopy));
return shrinkTree(treeCopy);
};
const selfCheck = (tree) => {
let log = [];
const getHoistedDependencies = (rootNode) => {
const hoistedDependencies = new Map();
const seenNodes = new Set();
const checkNode = (node, parentDeps, parents) => {
const addHoistedDependencies = (node) => {
if (seenNodes.has(node))
return;
seenNodes.add(node);
if (parents.has(node))
return;
const dependencies = new Map(parentDeps);
for (const dep of node.dependencies.values())
if (!node.peerNames.has(dep.name))
dependencies.set(dep.name, dep);
for (const origDep of node.originalDependencies.values()) {
const dep = dependencies.get(origDep.name);
if (node.peerNames.has(origDep.name)) {
const parentDep = parentDeps.get(origDep.name);
if (parentDep !== dep) {
log.push(`${Array.from(parents).concat([node]).map(x => x.locator).join('#')} - broken peer promise: expected ${dep.locator} but found ${parentDep ? parentDep.locator : parentDep}`);
}
}
else {
if (!dep) {
log.push(`${Array.from(parents).concat([node]).map(x => x.locator).join('#')} - broken require promise: no required dependency ${origDep.locator} found`);
}
else if (dep.physicalLocator !== origDep.physicalLocator) {
log.push(`${Array.from(parents).concat([node]).map(x => x.locator).join('#')} - broken require promise: expected ${origDep.physicalLocator}, but found: ${dep.physicalLocator}`);
}
}
}
const nextParents = new Set(parents).add(node);
for (const dep of node.hoistedDependencies.values())
if (!rootNode.dependencies.has(dep.name))
hoistedDependencies.set(dep.name, dep);
for (const dep of node.dependencies.values()) {
if (!node.peerNames.has(dep.name)) {
checkNode(dep, dependencies, nextParents);
addHoistedDependencies(dep);
}
}
};
checkNode(tree, tree.dependencies, new Set());
return log.join('\n');
addHoistedDependencies(rootNode);
return hoistedDependencies;
};

@@ -78,8 +80,8 @@ /**

* The regular and peer dependency promises are kept while performing transform
* on triples of packages at a time:
* `root package` -> `parent package` -> `dependency`
* on tree branches of packages at a time:
* `root package` -> `parent package 1` ... `parent package n` -> `dependency`
* We check wether we can hoist `dependency` to `root package`, this boils down basically
* to checking:
* 1. Wether `root package` does not depend on other version of `dependency`
* 2. Wether all the peer dependencies of a `dependency` had already been hoisted from `parent package`
* 2. Wether all the peer dependencies of a `dependency` had already been hoisted from all `parent packages`
*

@@ -89,181 +91,279 @@ * If many versions of the `dependency` can be hoisted to the `root package` we choose the most used

*
* This algorithm is shallow first, e.g. it transforms the tree:
* . -> A -> B -> C
* in this order:
* 1) . -> A
* -> B -> C
* 2) . -> A
* -> B
* -> C
*
* This function mutates the tree.
*
* @param tree package dependencies graph
* @param rootNode root node to hoist to
* @param rootNodePath root node path in the tree
* @param parentAncestorDependencies commulative dependencies of all root node ancestors, excluding root node dependenciew
* @param ancestorMap ancestor map
* @param options hoisting options
*/
const hoistTo = (tree, rootNode, ancestorMap, options, seenNodes = new Set()) => {
const hoistTo = (tree, rootNode, rootNodePath, parentAncestorDependencies, ancestorMap, options, seenNodes = new Set()) => {
if (seenNodes.has(rootNode))
return 0;
seenNodes.add(rootNode);
// Perform shallow-first hoisting by hoisting to the root node first
let totalHoisted = hoistPass(tree, rootNode, ancestorMap, options);
let childrenHoisted = 0;
// Now perform children hoisting
const ancestorDependencies = new Map(parentAncestorDependencies);
for (const dep of rootNode.dependencies.values())
childrenHoisted += hoistTo(tree, dep, ancestorMap, options, seenNodes);
if (childrenHoisted > 0)
// Perfrom 2nd pass of hoisting to the root node, because some of the children were hoisted
hoistPass(tree, rootNode, ancestorMap, options);
return totalHoisted + childrenHoisted;
};
const hoistPass = (tree, rootNode, ancestorMap, options) => {
let totalHoisted = 0;
let packagesToHoist;
const clonedParents = new Map();
if (!rootNode.peerNames.has(dep.name))
ancestorDependencies.set(dep.name, dep);
const hoistedDependencies = rootNode === tree ? new Map() : getHoistedDependencies(rootNode);
let clonedTree = { clone: rootNode, children: new Map() };
let hoistCandidates;
do {
packagesToHoist = getHoistablePackages(rootNode, ancestorMap);
totalHoisted += packagesToHoist.size;
for (const { parent, node } of packagesToHoist) {
let parentNode = clonedParents.get(parent);
if (!parentNode) {
const { name, references, physicalLocator, locator, dependencies, originalDependencies, hoistedDependencies, peerNames } = parent;
// To perform node hoisting from parent node we must clone parent node first,
// because some other package in the tree might depend on the parent package where hoisting
// cannot be performed
parentNode = {
name,
references: new Set(references),
physicalLocator,
locator,
dependencies: new Map(dependencies),
originalDependencies: new Map(originalDependencies),
hoistedDependencies: new Map(hoistedDependencies),
peerNames: new Set(peerNames),
};
clonedParents.set(parent, parentNode);
rootNode.dependencies.set(parentNode.name, parentNode);
}
// Delete hoisted node from parent node
parentNode.dependencies.delete(node.name);
parentNode.hoistedDependencies.set(node.name, node);
const hoistedNode = rootNode.dependencies.get(node.name);
// Add hoisted node to root node, in case it is not already there
if (!hoistedNode) {
// Avoid adding node to itself
if (node.physicalLocator !== rootNode.physicalLocator) {
rootNode.dependencies.set(node.name, node);
hoistCandidates = getHoistCandidates(rootNode, rootNodePath, ancestorDependencies, hoistedDependencies, ancestorMap, options);
for (const hoistSet of hoistCandidates) {
for (const { nodePath, node } of hoistSet.candidates) {
let parentClonedNode = clonedTree;
for (const originalNode of nodePath) {
let nodeClone = parentClonedNode.children.get(originalNode);
if (!nodeClone) {
const { name, references, ident, locator, dependencies, originalDependencies, hoistedDependencies, peerNames, reasons } = originalNode;
// To perform node hoisting from parent node we must clone parent nodes up to the root node,
// because some other package in the tree might depend on the parent package where hoisting
// cannot be performed
const clone = {
name,
references: new Set(references),
ident,
locator,
dependencies: new Map(dependencies),
originalDependencies: new Map(originalDependencies),
hoistedDependencies: new Map(hoistedDependencies),
peerNames: new Set(peerNames),
reasons: new Map(reasons),
};
nodeClone = { clone, children: new Map() };
const selfDep = clone.dependencies.get(name);
if (selfDep && selfDep.ident == clone.ident)
// Update self-reference
clone.dependencies.set(name, clone);
parentClonedNode.children.set(originalNode, nodeClone);
parentClonedNode.clone.dependencies.set(name, clone);
}
parentClonedNode = nodeClone;
}
}
else {
for (const reference of node.references) {
hoistedNode.references.add(reference);
parentClonedNode.clone.dependencies.delete(node.name);
parentClonedNode.clone.hoistedDependencies.set(node.name, node);
parentClonedNode.clone.reasons.delete(node.name);
const hoistedNode = rootNode.dependencies.get(node.name);
// Add hoisted node to root node, in case it is not already there
if (!hoistedNode) {
// Avoid adding other version of root node to itself
if (rootNode.ident !== node.ident) {
rootNode.dependencies.set(node.name, node);
ancestorDependencies.set(node.name, node);
}
}
}
if (options.check) {
const checkLog = selfCheck(tree);
if (checkLog) {
throw new Error(`After hoisting ${rootNode.locator}#${parent.physicalLocator}#${node.physicalLocator}:\n${require('util').inspect(node, { depth: null })}\n${checkLog}`);
else {
for (const reference of node.references) {
hoistedNode.references.add(reference);
}
}
if (options.check) {
const checkLog = selfCheck(tree);
if (checkLog) {
throw new Error(`${checkLog}, after hoisting ${[rootNode, ...nodePath, node].map(x => prettyPrintLocator(x.locator)).join('→')}:\n${dumpDepTree(tree)}`);
}
}
}
}
} while (packagesToHoist.size > 0);
return totalHoisted;
} while (hoistCandidates.size > 0);
for (const dependency of rootNode.dependencies.values()) {
if (!rootNode.peerNames.has(dependency.name) && !rootNodePath.has(dependency.locator)) {
rootNodePath.add(dependency.locator);
hoistTo(tree, dependency, rootNodePath, ancestorDependencies, ancestorMap, options);
rootNodePath.delete(dependency.locator);
}
}
};
/**
* Finds all the packages that can be hoisted to the root package node from the set of:
* `root node` -> `dependency` -> `subdependency`
* `root node` -> ... `parent dependency j` ... -> `dependency` -> `subdependency`
*
* @param rootNode root package node
* @param rootNodePath root node path in the tree
* @param ancestorDependencies commulative dependencies of all root node ancestors, including root node dependencies
* @param ancestorMap ancestor map to determine `dependency` version popularity
*/
const getHoistablePackages = (rootNode, ancestorMap) => {
const getHoistCandidates = (rootNode, rootNodePath, ancestorDependencies, hoistedDependencies, ancestorMap, options) => {
const hoistCandidates = new Map();
const computeHoistCandidates = (parentNode, node) => {
const parents = [];
const seenNodes = new Set();
const computeHoistCandidates = (nodePath, locatorPath, node) => {
const isSeen = seenNodes.has(node);
let reasonRoot;
let reason;
if (options.debugLevel >= 2)
reasonRoot = `${Array.from(rootNodePath).map(x => prettyPrintLocator(x)).join('→')}`;
let isHoistable = true;
let competitorInfo = hoistCandidates.get(node.name);
const ancestorNode = ancestorMap.get(node.physicalLocator);
const weight = ancestorNode.size;
if (isHoistable) {
const isCompatiblePhysicalLocator = (rootNode.name !== node.name || rootNode.physicalLocator === node.physicalLocator);
isHoistable = isCompatiblePhysicalLocator;
const isRegularDepAtRoot = !rootNode.peerNames.has(node.name);
if (options.debugLevel >= 2 && !isRegularDepAtRoot)
reason = `- is a peer dependency at ${reasonRoot}`;
isHoistable = isRegularDepAtRoot;
}
let competitorInfo;
let weight;
let rootDep;
if (isHoistable) {
const rootDep = rootNode.dependencies.get(node.name);
const origRootDep = rootNode.originalDependencies.get(node.name);
const hoistedRootDep = rootNode.hoistedDependencies.get(node.name);
const isNameAvailable = (!hoistedRootDep || hoistedRootDep.physicalLocator === node.physicalLocator)
&& (!rootDep || rootDep.physicalLocator === node.physicalLocator)
&& (!origRootDep || origRootDep.physicalLocator === node.physicalLocator);
isHoistable = isNameAvailable;
const isCompatibleIdent = (rootNode.name !== node.name || rootNode.ident === node.ident);
if (options.debugLevel >= 2 && !isCompatibleIdent)
reason = `- conflicts with ${reasonRoot}`;
isHoistable = isCompatibleIdent;
}
if (isHoistable) {
const isRegularDepAtRoot = !rootNode.peerNames.has(node.name);
isHoistable = isRegularDepAtRoot;
let isNameAvailable = false;
const hoistedDep = hoistedDependencies.get(node.name);
isNameAvailable = (!hoistedDep || hoistedDep.ident === node.ident);
if (options.debugLevel >= 2 && !isNameAvailable)
reason = `- filled by: ${prettyPrintLocator(hoistedDep.locator)} at ${reasonRoot}`;
if (isNameAvailable) {
for (const tuple of parents) {
const parentDep = tuple.parent.dependencies.get(node.name);
if (parentDep && parentDep.ident !== node.ident) {
isNameAvailable = false;
if (options.debugLevel >= 2)
reason = `- filled by: ${prettyPrintLocator(parentDep.locator)} at ${prettyPrintLocator(tuple.parent.locator)}`;
break;
}
}
}
isHoistable = isNameAvailable;
}
let isPreferred = false;
if (isHoistable) {
competitorInfo = hoistCandidates.get(node.name);
weight = ancestorMap.get(node.ident).size;
// If there is a competitor package to be hoisted, we should prefer the package with more usage
isPreferred = !competitorInfo || competitorInfo.weight < weight;
const isPreferred = !competitorInfo || competitorInfo.weight <= weight;
if (options.debugLevel >= 2 && !isPreferred)
reason = `- preferred package ${competitorInfo.node.locator} at ${reasonRoot}`;
isHoistable = isPreferred;
}
if (isHoistable) {
if (isHoistable && !rootDep) {
let areRegularDepsSatisfied = true;
// Check that hoisted dependencies of current node are satisifed
for (const dep of node.hoistedDependencies.values()) {
if (node.originalDependencies.has(dep.name)) {
const rootDepNode = rootNode.dependencies.get(dep.name) || rootNode.hoistedDependencies.get(dep.name);
if (!rootDepNode || rootDepNode.physicalLocator !== dep.physicalLocator) {
isHoistable = false;
const depNode = ancestorDependencies.get(dep.name);
if (!depNode) {
if (options.debugLevel >= 2)
reason = `- hoisted dependency ${prettyPrintLocator(dep.locator)} is absent at ${reasonRoot}`;
areRegularDepsSatisfied = false;
}
else if (depNode.ident !== dep.ident) {
if (options.debugLevel >= 2)
reason = `- hoisted dependency ${prettyPrintLocator(dep.locator)} has a clash with ${prettyPrintLocator(depNode.locator)} at ${reasonRoot}`;
areRegularDepsSatisfied = false;
}
}
if (!isHoistable) {
if (!areRegularDepsSatisfied) {
break;
}
}
// Check that hoisted dependencies of unhoisted children are still satisifed
if (isHoistable) {
const checkChildren = (node) => {
for (const dep of node.dependencies.values()) {
if (node.originalDependencies.has(dep.name) && !node.peerNames.has(dep.name)) {
for (const subDep of dep.hoistedDependencies.values()) {
const rootDepNode = rootNode.dependencies.get(subDep.name) || rootNode.hoistedDependencies.get(subDep.name);
if (!rootDepNode || rootDepNode.physicalLocator !== subDep.physicalLocator || !checkChildren(dep)) {
return false;
}
}
}
}
return true;
};
isHoistable = checkChildren(node);
}
isHoistable = areRegularDepsSatisfied;
}
if (isHoistable) {
for (const name of node.peerNames) {
const parentDepNode = parentNode.dependencies.get(name);
if (parentDepNode) {
isHoistable = false;
let arePeerDepsSatisfied = true;
const checkList = new Set(node.peerNames);
for (let idx = parents.length - 1; idx >= 0; idx--) {
const parent = parents[idx].node;
for (const name of checkList) {
if (parent.peerNames.has(name))
continue;
const parentDepNode = parent.dependencies.get(name);
if (parentDepNode) {
if (options.debugLevel >= 2)
reason = `- peer dependency ${prettyPrintLocator(parentDepNode.locator)} from parent ${prettyPrintLocator(parent.locator)} was not hoisted to ${reasonRoot}`;
arePeerDepsSatisfied = false;
break;
}
checkList.delete(name);
}
if (!arePeerDepsSatisfied) {
break;
}
}
isHoistable = arePeerDepsSatisfied;
}
if (isHoistable) {
let hoistCandidate = hoistCandidates.get(node.name);
if (!hoistCandidate || (competitorInfo && competitorInfo.physicalLocator !== node.physicalLocator)) {
hoistCandidate = { physicalLocator: node.physicalLocator, tuples: new Set(), weight };
if (!hoistCandidate || (competitorInfo && competitorInfo.node.ident !== node.ident)) {
hoistCandidate = { node, candidates: new Set(), weight: weight };
hoistCandidates.set(node.name, hoistCandidate);
}
hoistCandidate.tuples.add({ parent: parentNode, node });
hoistCandidate.candidates.add({ nodePath, node });
}
else if (options.debugLevel >= 2) {
const parent = parents[parents.length - 1].node;
const prevReason = parent.reasons.get(node.name);
if (!prevReason || prevReason.root === rootNode) {
parent.reasons.set(node.name, { reason: reason, root: rootNode });
}
}
if (!isSeen && locatorPath.indexOf(node.locator) < 0) {
seenNodes.add(node);
const parent = parents[parents.length - 1].node;
const tuple = { parent, node };
parents.push(tuple);
for (const dep of node.dependencies.values())
if (!node.peerNames.has(dep.name))
computeHoistCandidates([...nodePath, node], [...locatorPath, node.locator], dep);
parents.pop();
}
};
for (const dep of rootNode.dependencies.values()) {
for (const subDep of dep.dependencies.values()) {
computeHoistCandidates(dep, subDep);
}
if (rootNode.peerNames.has(dep.name) || dep.locator === rootNode.locator)
continue;
const tuple = { parent: rootNode, node: dep };
parents.push(tuple);
for (const subDep of dep.dependencies.values())
if (!dep.peerNames.has(subDep.name) && subDep.locator !== dep.locator)
computeHoistCandidates([dep], [rootNode.locator, dep.locator], subDep);
parents.pop();
}
const candidates = new Set();
for (const { tuples } of hoistCandidates.values())
for (const tuple of tuples)
candidates.add(tuple);
return candidates;
return new Set(hoistCandidates.values());
};
const selfCheck = (tree) => {
let log = [];
const seenNodes = new Set();
const parents = new Set();
const checkNode = (node, parentDeps) => {
if (seenNodes.has(node))
return;
seenNodes.add(node);
if (parents.has(node))
return;
const dependencies = new Map(parentDeps);
for (const dep of node.dependencies.values())
if (!node.peerNames.has(dep.name))
dependencies.set(dep.name, dep);
for (const origDep of node.originalDependencies.values()) {
const dep = dependencies.get(origDep.name);
const prettyPrintTreePath = () => `${Array.from(parents).concat([node]).map(x => prettyPrintLocator(x.locator)).join('→')}`;
if (node.peerNames.has(origDep.name)) {
const parentDep = parentDeps.get(origDep.name);
if (parentDep !== dep) {
log.push(`${prettyPrintTreePath()} - broken peer promise: expected ${dep.locator} but found ${parentDep ? parentDep.locator : parentDep}`);
}
}
else {
if (!dep) {
log.push(`${prettyPrintTreePath()} - broken require promise: no required dependency ${origDep.locator} found`);
}
else if (dep.ident !== origDep.ident) {
log.push(`${prettyPrintTreePath()} - broken require promise: expected ${origDep.ident}, but found: ${dep.ident}`);
}
}
}
parents.add(node);
for (const dep of node.dependencies.values()) {
if (!node.peerNames.has(dep.name)) {
checkNode(dep, dependencies);
}
}
parents.delete(node);
};
checkNode(tree, tree.dependencies);
return log.join('\n');
};
/**

@@ -280,3 +380,3 @@ * Creates a clone of package tree with extra fields used for hoisting purposes.

locator: makeLocator(name, reference),
physicalLocator: makePhysicalLocator(name, reference),
ident: makeIdent(name, reference),
dependencies: new Map(),

@@ -286,8 +386,7 @@ originalDependencies: new Map(),

peerNames: new Set(peerNames),
reasons: new Map(),
};
const seenNodes = new Map([[tree, treeCopy]]);
const addNode = (origParent, node, parentNode) => {
const addNode = (node, parentNode) => {
// Skip self-references
if (node === origParent)
return;
let workNode = seenNodes.get(node);

@@ -301,3 +400,3 @@ const isSeen = !!workNode;

locator: makeLocator(name, reference),
physicalLocator: makePhysicalLocator(name, reference),
ident: makeIdent(name, reference),
dependencies: new Map(),

@@ -307,2 +406,3 @@ originalDependencies: new Map(),

peerNames: new Set(peerNames),
reasons: new Map(),
};

@@ -315,3 +415,3 @@ seenNodes.set(node, workNode);

for (const dep of node.dependencies) {
addNode(node, dep, workNode);
addNode(dep, workNode);
}

@@ -321,3 +421,3 @@ }

for (const dep of tree.dependencies)
addNode(tree, dep, treeCopy);
addNode(dep, treeCopy);
return treeCopy;

@@ -336,5 +436,5 @@ };

};
const nodes = new Map([[tree, treeCopy]]);
const nodes = new Map([[tree.locator, treeCopy]]);
const addNode = (node, parentNode) => {
let resultNode = nodes.get(node);
let resultNode = nodes.get(node.locator);
const isSeen = !!resultNode;

@@ -349,2 +449,3 @@ if (!resultNode) {

if (!isSeen) {
nodes.set(node.locator, resultNode);
for (const dep of node.dependencies.values()) {

@@ -371,16 +472,17 @@ if (!node.peerNames.has(dep.name)) {

const ancestorMap = new Map();
const seenNodes = new Set();
const addParent = (parentNodes, node) => {
const isSeen = seenNodes.has(node);
seenNodes.add(node);
let parents = ancestorMap.get(node.physicalLocator);
const seenNodes = new Set([tree]);
const addParent = (parentNode, node) => {
const isSeen = !!seenNodes.has(node);
let parents = ancestorMap.get(node.ident);
if (!parents) {
parents = new Set();
ancestorMap.set(node.physicalLocator, parents);
ancestorMap.set(node.ident, parents);
}
for (const parent of parentNodes)
parents.add(parent.physicalLocator);
parents.add(parentNode.ident);
if (!isSeen) {
seenNodes.add(node);
for (const dep of node.dependencies.values()) {
addParent(new Set(parentNodes).add(node), dep);
if (!node.peerNames.has(dep.name)) {
addParent(node, dep);
}
}

@@ -390,4 +492,59 @@ }

for (const dep of tree.dependencies.values())
addParent(new Set([tree]), dep);
if (!tree.peerNames.has(dep.name))
addParent(tree, dep);
return ancestorMap;
};
const prettyPrintLocator = (locator) => {
const idx = locator.indexOf('@', 1);
const name = locator.substring(0, idx);
const reference = locator.substring(idx + 1);
if (reference === 'workspace:.') {
return `.`;
}
else if (!reference) {
return `${name}`;
}
else {
const version = (reference.indexOf('#') > 0 ? reference.split('#')[1] : reference).replace('npm:', '');
if (reference.startsWith('virtual')) {
return `v:${name}@${version}`;
}
else {
return `${name}@${version}`;
}
}
};
const MAX_NODES_TO_DUMP = 50000;
/**
* Pretty-prints dependency tree in the `yarn why`-like format
*
* The function is used for troubleshooting purposes only.
*
* @param pkg node_modules tree
*
* @returns sorted node_modules tree
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const dumpDepTree = (tree) => {
let nodeCount = 0;
const dumpPackage = (pkg, parents, prefix = '') => {
if (nodeCount > MAX_NODES_TO_DUMP || parents.has(pkg))
return '';
nodeCount++;
const dependencies = Array.from(pkg.dependencies.values());
let str = '';
parents.add(pkg);
for (let idx = 0; idx < dependencies.length; idx++) {
const dep = dependencies[idx];
if (!pkg.peerNames.has(dep.name)) {
const reasonObj = pkg.reasons.get(dep.name);
str += `${prefix}${idx < dependencies.length - 1 ? '├─' : '└─'}${(parents.has(dep) ? '>' : '') + prettyPrintLocator(dep.locator) + (reasonObj ? ` ${reasonObj.reason}` : '')}\n`;
str += dumpPackage(dep, parents, `${prefix}${idx < dependencies.length - 1 ? '│ ' : ' '}`);
}
}
parents.delete(pkg);
return str;
};
const treeDump = dumpPackage(tree, new Set());
return treeDump + ((nodeCount > MAX_NODES_TO_DUMP) ? '\nTree is too large, part of the tree has been dunped\n' : '');
};

@@ -5,2 +5,3 @@ import { NodeModulesFS } from './NodeModulesFS';

export declare const patchFs: () => void;
export { NodeModulesBaseNode, NodeModulesPackageNode, } from './buildNodeModulesTree';
export { NodeModulesFS, buildNodeModulesTree, buildLocatorMap, NodeModulesLocatorMap, getArchivePath, };
{
"name": "@yarnpkg/pnpify",
"version": "2.0.0-rc.18",
"version": "2.0.0-rc.19",
"main": "./lib/index.js",

@@ -9,3 +9,3 @@ "bin": "./lib/cli.js",

"dependencies": {
"@yarnpkg/fslib": "^2.0.0-rc.16",
"@yarnpkg/fslib": "^2.0.0-rc.17",
"chalk": "^3.0.0",

@@ -20,4 +20,4 @@ "comment-json": "^2.2.0",

"@yarnpkg/monorepo": "0.0.0",
"@yarnpkg/pnp": "^2.0.0-rc.17",
"eslint": "^5.16.0",
"@yarnpkg/pnp": "^2.0.0-rc.18",
"eslint": "^6.8.0",
"typescript": "^3.7.5"

@@ -24,0 +24,0 @@ },

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc