eslint-plugin-fsd-lint
Version:
ESLint plugin for enforcing Feature-Sliced Design (FSD) architecture
178 lines (158 loc) • 4.33 kB
JavaScript
/**
* @fileoverview Configuration management utility functions
*/
// Default configuration
export const defaultConfig = {
// Default alias setting - no slash format as default
alias: {
value: "@",
withSlash: false, // Default to @shared format
},
// Default root path
rootPath: "/src/",
// Optional tsconfig/jsconfig path for filesystem-based import resolution.
// When omitted, rules search upward from the linted file.
tsconfigPath: null,
// Layer definitions and priorities
layers: {
app: {
pattern: "app",
priority: 1,
allowedToImport: [
"processes",
"pages",
"widgets",
"features",
"entities",
"shared",
],
},
processes: {
pattern: "processes",
priority: 2,
allowedToImport: ["pages", "widgets", "features", "entities", "shared"],
},
pages: {
pattern: "pages",
priority: 3,
allowedToImport: ["widgets", "features", "entities", "shared"],
},
widgets: {
pattern: "widgets",
priority: 4,
allowedToImport: ["features", "entities", "shared"],
},
features: {
pattern: "features",
priority: 5,
allowedToImport: ["entities", "shared"],
},
entities: { pattern: "entities", priority: 6, allowedToImport: ["shared"] },
shared: { pattern: "shared", priority: 7, allowedToImport: [] },
},
// Folder naming pattern settings
folderPattern: {
enabled: false,
regex: "^(\\d+_)?(.*)", // Support for number_ prefix
extractionGroup: 2, // Regex group number to extract the actual layer name
},
// Test files settings
testFilesPatterns: [
"**/*.test.*",
"**/*.spec.*",
"**/*.stories.*",
"**/StoreDecorator.tsx",
],
// Public API settings
publicApi: {
enforceForLayers: ["features", "entities", "widgets"],
fileNames: ["index.ts", "index.tsx", "index.js", "index.jsx"],
allowSegmentImports: true,
enforceShared: false,
},
// Exception handling settings
ignoreImportPatterns: [],
// Relative path settings
relativePath: {
enforceWithinSlice: true,
allowBetweenSlices: false,
},
};
/**
* Deep merge user config with default config
* @param {Object} userConfig - User provided configuration
* @return {Object} - Merged final configuration
*/
export function mergeConfig(userConfig = {}) {
// Handle alias
let alias;
if (!userConfig.alias) {
alias = defaultConfig.alias;
} else if (typeof userConfig.alias === "string") {
// Convert string alias to object
alias = {
value: userConfig.alias,
withSlash: userConfig.alias.endsWith("/"),
};
} else {
// Merge object alias
alias = {
...defaultConfig.alias,
...userConfig.alias,
};
}
// Merge layers
const layers = { ...defaultConfig.layers };
if (userConfig.layers) {
for (const [key, value] of Object.entries(userConfig.layers)) {
if (layers[key]) {
layers[key] = { ...layers[key], ...value };
} else {
layers[key] = value;
}
}
}
// Merge folder pattern
const folderPattern = {
...defaultConfig.folderPattern,
...(userConfig.folderPattern || {}),
};
// Merge test file patterns
const testFilesPatterns = userConfig.testFilesPatterns
? [...userConfig.testFilesPatterns]
: [...defaultConfig.testFilesPatterns];
// Merge public API settings
const publicApi = {
...defaultConfig.publicApi,
...(userConfig.publicApi || {}),
fileNames: [
...(defaultConfig.publicApi.fileNames || []),
...(userConfig.publicApi?.fileNames || []),
],
};
// Merge ignore patterns
const ignoreImportPatterns = [
...(defaultConfig.ignoreImportPatterns || []),
...(userConfig.ignoreImportPatterns || []),
];
// Merge relative path settings
const relativePath = {
...defaultConfig.relativePath,
...(userConfig.relativePath || {}),
};
// Merge root path
const rootPath = userConfig.rootPath || defaultConfig.rootPath;
const tsconfigPath = userConfig.tsconfigPath || defaultConfig.tsconfigPath;
// Return final configuration
return {
alias,
layers,
rootPath,
tsconfigPath,
folderPattern,
testFilesPatterns,
publicApi,
ignoreImportPatterns,
relativePath,
};
}