Skip to content

Commit

Permalink
Fix MODULE_NOT_FOUND error message
Browse files Browse the repository at this point in the history
See #8 

Also:
* Set up tests with Vitest
* Add prettier
  • Loading branch information
JohnDaly authored Jun 12, 2022
1 parent ab109f3 commit ade0863
Show file tree
Hide file tree
Showing 10 changed files with 128 additions and 34 deletions.
3 changes: 3 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"singleQuote": true
}
7 changes: 7 additions & 0 deletions constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Empty extension takes advantage of Node's default require behavior to check for
// eslint-local-rules.js as well as an eslint-local-rules folder with an index.js
var DEFAULT_EXTENSIONS = ['', '.cjs'];

module.exports = {
DEFAULT_EXTENSIONS,
};
3 changes: 3 additions & 0 deletions fixtures/projectWithBadImport/eslint-local-rules.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
require('./does-not-exist');

module.exports = {};
1 change: 1 addition & 0 deletions fixtures/projectWithResolution/eslint-local-rules.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = {};
1 change: 1 addition & 0 deletions fixtures/projectWithResolutionCjs/eslint-local-rules.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = {};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = {};
41 changes: 9 additions & 32 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,46 +1,23 @@
/* eslint-env node */
'use strict';

var path = require('path');
var { requireUp } = require('./requireUp');
var { DEFAULT_EXTENSIONS } = require('./constants');

// Empty extension takes advantage of Node's default require behavior to check for
// eslint-local-rules.js as well as an eslint-local-rules folder with an index.js
var exts = ['', '.cjs'];
var rules = requireUp('eslint-local-rules', __dirname);
var rules = requireUp('eslint-local-rules', DEFAULT_EXTENSIONS, __dirname);

if (!rules) {
throw new Error(
'eslint-plugin-local-rules: ' +
'Cannot find "eslint-local-rules{' + ['.js'].concat(exts.filter(Boolean)) + "} " +
'or eslint-local-rules/index.js (checked all ancestors of "' + __dirname + '").'
'Cannot find "eslint-local-rules{' +
['.js'].concat(exts.filter(Boolean)) +
'} ' +
'or eslint-local-rules/index.js (checked all ancestors of "' +
__dirname +
'").'
);
}

module.exports = {
rules: rules,
};

// Attempt to require a file, recursively checking parent directories until found
// Similar to native `require` behavior, but doesn't check in `node_modules` folders
// Based on https://github.com/js-cli/node-findup-sync
function requireUp(filename, cwd) {
var filepath = path.resolve(cwd, filename);

for (var i = 0; i < exts.length; i++) {
try {
return require(filepath + exts[i]);
} catch(error) {
// Ignore OS errors (will recurse to parent directory)
if (error.code !== 'MODULE_NOT_FOUND') {
throw error;
}
}
}

var dir = path.dirname(cwd);
if (dir === cwd) {
return undefined;
}

return requireUp(filename, dir);
}
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"description": "A plugin for ESLint that allows you to use project-specific rules",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"test": "vitest"
},
"repository": {
"type": "git",
Expand All @@ -19,5 +19,9 @@
"bugs": {
"url": "https://github.com/cletusw/eslint-plugin-local-rules/issues"
},
"homepage": "https://github.com/cletusw/eslint-plugin-local-rules#readme"
"homepage": "https://github.com/cletusw/eslint-plugin-local-rules#readme",
"devDependencies": {
"prettier": "2.6.2",
"vitest": "^0.14.2"
}
}
38 changes: 38 additions & 0 deletions requireUp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
var path = require('path');

/**
* Attempt to require a file, recursively checking parent directories until found.
* Similar to native `require` behavior, but doesn't check in `node_modules` folders.
* Based on https://github.com/js-cli/node-findup-sync.
*
* @param filename {string} The name of the target file
* @param exts {string[]} The file extensions to look for (e.g. '.cjs')
* @param cwd {string} The directory to search in
*/
function requireUp(filename, exts, cwd) {
for (var i = 0; i < exts.length; i++) {
var filepath = path.resolve(cwd, filename) + exts[i];
try {
return require(filepath);
} catch (error) {
var filepathNotFound =
error.code === 'MODULE_NOT_FOUND' &&
error.message.includes(`Cannot find module '${filepath}'`);

// Rethrow unless error is just saying `filepath` not found (in that case,
// let next loop check parent directory instead).
if (!filepathNotFound) {
throw error;
}
}
}
var dir = path.dirname(cwd);
if (dir === cwd) {
return undefined;
}
return requireUp(filename, exts, dir);
}

module.exports = {
requireUp,
};
59 changes: 59 additions & 0 deletions requireUp.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { describe, it, expect } from 'vitest';

import { requireUp } from './requireUp';
import { DEFAULT_EXTENSIONS } from './constants';

const __dirname = path.dirname(fileURLToPath(import.meta.url));

// Path to the 'fixtures' directory
const fixturesDir = path.resolve(__dirname, './fixtures');

describe('requireUp', () => {
it('should find the file at eslint-local-rules.js', () => {
const file = requireUp(
'eslint-local-rules',
DEFAULT_EXTENSIONS,
path.join(fixturesDir, './projectWithResolution/a')
);
expect(file).toBeDefined();
});

it('should find the file at eslint-local-rules.cjs', () => {
const file = requireUp(
'eslint-local-rules',
DEFAULT_EXTENSIONS,
path.join(fixturesDir, './projectWithResolutionCjs/a')
);
expect(file).toBeDefined();
});

it('should find the file at eslint-local-rules/index.js', () => {
const file = requireUp(
'eslint-local-rules',
DEFAULT_EXTENSIONS,
path.join(fixturesDir, './projectWithResolutionIndex/a')
);
expect(file).toBeDefined();
});

it('should fail to find a file that does not exist', () => {
const file = requireUp(
'some-file-that-will-not-resolve',
DEFAULT_EXTENSIONS,
path.join(fixturesDir, './projectWithNoResolution/a')
);
expect(file).not.toBeDefined();
});

it('should throw MODULE_NOT_FOUND errors for modules other than the target', () => {
expect(() => {
requireUp(
'eslint-local-rules',
DEFAULT_EXTENSIONS,
path.join(fixturesDir, './projectWithBadImport/a')
);
}).toThrowError(`Cannot find module './does-not-exist'`);
});
});

0 comments on commit ade0863

Please sign in to comment.