@aquaori/deplens
Version:
A precise dependency analysis tool for npm and pnpm projects
115 lines • 4.71 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseNpmLockfile = parseNpmLockfile;
const fs_1 = __importDefault(require("fs"));
const compare_versions_1 = require("compare-versions");
/**
* 解析 npm lockfile
* @param manifestPath lockfile 路径
* @returns 依赖列表和检查计数
*/
function parseNpmLockfile(manifestPath, ignoreList) {
// 读取并解析 lockfile
const rootManifest = JSON.parse(fs_1.default.readFileSync(manifestPath, 'utf-8'));
// 获取不同类型的依赖
const rootProd = rootManifest["packages"][""].dependencies || {};
const rootPeer = rootManifest["packages"][""].peerDependencies || {};
const rootOpt = rootManifest["packages"][""].optionalDependencies || {};
const rootDev = rootManifest["packages"][""].devDependencies || {};
delete rootManifest["packages"][""];
const depSource = rootManifest["packages"];
// 收集被其他包使用的依赖
const usedByOthers = new Map();
let checkCount = 0;
for (const [key, pkg] of Object.entries(depSource)) {
if (key === '' || !pkg || typeof pkg !== 'object')
continue;
const p = pkg;
[
p.dependencies || {},
p.peerDependencies || {},
p.optionalDependencies || {}
].forEach(obj => {
Object.entries(obj).forEach(([depName, depRange]) => {
if (typeof depRange !== 'string')
return;
const ver = depRange.replace(/\(.+?\)+/g, '');
if (!usedByOthers.has(depName))
usedByOthers.set(depName, new Set());
usedByOthers.get(depName).add(ver);
checkCount++;
});
});
}
// 构建锁文件中的依赖包列表
const lockFilePkg = [];
const rootDeclared = new Map();
Object.entries({ ...rootProd, ...rootPeer, ...rootOpt, ...rootDev })
.forEach(([name, ver]) => rootDeclared.set(name, ver));
for (const [name, version] of rootDeclared) {
if (ignoreList.includes(name))
continue;
const pureVersion = version.replace(/[\^\*\~\=\>\<]/g, '');
let usedVersions = usedByOthers.get(name);
let usedVersionsList = new Set();
for (let ver of usedVersions || []) {
const verList = ver ? ver.split(" || ") : [];
for (let ver of verList) {
const verName = ver;
if (verName != "")
usedVersionsList.add(verName);
}
}
let isUsed = false;
for (let ver of usedVersionsList) {
if (ver == "*") {
isUsed = true;
break;
}
if ((0, compare_versions_1.satisfies)(pureVersion, ver)) {
isUsed = true;
break;
}
}
if (!isUsed) {
let preciseVersion = "0";
if (typeof version == "string")
preciseVersion = version.replace(/\(.+?\)+/g, '');
else if (typeof version == "object")
preciseVersion = version.version.replace(/\(.+?\)+/g, '');
const previousPkgIndex = lockFilePkg.findIndex(dep => dep.name == name);
const previousPkg = previousPkgIndex >= 0 ? lockFilePkg[previousPkgIndex] : null;
let previousVersion = previousPkg?.version ?? [];
if (previousPkg !== null && previousVersion !== "") {
if (previousVersion.length != 0 && !previousPkg?.usage)
previousVersion = [...previousVersion, preciseVersion];
else
previousVersion = [preciseVersion];
}
else {
previousVersion = [preciseVersion];
}
;
if (previousVersion.length != 1)
previousVersion = [previousVersion.join(" & @")];
if (previousPkgIndex >= 0 && previousPkg !== null) {
lockFilePkg[previousPkgIndex].version = previousVersion;
}
else
lockFilePkg.push({
name,
type: '',
version: previousVersion,
usage: isUsed,
isDev: Object.prototype.hasOwnProperty.call(rootDev, name)
});
}
}
// 按名称排序
lockFilePkg.sort((a, b) => a.name.localeCompare(b.name));
return { dependencies: lockFilePkg, checkCount };
}
//# sourceMappingURL=npm.js.map