Permalink
Browse files

add allow-same-level option

  • Loading branch information...
RyoNkmr committed Dec 11, 2018
1 parent 1381c55 commit 0448dfd285bbe186eb055f5f9d2e8379466490b8
@@ -1,26 +1,41 @@
const OPTION_IDENTIFIERS = {
allowSameLevels: '=',
};

const levelStringRegex = new RegExp(
`([${Object.keys(OPTION_IDENTIFIERS)
.map(key => OPTION_IDENTIFIERS[key])
.join('')}]*)(.+)`
);

const parseLevelOptionFromString = levelString => {
const [, optionsString, level] = levelStringRegex.exec(levelString);
const options = Object.keys(OPTION_IDENTIFIERS).reduce(
(options, option) => ({
...options,
[option]: optionsString.includes(OPTION_IDENTIFIERS[option]),
}),
{}
);
return {
level,
options,
};
};

const toRelative = (() => {
const root = process.cwd();
return absolutePath => require('path').relative(root, absolutePath);
})();

const createDefaultLevelFinder = levels => pathString =>
levels
.reduce(
(flatten, stringOrArray) =>
typeof stringOrArray === 'string'
? [...flatten, stringOrArray]
: [...flatten, ...stringOrArray],
[]
)
.reduce(
(accumulator, _level) => {
const lastIndex = pathString.lastIndexOf(_level);
return lastIndex >= accumulator[1]
? [_level, lastIndex]
: accumulator;
},
[null, 0]
)[0];
const createDefaultLevelFinder = levelMap => pathString =>
Object.keys(levelMap).reduce(
(accumulator, _level) => {
const lastIndex = pathString.lastIndexOf(_level);
return lastIndex >= accumulator[1] ? [_level, lastIndex] : accumulator;
},
[null, 0]
)[0];

const createLevelMatcher = patterns => {
const levelParsers = patterns.map(pattern => new RegExp(pattern, 'i'));
@@ -36,24 +51,36 @@ const createLevelMatcher = patterns => {
};
};

const createLevelMap = levels =>
levels.reduce((map, level, index) => {
return typeof level === 'string'
? { ...map, [level]: index }
: level.reduce(
(levelMap, levelItem) => ({
...levelMap,
[levelItem]: index,
}),
const createLevelMap = (() => {
const mergeMap = (map, levelString, priority) => {
const { level, options } = parseLevelOptionFromString(levelString);
return { ...map, [level]: { priority, ...options } };
};

return levels =>
levels.reduce((map, level, priority) => {
if (typeof level === 'string') {
return mergeMap(map, level, priority);
}
if (Array.isArray(level)) {
return level.reduce(
(levelMap, levelItem) => mergeMap(levelMap, levelItem, priority),
map
);
}, {});
}
return map;
}, {});
})();

const filterAllowedLevels = (level, map) =>
Object.keys(map).filter(_level => map[level] > map[_level]);
const filterAllowedLevels = (baseLevel, map) => {
const base = map[baseLevel];
const criterion = Number(!base.allowSameLevels);
return Object.keys(map).filter(
level => base.priority - map[level].priority >= criterion
);
};

const createTips = (currentLevel, levelMap, importOrRequire) => {
const allowedLevels = filterAllowedLevels(currentLevel, levelMap);
const createTips = (allowedLevels, importOrRequire) => {
const length = allowedLevels.length;
if (length === 0) {
return `cannot ${importOrRequire} any other components`;
@@ -72,4 +99,5 @@ module.exports = {
createLevelMap,
createLevelMatcher,
createDefaultLevelFinder,
filterAllowedLevels,
};
@@ -14,6 +14,7 @@ const {
createLevelMatcher,
createDefaultLevelFinder,
toRelative,
filterAllowedLevels,
} = require('../helpers');

const {
@@ -25,7 +26,7 @@ const {
const DEFAULT_LEVELS = [
'atoms',
'molecules',
'organisms',
'=organisms',
'templates',
'pages',
];
@@ -93,13 +94,14 @@ module.exports = {
const findLevel =
options.pathPatterns && options.pathPatterns.length > 0
? createLevelMatcher(options.pathPatterns)
: createDefaultLevelFinder(levels);
: createDefaultLevelFinder(levelMap);

const currentLevel = findLevel(currentPath);

if (currentLevel === null) {
return {};
}
const allowedLevels = filterAllowedLevels(currentLevel, levelMap);

const validate = (sourcePath, node, importOrRequire) => {
if (!sourcePath) {
@@ -120,12 +122,12 @@ module.exports = {
if (
importLevel === null ||
!Object.prototype.hasOwnProperty.call(levelMap, importLevel) ||
levelMap[importLevel] < levelMap[currentLevel]
allowedLevels.includes(importLevel)
) {
return;
}

const tips = createTips(currentLevel, levelMap, importOrRequire);
const tips = createTips(allowedLevels, importOrRequire);

context.report({
node,
@@ -111,6 +111,9 @@ ruleTester.run('hierarchical-import', rule, {
],
}
),

// the same level
...spec('components/organisms/Component.js', './AnotherComponent'),
],

invalid: [

0 comments on commit 0448dfd

Please sign in to comment.