UNPKG

@nx/eslint

Version:

The ESLint plugin for Nx contains executors, generators and utilities used for linting JavaScript/TypeScript projects within an Nx workspace.

183 lines (182 loc) • 8.36 kB
"use strict"; 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); }