UNPKG

@hyrious/dup

Version:

Find duplicates in your lockfile

164 lines (162 loc) 4.89 kB
// src/jsonc.ts var regexp = /("[^"\\]*(?:\\.[^"\\]*)*")|('[^'\\]*(?:\\.[^'\\]*)*')|(\/\*[^\/\*]*(?:(?:\*|\/)[^\/\*]*)*?\*\/)|(\/{2,}.*?(?:(?:\r?\n)|$))|(,\s*[}\]])/g; function stripComments(content) { return content.replace(regexp, function(match, _m1, _m2, m3, m4, m5) { if (m3) { return ""; } else if (m4) { const length = m4.length; if (m4[length - 1] === "\n") { return m4[length - 2] === "\r" ? "\r\n" : "\n"; } else { return ""; } } else if (m5) { return match.substring(1); } else { return match; } }); } function parse(content) { const commentsStripped = stripComments(content); try { return JSON.parse(commentsStripped); } catch (error) { const trailingCommasStriped = commentsStripped.replace(/,\s*([}\]])/g, "$1"); return JSON.parse(trailingCommasStriped); } } // src/dup.ts function dup(lockfile) { if (typeof lockfile === "object" && lockfile !== null) { return dup_object(lockfile); } if (typeof lockfile === "string") { return dup_string(lockfile); } throw new Error( `expect string or object, got ${lockfile && typeof lockfile}` ); } function dup_object(a) { return dup_packages(a.lockfileVersion ? a.packages : a); } function dup_value_is_array(p) { for (const key in p) { if (Array.isArray(p[key])) return true; return false; } return false; } function dup_packages(p) { const isNPM = !!p[""]; const isBun = dup_value_is_array(p); const collected = []; for (const key in p) { let pkg; let ver; if (isNPM && key) { const parts = key.split("/").slice(-2); if (parts[0][0] === "@") { pkg = parts.join("/"); } else { pkg = parts.pop(); } ver = p[key].version; if (ver == null) continue; collected.push([pkg, ver]); } else if (isBun && key) { const parts = key.split("/").slice(-2); if (parts[0][0] === "@") { pkg = parts.join("/"); } else { pkg = parts.pop(); } const line = p[key][0]; const i = line.indexOf("@", 1); collected.push([pkg, line.slice(i + 1)]); } else if (key) { let line = key; if (line[0] === '"' || line[0] === "'") line = line.slice(1); if (line[0] === "/") line = line.slice(1); const i = line.indexOf("@", 1); pkg = line.slice(0, i); line = line.slice(i + 1); const match = line.match(/['",(:]/); ver = match ? line.slice(0, match.index) : line; const another = p[line].version; if (another) ver = another; collected.push([pkg, ver]); } } return dup_collected(collected); } function dup_string(a) { if (a[0] === "{") return dup_object(parse(a)); const collected = []; if (a.startsWith("lockfileVersion")) { const lines = a.split(/\r\n|\n/g); let working = false; for (let index = 0; index < lines.length; ++index) { let line = lines[index]; if (line) { if (line[0] !== " ") working = line.startsWith("packages:"); else if (working && line[2] && line[2] !== " ") { line = line.slice(2); if (line[0] === '"' || line[0] === "'") line = line.slice(1); if (line[0] === "/") line = line.slice(1); const i = line.indexOf("@", 1); const pkg = line.slice(0, i); line = line.slice(i + 1); const match = line.match(/['",(:]/); const ver = match ? line.slice(0, match.index) : line; collected.push([pkg, ver]); } } } } else if (a.includes("yarn lockfile") || a.includes("__metadata")) { const lines = a.split(/\r\n|\n/g); for (let index = 0; index < lines.length; ++index) { const line = lines[index]; if (line.length && line[0] !== " ") { const quoted = line[0] === '"'; const i = line.indexOf("@", quoted ? 2 : 1); const pkg = line.slice(quoted ? 1 : 0, i); let ver; const version = lines[index + 1]; if (version.startsWith(" version")) { if (version[9] === " ") { ver = version.slice(10); } else if (version[9] === ":") { ver = version.slice(11); } if (ver && ver[0] === '"') ver = ver.slice(1, -1); if (ver) collected.push([pkg, ver]); } } } } return dup_collected(collected); } function dup_collected(collected) { const map = /* @__PURE__ */ new Map(); for (const [name, version] of collected) { if (map.has(name)) { map.get(name).add(version); } else { map.set(name, /* @__PURE__ */ new Set([version])); } } const result = /* @__PURE__ */ Object.create(null); for (const name of map.keys()) { const versions = map.get(name); if (versions.size > 1) { result[name] = Array.from(versions); } } return result; } export { dup };