Skip to content

Commit

Permalink
Handle semantically scoped @ modules when finding dupes.
Browse files Browse the repository at this point in the history
  • Loading branch information
samccone committed May 24, 2020
1 parent 6a92d7b commit e97a18f
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 2 deletions.
35 changes: 34 additions & 1 deletion src/resolve/duplicateModules.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
import { findDuplicateModules } from "./duplicateModules";
import {
findDuplicateModules,
splitBySemanticModulePath
} from "./duplicateModules";

it("handles non-scoped packages", () => {
const ret = splitBySemanticModulePath("foo/node_modules/zap/tap");
expect(ret).toEqual(["foo", "node_modules", "zap", "tap"]);
});

it("handles @scoped packages", () => {
const ret = splitBySemanticModulePath("foo/node_modules/@zap/tap");
expect(ret).toEqual(["foo", "node_modules", "@zap/tap"]);
});

it("handles one module", () => {
const ret = findDuplicateModules(["foo/zap/node_modules/tap"]);
Expand All @@ -15,6 +28,26 @@ it("handles multiple modules", () => {
expect(ret.length).toBe(0);
});

it("correctly splits @ scoped modules", () => {
const ret = findDuplicateModules([
"foo/zap/node_modules/@tap/wow",
"foo/zap/node_modules/no/node_modules/@tap/zap"
]);

expect(ret.length).toBe(0);
});

it("correctly find duplicated @ scoped modules", () => {
const ret = findDuplicateModules([
"foo/zap/node_modules/@tap/wow",
"foo/zap/node_modules/no/node_modules/@tap/wow"
]);

expect(ret.length).toBe(1);
expect(ret[0].key).toBe("@tap/wow");
expect(ret[0].value.sort()).toEqual(["<PROJECT ROOT>", "no"]);
});

it("handles duplicate modules", () => {
const ret = findDuplicateModules([
"foo/zap/node_modules/tap",
Expand Down
47 changes: 46 additions & 1 deletion src/resolve/duplicateModules.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,48 @@
/**
* Splits the folder path by semantically scoped package path.
*
* For example
* node_modules/@foo/zap becomes ["node_modules", "@foo/zap"]
*
* vs:
* node_modules/foo/zap becomes ["node_modules", "foo", "zap"]
*
* @param path file path to split
*/
export function splitBySemanticModulePath(path: string): string[] {
let folderSplit = path.split("/");

const ret: string[] = [];
let scopedPackage = "";
let lastNodeModules = false;

for (const p of folderSplit) {
if (p === "node_modules") {
lastNodeModules = true;
ret.push(p);
continue;
}

if (lastNodeModules && p[0] === "@") {
scopedPackage = p;
lastNodeModules = false;
continue;
}

lastNodeModules = false;

if (scopedPackage.length) {
ret.push(`${scopedPackage}/${p}`);
scopedPackage = "";
continue;
}

ret.push(p);
}

return ret;
}

/**
* Given a list of files find duplicate node modules and the dependencies that
* brought them into the project.
Expand All @@ -17,7 +62,7 @@ export function findDuplicateModules(
v => v.indexOf("node_modules") > -1
);
const explodedPaths = containsNodeModules
.map(v => v.split("/"))
.map(v => splitBySemanticModulePath(v))
.map(splitPath => {
return {
nodeModulePreamables: splitPath
Expand Down

0 comments on commit e97a18f

Please sign in to comment.