@hyrious/dup
Version:
Find duplicates in your lockfile
164 lines (162 loc) • 4.89 kB
JavaScript
// 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
};