Skip to content

Commit

Permalink
Refactored path resolution into getExports + added 'resolve.root' set…
Browse files Browse the repository at this point in the history
…ting. (closes #18)
  • Loading branch information
benmosher committed Mar 31, 2015
1 parent 3570266 commit d63890f
Show file tree
Hide file tree
Showing 12 changed files with 86 additions and 94 deletions.
37 changes: 20 additions & 17 deletions lib/getExports.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,30 @@ var
Set = require("es6-set"),
traverse = require("estraverse").traverse,
parse = require("./parse"),
resolve = require("./resolve");
resolve = require("./resolve"),
isCore = require("resolve").isCore;

var exportCache = new Map();

function ExportMap() {
function ExportMap(context) {
this.context = context;

this.hasDefault = false;
this.named = new Set();

this.isCommon = false;
this.errors = [];
}

ExportMap.get = function (path) {
ExportMap.get = function (source, context) {

var path = resolve(source, context);
if (path == null) return null;

var exportMap = exportCache.get(path);
if (exportMap != null) return exportMap;

exportMap = ExportMap.parse(path);
exportMap = ExportMap.parse(path, context);

exportCache.set(path, exportMap);

Expand All @@ -32,8 +38,14 @@ ExportMap.get = function (path) {
return exportMap;
};

ExportMap.parse = function (path) {
var m = new ExportMap();
ExportMap.parse = function (path, context) {
var m = new ExportMap(context);

if (isCore(path)) {
// skip parsing, mark as common
m.isCommon = true;
return m;
}

try {
var ast = parse(path);
Expand All @@ -59,19 +71,10 @@ ExportMap.prototype.captureDefault = function (n) {
this.hasDefault = true;
};

ExportMap.prototype.captureAll = function (n, path) {
ExportMap.prototype.captureAll = function (n) {
if (n.type !== "ExportAllDeclaration") return;

try {
var deepPath = resolve(n.source.value, path);
} catch (err) {
this.errors.push(err);
return;
}

if (deepPath == null) return;

var remoteMap = ExportMap.get(deepPath);
var remoteMap = ExportMap.get(n.source.value, this.context);
remoteMap.named.forEach(function (name) { this.named.add(name); }.bind(this));
};

Expand Down
24 changes: 15 additions & 9 deletions lib/resolve.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,26 @@ var
/**
* resolve
* @param {[type]} file [description]
* @param {[type]} path [description]
* @param {[type]} extensions [description]
* @return {[type]} [description]
* @param {[type]} p - path
* @return {[type]} - the full module filesystem path
*/
module.exports = function (p, file) {
module.exports = function (p, context) {
var
paths = [],
resolveRoot = context.settings["resolve.root"];


if (resolveRoot != null) paths = paths.concat(resolveRoot);

try {
return resolve.sync(p, {
basedir: path.dirname(file)
basedir: path.dirname(context.getFilename()),
paths: paths
});
} catch (err) {
if (err.message.indexOf("Cannot find module") === 0) {
if (err.message.indexOf("Cannot find module") === 0)
return null;
} else {
throw err;
}

throw err;
}
};
23 changes: 7 additions & 16 deletions lib/rules/default.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,23 @@
"use strict";

var
resolve = require("../resolve"),
getExports = require("../getExports");
var getExports = require("../getExports");

require("array.prototype.find");

module.exports = function (context) {
return {
"ImportDeclaration": function (node) {
var path = resolve(node.source.value, context.getFilename());
if (path == null) {
return;
}

var defaultSpecifier = node.specifiers.find(function (n) { return n.type === "ImportDefaultSpecifier"; });
if (!defaultSpecifier) {
return;
}
if (!defaultSpecifier) return;

var imports = getExports(node.source.value, context);
if (imports == null) return;

var imports = getExports(path);
if (imports.named.size === 0 && context.options[0] !== "es6-only") {
if (imports.named.size === 0 && context.options[0] !== "es6-only")
return; // ignore for commonjs compatibility
}

if (!imports.hasDefault) {
if (!imports.hasDefault)
context.report(defaultSpecifier, "No default export found in module.");
}
}
};
};
28 changes: 11 additions & 17 deletions lib/rules/named.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,28 @@
"use strict";

var
resolve = require("../resolve"),
getExports = require("../getExports");
var getExports = require("../getExports");

module.exports = function (context) {
return {
"ImportDeclaration": function (node) {
var path = resolve(node.source.value, context.getFilename());
if (path == null) {
return;
}
if (!node.specifiers.some(function (im) { return im.type === "ImportSpecifier"; }))
return; // no named imports

var imports = getExports(node.source.value, context);
if (imports == null) return;

var
imports = getExports(path),
names = imports.named;
var names = imports.named;

// if there are no exports, may be a commonjs module.
// TODO: "interop" mode that attempts to read module.exports, exports member assignments?
if (names.size === 0 && !imports.hasDefault && context.options[0] !== "es6-only") {
if (names.size === 0 && !imports.hasDefault && context.options[0] !== "es6-only")
return;
}

node.specifiers.forEach(function (im) {
if (im.type !== "ImportSpecifier") {
return;
}
if (!names.has(im.imported.name)){
if (im.type !== "ImportSpecifier") return;

if (!names.has(im.imported.name))
context.report(im.imported, im.imported.name + " not found in '" + node.source.value + "'");
}
});
}
};
Expand Down
13 changes: 5 additions & 8 deletions lib/rules/namespace.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

var
Map = require("es6-map"),
resolve = require("../resolve"),
getExports = require("../getExports");

function importDeclaration(context) {
Expand All @@ -19,14 +18,12 @@ module.exports = function (context) {

var declaration = importDeclaration(context);

var path = resolve(declaration.source.value, context.getFilename());
if (path == null) return;
var imports = getExports(declaration.source.value, context);
if (imports == null || imports.isCommon) return;

var imports = getExports(path);
if (imports.isCommon) return;

if (imports.named.size === 0) context.report(namespace,
"No exported names found in module '" + declaration.source.value + "'.");
if (imports.named.size === 0)
context.report(namespace,
"No exported names found in module '" + declaration.source.value + "'.");

namespaces.set(namespace.local.name, imports.named);
},
Expand Down
16 changes: 6 additions & 10 deletions lib/rules/no-common.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
"use strict";

var
resolve = require("../resolve"),
getExports = require("../getExports");
var getExports = require("../getExports");

module.exports = function (context) {
return {
"ImportDeclaration": function (node) {
var path = resolve(node.source.value, context.getFilename());
if (path == null) { return; }

var imports = getExports(path);
if (imports.isCommon) {
context.report(node.source, "'" + node.source.value + "' is a CommonJS module.");
}
var imports = getExports(node.source.value, context);
if (imports == null) return;

if (imports.isCommon)
context.report(node.source, "'" + node.source.value + "' is a CommonJS module.");
}
}
};
};
9 changes: 3 additions & 6 deletions lib/rules/no-errors.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
"use strict";

var
resolve = require("../resolve"),
getExports = require("../getExports");
var getExports = require("../getExports");

module.exports = function (context) {
function message(node, errors) {
Expand All @@ -16,10 +14,9 @@ module.exports = function (context) {

return {
"ImportDeclaration": function (node) {
var path = resolve(node.source.value, context.getFilename());
if (path == null) return;
var imports = getExports(node.source.value, context);
if (imports == null) return;

var imports = getExports(path);
if (imports.errors.length > 0)
context.report(node.source, message(node, imports.errors));
}
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/no-unresolved.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ var resolve = require("../resolve");
module.exports = function (context) {
return {
"ImportDeclaration": function (node) {
if (resolve(node.source.value, context.getFilename()) == null)
if (resolve(node.source.value, context) == null)
context.report(node.source,
"Unable to resolve path to module '" + node.source.value + "'.");
}
Expand Down
1 change: 1 addition & 0 deletions tests/files/alternate-root/in-alternate-root.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const DEEP = "RISING";
5 changes: 4 additions & 1 deletion tests/lib/rules/no-common.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ eslintTester.addRuleTest("lib/rules/no-common", {
errors: [{ message: "'./nested-common' is a CommonJS module."}]}),

test({code: "import {x} from './umd';",
errors: [{ message: "'./umd' is a CommonJS module."}]})
errors: [{ message: "'./umd' is a CommonJS module."}]}),

test({code: "import fs from 'fs';",
errors: [{ message: "'fs' is a CommonJS module.", type: "Literal"}]})
]
});
7 changes: 0 additions & 7 deletions tests/lib/rules/no-errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,6 @@ eslintTester.addRuleTest("lib/rules/no-errors", {
],

invalid: [
test({code: "import fs from 'fs';",
errors: [{
message: "Errors encountered while analysing imported module 'fs'.",
type: "Literal"}]}),
test({code: "import fs from 'fs';",
args: [1, "include-messages"],
errors: [{type: "Literal"}]}),
test({code: "import { a } from './test.coffee';",
errors: [{
message: "Errors encountered while analysing imported module './test.coffee'.",
Expand Down
15 changes: 13 additions & 2 deletions tests/lib/rules/no-unresolved.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"use strict";

var path = require("path");

var test = require("../../utils").test;

var linter = require("eslint").linter,
Expand All @@ -16,7 +18,11 @@ eslintTester.addRuleTest("lib/rules/no-unresolved", {
test({
code: "import {someThing} from './module';"}),
test({
code: "import fs from 'fs';"})
code: "import fs from 'fs';"}),

test({
code: "import { DEEP } from 'in-alternate-root';",
settings: {"resolve.root": path.join(process.cwd(), "tests", "files", "alternate-root")}})
],

invalid: [
Expand All @@ -25,6 +31,11 @@ eslintTester.addRuleTest("lib/rules/no-unresolved", {
errors: [{message: "Unable to resolve path to module './baz'.", type: "Literal"}]}),
test({
code: "import bar from './empty-folder';",
errors: [{message: "Unable to resolve path to module './empty-folder'.", type: "Literal"}]})
errors: [{message: "Unable to resolve path to module './empty-folder'.", type: "Literal"}]}),

// sanity check that this module is _not_ found without proper settings
test({
code: "import { DEEP } from 'in-alternate-root';",
errors: [{message: "Unable to resolve path to module 'in-alternate-root'.", type: "Literal"}]})
]
});

0 comments on commit d63890f

Please sign in to comment.