eslint-plugin-feature-modules
Advanced tools
Comparing version 1.0.0 to 1.0.1
@@ -0,118 +1,121 @@ | ||
const path = require('path'); | ||
const isRequireFunction = node => { | ||
return ( | ||
node.callee.type === 'Identifier' && | ||
node.callee.name === 'require' && | ||
node.arguments.length === 1 && | ||
node.arguments[0].type === 'Literal' | ||
return ( | ||
node.callee.type === 'Identifier' && | ||
node.callee.name === 'require' && | ||
node.arguments.length === 1 && | ||
node.arguments[0].type === 'Literal' | ||
); | ||
}; | ||
const isDotPath = filePath => { | ||
return filePath.startsWith('.'); | ||
}; | ||
const isDeepNonIndexImport = modulePathParts => { | ||
if (modulePathParts.length <= 2) return false; | ||
const thirdPathPart = modulePathParts[2]; | ||
return thirdPathPart !== 'index' && thirdPathPart !== 'index.js'; | ||
}; | ||
const getRelevantPathParts = filePath => { | ||
return filePath.split(path.sep).filter(part => !part.startsWith('.')); | ||
}; | ||
const getModuleName = (pathParts, moduleFolderName) => { | ||
const moduleFolderNameIndex = pathParts.indexOf(moduleFolderName); | ||
if (moduleFolderNameIndex === -1) return null; | ||
return pathParts[moduleFolderNameIndex + 1]; //get moduleName, one after moduleFolderName | ||
}; | ||
const trimPathsToModuleFolder = (pathParts, moduleFolderName) => { | ||
const moduleFolderNameIndex = pathParts.indexOf(moduleFolderName); | ||
return pathParts.slice(moduleFolderNameIndex); | ||
}; | ||
const lintingRule = function(context) { | ||
const verifyValidImport = (node, requirePath) => { | ||
if (!isDotPath(requirePath)) return; //dont check against node_modules or alias paths | ||
const fileName = context.getFilename(); | ||
const { moduleFolderName } = context.options[0]; | ||
const fullRequirePath = path.resolve(path.parse(fileName).dir, requirePath); | ||
const dependencyPathParts = getRelevantPathParts(fullRequirePath); | ||
const importingModulePathParts = getRelevantPathParts(fileName); | ||
// //are we requiring a file that is in same module? | ||
const dependencyModuleName = getModuleName( | ||
dependencyPathParts, | ||
moduleFolderName | ||
); | ||
const importingModuleName = getModuleName( | ||
importingModulePathParts, | ||
moduleFolderName | ||
); | ||
//if we arent requiring something from module folders | ||
// OR the requiring module is the same as our importing module, bail | ||
if ( | ||
dependencyModuleName == null || | ||
dependencyModuleName === importingModuleName | ||
) { | ||
return; | ||
} | ||
//if not, are we digging more than one level deep? | ||
const modulePathParts = trimPathsToModuleFolder( | ||
dependencyPathParts, | ||
moduleFolderName | ||
); | ||
if (isDeepNonIndexImport(modulePathParts)) { | ||
context.report(node, 'Cannot request module thats too deep!'); | ||
} | ||
}; | ||
const isRelativePath = path => { | ||
return path.startsWith('.'); | ||
}; | ||
const isDeepNonIndexImport = modulePathParts => { | ||
if (modulePathParts.length <= 2) return false; | ||
const thirdPathPart = modulePathParts[2]; | ||
return thirdPathPart !== 'index' && thirdPathPart !== 'index.js'; | ||
}; | ||
const getRelevantPathParts = path => { | ||
return path.split('/').filter(part => !part.startsWith('.')); | ||
}; | ||
const getModuleName = (pathParts, moduleFolderName) => { | ||
const moduleFolderNameIndex = pathParts.indexOf(moduleFolderName); | ||
if (moduleFolderNameIndex === -1) return null; | ||
return pathParts[moduleFolderNameIndex + 1]; //get moduleName, one after moduleFolderName | ||
}; | ||
const trimPathsToModuleFolder = (pathParts, moduleFolderName) => { | ||
const moduleFolderNameIndex = pathParts.indexOf(moduleFolderName); | ||
return pathParts.slice(moduleFolderNameIndex); | ||
}; | ||
const lintingRule = function(context) { | ||
const verifyValidImport = (node, requirePath) => { | ||
if (!isRelativePath(requirePath)) return; //dont check against node_modules or alias paths | ||
const fileName = context.getFilename(); | ||
const { moduleFolderName } = context.options[0]; | ||
const dependencyPathParts = getRelevantPathParts(requirePath); | ||
const importingModulePathParts = getRelevantPathParts(fileName); | ||
// //are we requiring a file that is in same module? | ||
const dependencyModuleName = getModuleName( | ||
dependencyPathParts, | ||
moduleFolderName | ||
); | ||
const importingModuleName = getModuleName( | ||
importingModulePathParts, | ||
moduleFolderName | ||
); | ||
//if we arent requiring something from module folders | ||
// OR the requiring module is the same as our importing module, bail | ||
if ( | ||
dependencyModuleName == null || | ||
dependencyModuleName === importingModuleName | ||
) { | ||
return { | ||
ImportDeclaration(node) { | ||
const importSource = node.source.value; | ||
verifyValidImport(node.source, importSource); | ||
}, | ||
CallExpression(node) { | ||
if (!isRequireFunction(node)) { | ||
return; | ||
} | ||
//if not, are we digging more than one level deep? | ||
const modulePathParts = trimPathsToModuleFolder( | ||
dependencyPathParts, | ||
moduleFolderName | ||
); | ||
if (isDeepNonIndexImport(modulePathParts)) { | ||
context.report(node, 'Cannot request module thats too deep!'); | ||
} | ||
}; | ||
return { | ||
ImportDeclaration(node) { | ||
const importSource = node.source.value; | ||
verifyValidImport(node.source, importSource); | ||
}, | ||
CallExpression(node) { | ||
if (!isRequireFunction(node)) { | ||
return; | ||
} | ||
const fileName = context.getFilename(); | ||
const source = node.arguments[0].value; | ||
verifyValidImport(node.arguments[0], source); | ||
} | ||
}; | ||
const fileName = context.getFilename(); | ||
const source = node.arguments[0].value; | ||
verifyValidImport(node.arguments[0], source); | ||
} | ||
}; | ||
module.exports = { | ||
meta: { | ||
docs: { | ||
description: 'Disallow digging too deep into feature modules', | ||
category: 'best practices' | ||
}, | ||
schema: [ | ||
{ | ||
type: 'object', | ||
properties: { | ||
moduleBasePath: { | ||
type: 'string' | ||
}, | ||
moduleFolderName: { | ||
type: 'string' | ||
} | ||
}; | ||
module.exports = { | ||
meta: { | ||
docs: { | ||
description: 'Disallow digging too deep into feature modules', | ||
category: 'best practices' | ||
}, | ||
schema: [ | ||
{ | ||
type: 'object', | ||
properties: { | ||
moduleBasePath: { | ||
type: 'string' | ||
}, | ||
required: ['moduleFolderName'] | ||
} | ||
] | ||
}, | ||
create: lintingRule | ||
}; | ||
moduleFolderName: { | ||
type: 'string' | ||
} | ||
}, | ||
required: ['moduleFolderName'] | ||
} | ||
] | ||
}, | ||
create: lintingRule | ||
}; |
{ | ||
"name": "eslint-plugin-feature-modules", | ||
"version": "1.0.0", | ||
"version": "1.0.1", | ||
"description": "Plugin for eslint rules that apply to feature modules directory structure", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
const { RuleTester } = require('eslint'); | ||
const rule = require('../../../../lib/rules/no-deep-module-require'); | ||
const path = require('path') | ||
@@ -11,2 +12,6 @@ const config = { | ||
const normalizePath = filePath => { | ||
return path.resolve(filePath) | ||
} | ||
const ruleOptions = [{ moduleFolderName: 'module' }]; | ||
@@ -34,3 +39,3 @@ | ||
code: 'import foo from "./module/story"', | ||
filename: 'src/app', | ||
filename: normalizePath('src/app'), | ||
options: ruleOptions | ||
@@ -40,3 +45,3 @@ }, | ||
code: 'import foo from "../../module/story"', | ||
filename: 'module/party/index.js', | ||
filename: normalizePath('module/party/index.js'), | ||
options: ruleOptions | ||
@@ -46,8 +51,8 @@ }, | ||
code: 'const foo = require("../../module/story")', | ||
filename: 'module/party/index.js', | ||
filename: normalizePath('module/party/index.js'), | ||
options: ruleOptions | ||
}, | ||
{ | ||
code: 'const foo = require("../module/party/foo")', | ||
filename: 'module/party/index.js', | ||
code: 'const foo = require("../../module/party/foo")', | ||
filename: normalizePath('module/party/index.js'), | ||
options: ruleOptions | ||
@@ -57,8 +62,8 @@ }, | ||
code: 'const foo = require("./reducer/test/test.js")', | ||
filename: 'module/party/index.js', | ||
filename: normalizePath('module/party/index.js'), | ||
options: ruleOptions | ||
}, | ||
{ | ||
code: 'const foo = require("../feature/party")', | ||
filename: 'feature/something/index.js', | ||
code: 'const foo = require("../../feature/party")', | ||
filename: normalizePath('feature/something/index.js'), | ||
options: [{ moduleFolderName: 'feature' }] | ||
@@ -68,3 +73,3 @@ }, | ||
code: 'const foo = require("module/this/is/long/but/fine")', | ||
filename: 'module/something', | ||
filename: normalizePath('module/something'), | ||
options: ruleOptions | ||
@@ -74,3 +79,3 @@ }, | ||
code: 'const foo = require("./module")', | ||
filename: 'src', | ||
filename: normalizePath('src'), | ||
options: ruleOptions | ||
@@ -80,3 +85,3 @@ }, | ||
code: 'const foo = require("./module/party/index.js")', | ||
filename: 'src', | ||
filename: normalizePath('src'), | ||
options: ruleOptions | ||
@@ -86,3 +91,3 @@ }, | ||
code: 'const foo = require("./module/party/index")', | ||
filename: 'src', | ||
filename: normalizePath('src'), | ||
options: ruleOptions | ||
@@ -94,3 +99,3 @@ } | ||
code: 'const foo = require("../../module/story/foo")', | ||
filename: 'module/party/index.js', | ||
filename: normalizePath('module/party/index.js'), | ||
options: ruleOptions | ||
@@ -100,3 +105,3 @@ }), | ||
code: 'const reducer = require("./module/story/foo")', | ||
filename: 'src/app', | ||
filename: normalizePath('src/app'), | ||
options: ruleOptions | ||
@@ -106,3 +111,3 @@ }), | ||
code: 'const foo = require("../feature/party/reducer")', | ||
filename: 'feature/something/index.js', | ||
filename: normalizePath('feature/something/index.js'), | ||
options: [{ moduleFolderName: 'feature' }] | ||
@@ -112,6 +117,11 @@ }), | ||
code: 'const foo = require("../feature/party/inde")', | ||
filename: 'feature/something/index.js', | ||
filename: normalizePath('feature/something/index.js'), | ||
options: [{ moduleFolderName: 'feature' }] | ||
}), | ||
invalid({ | ||
code: 'const foo = require("../party/foo")', | ||
filename: normalizePath('src/module/awesome/index.js'), | ||
options: ruleOptions | ||
}) | ||
] | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
99222
211