@nx/eslint
Version:
183 lines (182 loc) • 8.36 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.convertEslintJsonToFlatConfig = convertEslintJsonToFlatConfig;
const devkit_1 = require("@nx/devkit");
const ts = require("typescript");
const ast_utils_1 = require("../../utils/flat-config/ast-utils");
const eslint_file_1 = require("../../utils/eslint-file");
const path_utils_1 = require("../../utils/flat-config/path-utils");
/**
* Converts an ESLint JSON config to a flat config.
* Deletes the original file along with .eslintignore if it exists.
*/
function convertEslintJsonToFlatConfig(tree, root, config, ignorePaths, format) {
const importsMap = new Map();
const exportElements = [];
let isFlatCompatNeeded = false;
let isESLintJSNeeded = false;
let combinedConfig = [];
let languageOptions = [];
// exclude dist and eslint config from being linted, which matches the default for new workspaces
exportElements.push((0, ast_utils_1.generateAst)({
ignores: ['**/dist'],
}));
if (config.extends) {
const extendsResult = addExtends(importsMap, exportElements, config, format);
isFlatCompatNeeded = extendsResult.isFlatCompatNeeded;
isESLintJSNeeded = extendsResult.isESLintJSNeeded;
}
if (config.plugins) {
addPlugins(importsMap, exportElements, config);
}
if (config.parser) {
const imp = config.parser;
const parserName = (0, devkit_1.names)(imp).propertyName;
importsMap.set(imp, parserName);
languageOptions.push(ts.factory.createPropertyAssignment('parser', ts.factory.createIdentifier(parserName)));
}
if (config.parserOptions) {
languageOptions.push(ts.factory.createPropertyAssignment('parserOptions', (0, ast_utils_1.generateAst)(config.parserOptions)));
}
if (config.globals || config.env) {
if (config.env) {
importsMap.set('globals', 'globals');
}
languageOptions.push(ts.factory.createPropertyAssignment('globals', ts.factory.createObjectLiteralExpression([
...Object.keys(config.env || {}).map((env) => ts.factory.createSpreadAssignment(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('globals'), ts.factory.createIdentifier(env)))),
...Object.keys(config.globals || {}).map((key) => ts.factory.createPropertyAssignment(key, (0, ast_utils_1.generateAst)(config.globals[key]))),
])));
}
if (config.settings) {
combinedConfig.push(ts.factory.createPropertyAssignment('settings', (0, ast_utils_1.generateAst)(config.settings)));
}
if (config.noInlineConfig !== undefined ||
config.reportUnusedDisableDirectives !== undefined) {
combinedConfig.push(ts.factory.createPropertyAssignment('linterOptions', (0, ast_utils_1.generateAst)({
noInlineConfig: config.noInlineConfig,
reportUnusedDisableDirectives: config.reportUnusedDisableDirectives,
})));
}
if (languageOptions.length > 0) {
combinedConfig.push(ts.factory.createPropertyAssignment('languageOptions', ts.factory.createObjectLiteralExpression(languageOptions, languageOptions.length > 1)));
}
if (combinedConfig.length > 0) {
exportElements.push(ts.factory.createObjectLiteralExpression(combinedConfig, combinedConfig.length > 1));
}
if (config.rules) {
exportElements.push((0, ast_utils_1.generateAst)({ rules: config.rules }));
}
if (config.overrides) {
config.overrides.forEach((override) => {
if (override.env ||
override.extends ||
override.plugins ||
override.parser) {
isFlatCompatNeeded = true;
}
exportElements.push((0, ast_utils_1.generateFlatOverride)(override, format));
});
}
if (config.ignorePatterns) {
const patterns = (Array.isArray(config.ignorePatterns)
? config.ignorePatterns
: [config.ignorePatterns]).filter((pattern) => !['**/*', '!**/*', 'node_modules'].includes(pattern)); // these are useless in a flat config
if (patterns.length > 0) {
exportElements.push((0, ast_utils_1.generateAst)({
ignores: patterns.map((path) => (0, path_utils_1.mapFilePath)(path)),
}));
}
}
for (const ignorePath of ignorePaths) {
if (tree.exists(ignorePath)) {
const patterns = tree
.read(ignorePath, 'utf-8')
.split('\n')
.filter((line) => line.length > 0 && line !== 'node_modules')
.map((path) => (0, path_utils_1.mapFilePath)(path));
if (patterns.length > 0) {
exportElements.push((0, ast_utils_1.generateAst)({ ignores: patterns }));
}
}
}
// create the node list and print it to new file
const nodeList = (0, ast_utils_1.createNodeList)(importsMap, exportElements, format);
let content = (0, ast_utils_1.stringifyNodeList)(nodeList);
if (isFlatCompatNeeded) {
content = (0, ast_utils_1.addFlatCompatToFlatConfig)(content);
}
return {
content,
addESLintRC: isFlatCompatNeeded,
addESLintJS: isESLintJSNeeded,
};
}
// add parsed extends to export blocks and add import statements
function addExtends(importsMap, configBlocks, config, format) {
let isFlatCompatNeeded = false;
let isESLintJSNeeded = false;
const extendsConfig = Array.isArray(config.extends)
? config.extends
: [config.extends];
const eslintrcConfigs = [];
// add base extends
extendsConfig
.filter((imp) => imp.match(/^\.?(\.\/)/))
.forEach((imp, index) => {
if (imp.match(/\.eslintrc(.base)?\.json$/)) {
const localName = index ? `baseConfig${index}` : 'baseConfig';
configBlocks.push((0, ast_utils_1.generateSpreadElement)(localName));
const newImport = imp.replace(/^(.*)\.eslintrc(.base)?\.json$/, `$1eslint$2.config.${format}`);
importsMap.set(newImport, localName);
}
else {
eslintrcConfigs.push(imp);
}
});
// add plugin extends
const pluginExtends = extendsConfig.filter((imp) => !imp.match(/^\.?(\.\/)/));
if (pluginExtends.length) {
const eslintPluginExtends = pluginExtends.filter((imp) => imp.startsWith('eslint:'));
pluginExtends.forEach((imp) => {
if (!imp.startsWith('eslint:')) {
eslintrcConfigs.push(imp);
}
});
if (eslintPluginExtends.length) {
isESLintJSNeeded = true;
importsMap.set('@eslint/js', 'js');
eslintPluginExtends.forEach((plugin) => {
configBlocks.push(ts.factory.createPropertyAccessExpression(ts.factory.createPropertyAccessExpression(ts.factory.createIdentifier('js'), ts.factory.createIdentifier('configs')), ts.factory.createIdentifier(plugin.slice(7)) // strip 'eslint:' prefix
));
});
}
}
if (eslintrcConfigs.length) {
isFlatCompatNeeded = true;
isESLintJSNeeded = true;
configBlocks.push((0, ast_utils_1.generatePluginExtendsElement)(eslintrcConfigs));
}
return { isFlatCompatNeeded, isESLintJSNeeded };
}
function addPlugins(importsMap, configBlocks, config) {
const mappedPlugins = [];
config.plugins.forEach((name) => {
const imp = (0, eslint_file_1.getPluginImport)(name);
const varName = (0, devkit_1.names)(imp).propertyName;
mappedPlugins.push({ name, varName, imp });
});
mappedPlugins.forEach(({ varName, imp }) => {
importsMap.set(imp, varName);
});
const pluginsAst = ts.factory.createObjectLiteralExpression([
ts.factory.createPropertyAssignment('plugins', ts.factory.createObjectLiteralExpression(mappedPlugins.map(({ name, varName }) => {
return ts.factory.createPropertyAssignment(ts.factory.createStringLiteral(name), ts.factory.createIdentifier(varName));
}), mappedPlugins.length > 1)),
...(config.processor
? [
ts.factory.createPropertyAssignment('processor', ts.factory.createStringLiteral(config.processor)),
]
: []),
], false);
configBlocks.push(pluginsAst);
}
;