@vue-storefront/eslint-config
Version:
> Common ESLint configuration used in Alokai projects. These configurations are compatible with ESLint 9.
125 lines (109 loc) • 3.32 kB
JavaScript
import path from "node:path";
export const ERROR_MESSAGE = "import/export statements should have an absolute path";
/**
* A custom version of {@link https://www.npmjs.com/package/eslint-plugin-no-relative-import-paths | eslint-plugin-no-relative-import-paths}.
*
* @description
* We needed to modify the original plugin to force aliased imports and
* exports and auto-fix them. The original plugin only forces and fixes
* imports and leaves exports untouched.
*/
export default {
rules: {
"no-relative-import-paths": {
create: function (context) {
return {
ExportAllDeclaration: (node) => {
handleNode(context, node);
},
ExportNamedDeclaration: (node) => {
handleNode(context, node);
},
ImportDeclaration: (node) => {
handleNode(context, node);
},
};
},
meta: {
fixable: "code",
schema: {
items: [
{
additionalProperties: false,
properties: {
allowedDepth: { type: "number" },
allowSameFolder: { type: "boolean" },
prefix: { type: "string" },
rootDir: { type: "string" },
},
type: "object",
},
],
maxItems: 1,
minItems: 0,
type: "array",
},
type: "layout",
},
},
},
};
function handleNode(context, node) {
const pathValue = node.source?.value;
if (!pathValue) return;
const { allowedDepth, allowSameFolder, prefix, rootDir } = {
allowedDepth: context.options[0]?.allowedDepth,
allowSameFolder: context.options[0]?.allowSameFolder || false,
prefix: context.options[0]?.prefix || "",
rootDir: context.options[0]?.rootDir || "",
};
const range = [node.source.range[0] + 1, node.source.range[1] - 1];
function report() {
context.report({
fix: function (fixer) {
return fixer.replaceTextRange(range, getAbsolutePath(pathValue, context, rootDir, prefix));
},
message: ERROR_MESSAGE,
node,
});
}
if (
isParentFolder(pathValue, context, rootDir) &&
(typeof allowedDepth === "undefined" || getRelativePathDepth(pathValue) > allowedDepth)
) {
report();
}
if (isSameFolder(pathValue) && !allowSameFolder) {
report();
}
}
function isParentFolder(relativeFilePath, context, rootDir) {
const absoluteRootPath = path.join(context.getCwd(), rootDir);
const absoluteFilePath = path.join(path.dirname(context.getFilename()), relativeFilePath);
return (
relativeFilePath.startsWith("../") &&
(rootDir === "" ||
(absoluteFilePath.startsWith(absoluteRootPath) && context.getFilename().startsWith(absoluteRootPath)))
);
}
function isSameFolder(path) {
return path.startsWith("./");
}
function getRelativePathDepth(path) {
let depth = 0;
while (path.startsWith("../")) {
depth += 1;
path = path.slice(3);
}
return depth;
}
function getAbsolutePath(relativePath, context, rootDir, prefix) {
return [
prefix,
...path
.relative(path.join(context.getCwd(), rootDir), path.join(path.dirname(context.getFilename()), relativePath))
.split(path.sep),
]
.filter(Boolean)
.join("/");
}