Skip to content

Commit

Permalink
Merge pull request #22 from mysticatea/fix-relative-path-to-dir
Browse files Browse the repository at this point in the history
Fix: `no-missing-*` should work for relative paths to a directory (fixes #21)
  • Loading branch information
mysticatea committed Jan 30, 2016
2 parents 57b05c0 + f603c06 commit 7f8e975
Show file tree
Hide file tree
Showing 8 changed files with 163 additions and 16 deletions.
4 changes: 2 additions & 2 deletions lib/util/exists.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ var fs = require("fs");
//------------------------------------------------------------------------------

/**
* Checks whether or not the file which is at given path exists.
* Checks whether or not the file of a given path exists.
*
* @param {string} filePath - A file path to check.
* @returns {boolean} `true` if the file which is at given path exists.
* @returns {boolean} `true` if the file of a given path exists.
*/
module.exports = function exists(filePath) {
try {
Expand Down
88 changes: 74 additions & 14 deletions lib/util/import-target.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,36 +10,96 @@
// Requirements
//------------------------------------------------------------------------------

var fs = require("fs");
var path = require("path");
var exists = require("./exists");
var getPackageJson = require("./get-package-json");

//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------

/**
* Checks whether or not a given path is a directory.
*
* @param {string} filePath - A file path to check.
* @returns {boolean} `true` if the path is a directory.
*/
function isDirectory(filePath) {
try {
return fs.statSync(filePath).isDirectory();
}
catch (err) {
return false;
}
}

/**
* Resolve a given path as a file with given extensions.
*
* @param {string} filePath - A path to resolve.
* @param {string[]} exts - Extensions that it checks whether or not the file exists.
* @returns {string|null} The resolved path. Or `null` if failed to resolve.
*/
function tryExtentions(filePath, exts) {
for (var i = 0; i < exts.length; ++i) {
var ext = exts[i];
if (exists(filePath + ext)) {
return filePath + ext;
}
}

return null;
}

/**
* Resolve a given path as a file.
*
* @param {string} filePath - A path to resolve.
* @param {string[]} exts - Extensions that it checks whether or not the file exists.
* @returns {string|null} The resolved path. Or `null` if failed to resolve.
*/
function resolveAsFile(filePath, exts) {
if (exists(filePath)) {
return filePath;
}
return tryExtentions(filePath, exts);
}

/**
* Resolve a given path as a directory.
*
* @param {string} filePath - A path to resolve.
* @param {string[]} exts - Extensions that it checks whether or not the file exists.
* @returns {string|null} The resolved path. Or `null` if failed to resolve.
*/
function resolveAsDirectory(filePath, exts) {
if (!isDirectory(filePath)) {
return null;
}

var p = getPackageJson(path.join(filePath, "package.json"));
if (p && path.dirname(p.filePath) === filePath && p.main) {
return resolveAsFile(path.join(filePath, p.main), exts);
}
return tryExtentions(path.join(filePath, "index"), exts);
}

/**
* Resolves the file.
*
* @param {string} basedir - The path of base directory to resolve relative path.
* @param {string} name - The name of an import target.
* @param {string[]} exts - Extensions that it checks whether or not the file exists.
* @returns {string} Resolved path.
* @returns {string} The resolved path.
*/
function resolve(basedir, name, exts) {
var resolvedPath = path.resolve(basedir, name);

// Checks with extensions.
if (!exists(resolvedPath)) {
for (var i = 0; i < exts.length; ++i) {
var ext = exts[i];

if (exists(resolvedPath + ext)) {
return resolvedPath + ext;
}
}
}

return resolvedPath;
return (
resolveAsFile(resolvedPath, exts) ||
resolveAsDirectory(resolvedPath, exts) ||
resolvedPath
);
}

/**
Expand Down
2 changes: 2 additions & 0 deletions tests/fixtures/no-missing/bar/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
"use strict";
console.log("hello!");
2 changes: 2 additions & 0 deletions tests/fixtures/no-missing/foo/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
"use strict";
console.log("hello!");
3 changes: 3 additions & 0 deletions tests/fixtures/no-missing/foo/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"main": "main.js"
}
2 changes: 2 additions & 0 deletions tests/fixtures/no-missing/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
"use strict";
console.log("hello!");
42 changes: 42 additions & 0 deletions tests/lib/rules/no-missing-import.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,32 @@ ruleTester.run("no-missing-import", rule, {
code: "import a from './a';",
ecmaFeatures: {modules: true},
parserOptions: {sourceType: "module"}
},

// Relative paths to a directory should work.
{
filename: fixture("test.js"),
code: "import a from '.';",
ecmaFeatures: {modules: true},
parserOptions: {sourceType: "module"}
},
{
filename: fixture("test.js"),
code: "import a from './';",
ecmaFeatures: {modules: true},
parserOptions: {sourceType: "module"}
},
{
filename: fixture("test.js"),
code: "import a from './foo';",
ecmaFeatures: {modules: true},
parserOptions: {sourceType: "module"}
},
{
filename: fixture("test.js"),
code: "import a from './foo/';",
ecmaFeatures: {modules: true},
parserOptions: {sourceType: "module"}
}
],
invalid: [
Expand Down Expand Up @@ -203,6 +229,22 @@ ruleTester.run("no-missing-import", rule, {
ecmaFeatures: {modules: true},
parserOptions: {sourceType: "module"},
errors: ["\"./c\" is not found."]
},

// Relative paths to a directory should work.
{
filename: fixture("test.js"),
code: "import a from './bar';",
ecmaFeatures: {modules: true},
parserOptions: {sourceType: "module"},
errors: ["\"./bar\" is not found."]
},
{
filename: fixture("test.js"),
code: "import a from './bar/';",
ecmaFeatures: {modules: true},
parserOptions: {sourceType: "module"},
errors: ["\"./bar/\" is not found."]
}
]
});
36 changes: 36 additions & 0 deletions tests/lib/rules/no-missing-require.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,28 @@ ruleTester.run("no-missing-require", rule, {
filename: "tests/fixtures/no-missing/test.js",
code: "require('./a');",
env: {node: true}
},

// Relative paths to a directory should work.
{
filename: fixture("test.js"),
code: "require('.');",
env: {node: true}
},
{
filename: fixture("test.js"),
code: "require('./');",
env: {node: true}
},
{
filename: fixture("test.js"),
code: "require('./foo');",
env: {node: true}
},
{
filename: fixture("test.js"),
code: "require('./foo/');",
env: {node: true}
}
],
invalid: [
Expand Down Expand Up @@ -210,6 +232,20 @@ ruleTester.run("no-missing-require", rule, {
code: "require('./c');",
env: {node: true},
errors: ["\"./c\" is not found."]
},

// Relative paths to a directory should work.
{
filename: fixture("test.js"),
code: "require('./bar');",
env: {node: true},
errors: ["\"./bar\" is not found."]
},
{
filename: fixture("test.js"),
code: "require('./bar/');",
env: {node: true},
errors: ["\"./bar/\" is not found."]
}
]
});

0 comments on commit 7f8e975

Please sign in to comment.