Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion lib/shameimaru.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"use strict";

const { CancellationError } = require("bluebird");
const fs = require("fs");
const path = require("path");

Expand All @@ -11,14 +12,32 @@ class Shameimaru {
this.projDir = projDir;
this.nodeModuleDir = path.resolve(process.cwd(), projDir, "node_modules");
this.package = JSON.parse(fs.readFileSync(path.join(projDir, "package.json"), "utf8"));
this.traversePromise = null;
}

async traverse() {
const ret = await traverse(
this.traversePromise = traverse(
utils.extraDependenciesFromPackage(this.package),
this.nodeModuleDir);

const ret = await new Promise((resolve, reject) => {
this.traversePromise.then(resolve, reject).finally(() => {
// onFulfilled & onFailure won't be called if the promise was cancelled, so we need to handle cancellation mannually
if (this.traversePromise.isCancelled()) {
reject(new CancellationError());
}
});
});
return ret;
}

cancel() {
if (!this.traversePromise) {
return;
}

this.traversePromise.cancel();
}
}

module.exports = Shameimaru;
22 changes: 19 additions & 3 deletions lib/traverse.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ const fs = require("mz/fs");
const Linklist = require("algorithmjs").ds.Linklist;
const npa = require("npm-package-arg");
const uuid = require("uuid/v4");
const Bluebird = require("bluebird");

Bluebird.config({ cancellation: true });

const utils = require("./utils");

Expand Down Expand Up @@ -192,7 +195,7 @@ async function scanDir(q, node, ancestors, refs) {
}
}

async function traverse(rootDependencies, rootDir) {
function traverse(rootDependencies, rootDir) {
const q = new Linklist();
const rootTree = {};
const ancestors = {};
Expand All @@ -205,12 +208,25 @@ async function traverse(rootDependencies, rootDir) {
dummyFolder: "/"
});

while(q.length) {
let isCanceled = false;
const run = async () => {
// when cancelled or the queue is empty, stop and return
if (isCanceled || !q.length) {
return rootTree;
}

const node = q.popFront();
await scanDir(q, node, ancestors, refs);
return run();
}

return rootTree;
return new Bluebird((resolve, reject, onCancel) => {
onCancel(() => {
isCanceled = true;
});

run().then(resolve, reject);
}) ;
}

module.exports = traverse;
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"description": "Shameimaru Aya likes to traverse node_modules and capture the tree",
"dependencies": {
"algorithmjs": "^1.0.0",
"bluebird": "^3.7.2",
"mz": "^2.7.0",
"npm-package-arg": "^6.1.0",
"uuid": "^3.2.1"
Expand Down
12 changes: 12 additions & 0 deletions test/app1.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

require("should");

const { CancellationError } = require("bluebird");
const Shameimaru = require("../");
const utils = require("./utils");

Expand All @@ -20,6 +21,17 @@ describe("app1.test.js", () => {

// require("fs").writeFileSync("./test/fixtures/apps/app1/target.npm.json", JSON.stringify(tree, 0, 2));
});

it("#traverse canncel", async function() {
const shameimaru = new Shameimaru("./test/fixtures/apps/app1");
console.time("app1#npm");
const promise = shameimaru.traverse();
setTimeout(() => {
shameimaru.cancel();
}, 0);
console.timeEnd("app1#npm");
promise.should.rejectedWith(CancellationError);
})
});

describe("cnpm 6", () => {
Expand Down