@nx/eslint 17.2.0-beta.3 → 17.2.0-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +9 -5
- package/src/generators/convert-to-flat-config/converters/json-converter.d.ts +6 -1
- package/src/generators/convert-to-flat-config/converters/json-converter.js +15 -22
- package/src/generators/convert-to-flat-config/generator.js +42 -8
- package/src/generators/init/global-eslint-config.js +1 -1
- package/src/generators/lint-project/lint-project.js +9 -8
- package/src/generators/utils/flat-config/ast-utils.d.ts +1 -1
- package/src/generators/utils/flat-config/ast-utils.js +8 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nx/eslint",
|
|
3
|
-
"version": "17.2.0-beta.
|
|
3
|
+
"version": "17.2.0-beta.5",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "The ESLint plugin for Nx contains executors, generators and utilities used for linting JavaScript/TypeScript projects within an Nx workspace.",
|
|
6
6
|
"repository": {
|
|
@@ -30,18 +30,22 @@
|
|
|
30
30
|
"executors": "./executors.json",
|
|
31
31
|
"generators": "./generators.json",
|
|
32
32
|
"peerDependencies": {
|
|
33
|
-
"eslint": "^8.0.0"
|
|
33
|
+
"eslint": "^8.0.0",
|
|
34
|
+
"js-yaml": "4.1.0"
|
|
34
35
|
},
|
|
35
36
|
"dependencies": {
|
|
36
37
|
"tslib": "^2.3.0",
|
|
37
|
-
"@nx/devkit": "17.2.0-beta.
|
|
38
|
-
"@nx/js": "17.2.0-beta.
|
|
38
|
+
"@nx/devkit": "17.2.0-beta.5",
|
|
39
|
+
"@nx/js": "17.2.0-beta.5",
|
|
39
40
|
"typescript": "~5.2.2",
|
|
40
|
-
"@nx/linter": "17.2.0-beta.
|
|
41
|
+
"@nx/linter": "17.2.0-beta.5"
|
|
41
42
|
},
|
|
42
43
|
"peerDependenciesMeta": {
|
|
43
44
|
"eslint": {
|
|
44
45
|
"optional": true
|
|
46
|
+
},
|
|
47
|
+
"js-yaml": {
|
|
48
|
+
"optional": true
|
|
45
49
|
}
|
|
46
50
|
},
|
|
47
51
|
"publishConfig": {
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { Tree } from '@nx/devkit';
|
|
2
|
+
import { ESLint } from 'eslint';
|
|
2
3
|
/**
|
|
3
4
|
* Converts an ESLint JSON config to a flat config.
|
|
4
5
|
* Deletes the original file along with .eslintignore if it exists.
|
|
5
6
|
*/
|
|
6
|
-
export declare function convertEslintJsonToFlatConfig(tree: Tree, root: string,
|
|
7
|
+
export declare function convertEslintJsonToFlatConfig(tree: Tree, root: string, config: ESLint.ConfigData, ignorePaths: string[]): {
|
|
8
|
+
content: string;
|
|
9
|
+
addESLintRC: boolean;
|
|
10
|
+
addESLintJS: boolean;
|
|
11
|
+
};
|
|
@@ -2,25 +2,24 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.convertEslintJsonToFlatConfig = void 0;
|
|
4
4
|
const devkit_1 = require("@nx/devkit");
|
|
5
|
-
const path_1 = require("path");
|
|
6
5
|
const ts = require("typescript");
|
|
7
|
-
const versions_1 = require("../../../utils/versions");
|
|
8
6
|
const ast_utils_1 = require("../../utils/flat-config/ast-utils");
|
|
9
7
|
const eslint_file_1 = require("../../utils/eslint-file");
|
|
10
8
|
/**
|
|
11
9
|
* Converts an ESLint JSON config to a flat config.
|
|
12
10
|
* Deletes the original file along with .eslintignore if it exists.
|
|
13
11
|
*/
|
|
14
|
-
function convertEslintJsonToFlatConfig(tree, root,
|
|
12
|
+
function convertEslintJsonToFlatConfig(tree, root, config, ignorePaths) {
|
|
15
13
|
const importsMap = new Map();
|
|
16
14
|
const exportElements = [];
|
|
17
15
|
let isFlatCompatNeeded = false;
|
|
16
|
+
let isESLintJSNeeded = false;
|
|
18
17
|
let combinedConfig = [];
|
|
19
18
|
let languageOptions = [];
|
|
20
|
-
// read original config
|
|
21
|
-
const config = (0, devkit_1.readJson)(tree, `${root}/${sourceFile}`);
|
|
22
19
|
if (config.extends) {
|
|
23
|
-
|
|
20
|
+
const extendsResult = addExtends(importsMap, exportElements, config);
|
|
21
|
+
isFlatCompatNeeded = extendsResult.isFlatCompatNeeded;
|
|
22
|
+
isESLintJSNeeded = extendsResult.isESLintJSNeeded;
|
|
24
23
|
}
|
|
25
24
|
if (config.plugins) {
|
|
26
25
|
addPlugins(importsMap, exportElements, config);
|
|
@@ -95,21 +94,19 @@ function convertEslintJsonToFlatConfig(tree, root, sourceFile, destinationFile,
|
|
|
95
94
|
}
|
|
96
95
|
}
|
|
97
96
|
}
|
|
98
|
-
tree.delete((0, path_1.join)(root, sourceFile));
|
|
99
97
|
// create the node list and print it to new file
|
|
100
98
|
const nodeList = (0, ast_utils_1.createNodeList)(importsMap, exportElements, isFlatCompatNeeded);
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
});
|
|
107
|
-
}
|
|
99
|
+
return {
|
|
100
|
+
content: (0, ast_utils_1.stringifyNodeList)(nodeList, root),
|
|
101
|
+
addESLintRC: isFlatCompatNeeded,
|
|
102
|
+
addESLintJS: isESLintJSNeeded,
|
|
103
|
+
};
|
|
108
104
|
}
|
|
109
105
|
exports.convertEslintJsonToFlatConfig = convertEslintJsonToFlatConfig;
|
|
110
106
|
// add parsed extends to export blocks and add import statements
|
|
111
|
-
function addExtends(importsMap, configBlocks, config
|
|
107
|
+
function addExtends(importsMap, configBlocks, config) {
|
|
112
108
|
let isFlatCompatNeeded = false;
|
|
109
|
+
let isESLintJSNeeded = false;
|
|
113
110
|
const extendsConfig = Array.isArray(config.extends)
|
|
114
111
|
? config.extends
|
|
115
112
|
: [config.extends];
|
|
@@ -138,9 +135,7 @@ function addExtends(importsMap, configBlocks, config, tree) {
|
|
|
138
135
|
}
|
|
139
136
|
});
|
|
140
137
|
if (eslintPluginExtends.length) {
|
|
141
|
-
|
|
142
|
-
'@eslint/js': versions_1.eslintVersion,
|
|
143
|
-
});
|
|
138
|
+
isESLintJSNeeded = true;
|
|
144
139
|
importsMap.set('@eslint/js', 'js');
|
|
145
140
|
eslintPluginExtends.forEach((plugin) => {
|
|
146
141
|
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
|
|
@@ -150,12 +145,10 @@ function addExtends(importsMap, configBlocks, config, tree) {
|
|
|
150
145
|
}
|
|
151
146
|
if (eslintrcConfigs.length) {
|
|
152
147
|
isFlatCompatNeeded = true;
|
|
153
|
-
|
|
154
|
-
'@eslint/js': versions_1.eslintVersion,
|
|
155
|
-
});
|
|
148
|
+
isESLintJSNeeded = true;
|
|
156
149
|
configBlocks.push((0, ast_utils_1.generatePluginExtendsElement)(eslintrcConfigs));
|
|
157
150
|
}
|
|
158
|
-
return isFlatCompatNeeded;
|
|
151
|
+
return { isFlatCompatNeeded, isESLintJSNeeded };
|
|
159
152
|
}
|
|
160
153
|
function addPlugins(importsMap, configBlocks, config) {
|
|
161
154
|
const mappedPlugins = [];
|
|
@@ -3,14 +3,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.convertToFlatConfigGenerator = void 0;
|
|
4
4
|
const devkit_1 = require("@nx/devkit");
|
|
5
5
|
const eslint_file_1 = require("../utils/eslint-file");
|
|
6
|
+
const path_1 = require("path");
|
|
7
|
+
const versions_1 = require("../../utils/versions");
|
|
6
8
|
const json_converter_1 = require("./converters/json-converter");
|
|
9
|
+
const js_yaml_1 = require("js-yaml");
|
|
7
10
|
async function convertToFlatConfigGenerator(tree, options) {
|
|
8
11
|
const eslintFile = (0, eslint_file_1.findEslintFile)(tree);
|
|
9
12
|
if (!eslintFile) {
|
|
10
13
|
throw new Error('Could not find root eslint file');
|
|
11
14
|
}
|
|
12
|
-
if (
|
|
13
|
-
throw new Error('Only json eslint config files are supported for conversion');
|
|
15
|
+
if (eslintFile.endsWith('.js')) {
|
|
16
|
+
throw new Error('Only json and yaml eslint config files are supported for conversion');
|
|
14
17
|
}
|
|
15
18
|
const eslintIgnoreFiles = new Set(['.eslintignore']);
|
|
16
19
|
// convert root eslint config to eslint.config.js
|
|
@@ -34,13 +37,14 @@ async function convertToFlatConfigGenerator(tree, options) {
|
|
|
34
37
|
exports.convertToFlatConfigGenerator = convertToFlatConfigGenerator;
|
|
35
38
|
exports.default = convertToFlatConfigGenerator;
|
|
36
39
|
function convertRootToFlatConfig(tree, eslintFile) {
|
|
37
|
-
if (
|
|
38
|
-
convertConfigToFlatConfig(tree, '',
|
|
40
|
+
if (/\.base\.(js|json|yml|yaml)$/.test(eslintFile)) {
|
|
41
|
+
convertConfigToFlatConfig(tree, '', eslintFile, 'eslint.base.config.js');
|
|
39
42
|
}
|
|
40
|
-
convertConfigToFlatConfig(tree, '', '.
|
|
43
|
+
convertConfigToFlatConfig(tree, '', eslintFile.replace('.base.', '.'), 'eslint.config.js');
|
|
41
44
|
}
|
|
42
45
|
function convertProjectToFlatConfig(tree, project, projectConfig, nxJson, eslintIgnoreFiles) {
|
|
43
|
-
|
|
46
|
+
const eslintFile = (0, eslint_file_1.findEslintFile)(tree, projectConfig.root);
|
|
47
|
+
if (eslintFile && !eslintFile.endsWith('.js')) {
|
|
44
48
|
if (projectConfig.targets) {
|
|
45
49
|
const eslintTargets = Object.keys(projectConfig.targets || {}).filter((t) => projectConfig.targets[t].executor === '@nx/eslint:lint');
|
|
46
50
|
let ignorePath;
|
|
@@ -59,7 +63,7 @@ function convertProjectToFlatConfig(tree, project, projectConfig, nxJson, eslint
|
|
|
59
63
|
nxJson.targetDefaults[t].executor === '@nx/eslint:lint') &&
|
|
60
64
|
projectConfig.targets?.[t]);
|
|
61
65
|
if (nxHasLintTargets || eslintTargets.length > 0) {
|
|
62
|
-
convertConfigToFlatConfig(tree, projectConfig.root,
|
|
66
|
+
convertConfigToFlatConfig(tree, projectConfig.root, eslintFile, 'eslint.config.js', ignorePath);
|
|
63
67
|
eslintIgnoreFiles.add(`${projectConfig.root}/.eslintignore`);
|
|
64
68
|
if (ignorePath) {
|
|
65
69
|
eslintIgnoreFiles.add(ignorePath);
|
|
@@ -96,5 +100,35 @@ function convertConfigToFlatConfig(tree, root, source, target, ignorePath) {
|
|
|
96
100
|
const ignorePaths = ignorePath
|
|
97
101
|
? [ignorePath, `${root}/.eslintignore`]
|
|
98
102
|
: [`${root}/.eslintignore`];
|
|
99
|
-
(
|
|
103
|
+
if (source.endsWith('.json')) {
|
|
104
|
+
const config = (0, devkit_1.readJson)(tree, `${root}/${source}`);
|
|
105
|
+
const conversionResult = (0, json_converter_1.convertEslintJsonToFlatConfig)(tree, root, config, ignorePaths);
|
|
106
|
+
return processConvertedConfig(tree, root, source, target, conversionResult);
|
|
107
|
+
}
|
|
108
|
+
if (source.endsWith('.yaml') || source.endsWith('.yml')) {
|
|
109
|
+
const originalContent = tree.read(`${root}/${source}`, 'utf-8');
|
|
110
|
+
const config = (0, js_yaml_1.load)(originalContent, {
|
|
111
|
+
json: true,
|
|
112
|
+
filename: source,
|
|
113
|
+
});
|
|
114
|
+
const conversionResult = (0, json_converter_1.convertEslintJsonToFlatConfig)(tree, root, config, ignorePaths);
|
|
115
|
+
return processConvertedConfig(tree, root, source, target, conversionResult);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function processConvertedConfig(tree, root, source, target, { content, addESLintRC, addESLintJS, }) {
|
|
119
|
+
// remove original config file
|
|
120
|
+
tree.delete((0, path_1.join)(root, source));
|
|
121
|
+
// save new
|
|
122
|
+
tree.write((0, path_1.join)(root, target), content);
|
|
123
|
+
// add missing packages
|
|
124
|
+
if (addESLintRC) {
|
|
125
|
+
(0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
|
|
126
|
+
'@eslint/eslintrc': versions_1.eslintrcVersion,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
if (addESLintJS) {
|
|
130
|
+
(0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
|
|
131
|
+
'@eslint/js': versions_1.eslintVersion,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
100
134
|
}
|
|
@@ -80,7 +80,7 @@ const getGlobalEsLintConfiguration = (unitTestRunner, rootProject) => {
|
|
|
80
80
|
exports.getGlobalEsLintConfiguration = getGlobalEsLintConfiguration;
|
|
81
81
|
const getGlobalFlatEslintConfiguration = (unitTestRunner, rootProject) => {
|
|
82
82
|
const nodeList = (0, ast_utils_1.createNodeList)(new Map(), [], true);
|
|
83
|
-
let content = (0, ast_utils_1.stringifyNodeList)(nodeList, ''
|
|
83
|
+
let content = (0, ast_utils_1.stringifyNodeList)(nodeList, '');
|
|
84
84
|
content = (0, ast_utils_1.addImportToFlatConfig)(content, 'nxPlugin', '@nx/eslint-plugin');
|
|
85
85
|
content = (0, ast_utils_1.addPluginsToExportsBlock)(content, [
|
|
86
86
|
{ name: '@nx', varName: 'nxPlugin', imp: '@nx/eslint-plugin' },
|
|
@@ -58,7 +58,7 @@ async function lintProjectGenerator(tree, options) {
|
|
|
58
58
|
// additionally, the companion e2e app would have `rootProject: true`
|
|
59
59
|
// so we need to check for the root path as well
|
|
60
60
|
if (!options.rootProject || projectConfig.root !== '.') {
|
|
61
|
-
createEsLintConfiguration(tree, projectConfig, options.setParserOptionsProject);
|
|
61
|
+
createEsLintConfiguration(tree, projectConfig, options.setParserOptionsProject, options.rootProject);
|
|
62
62
|
}
|
|
63
63
|
// Buildable libs need source analysis enabled for linting `package.json`.
|
|
64
64
|
if (isBuildableLibraryProject(projectConfig) &&
|
|
@@ -77,10 +77,11 @@ async function lintProjectGenerator(tree, options) {
|
|
|
77
77
|
return installTask;
|
|
78
78
|
}
|
|
79
79
|
exports.lintProjectGenerator = lintProjectGenerator;
|
|
80
|
-
function createEsLintConfiguration(tree, projectConfig, setParserOptionsProject) {
|
|
81
|
-
|
|
82
|
-
const
|
|
83
|
-
|
|
80
|
+
function createEsLintConfiguration(tree, projectConfig, setParserOptionsProject, rootProject) {
|
|
81
|
+
// we are only extending root for non-standalone projects or their complementary e2e apps
|
|
82
|
+
const extendedRootConfig = rootProject ? undefined : (0, eslint_file_1.findEslintFile)(tree);
|
|
83
|
+
const pathToRootConfig = extendedRootConfig
|
|
84
|
+
? `${(0, devkit_1.offsetFromRoot)(projectConfig.root)}${extendedRootConfig}`
|
|
84
85
|
: undefined;
|
|
85
86
|
const addDependencyChecks = isBuildableLibraryProject(projectConfig);
|
|
86
87
|
const overrides = [
|
|
@@ -132,7 +133,7 @@ function createEsLintConfiguration(tree, projectConfig, setParserOptionsProject)
|
|
|
132
133
|
const isCompatNeeded = addDependencyChecks;
|
|
133
134
|
const nodes = [];
|
|
134
135
|
const importMap = new Map();
|
|
135
|
-
if (
|
|
136
|
+
if (extendedRootConfig) {
|
|
136
137
|
importMap.set(pathToRootConfig, 'baseConfig');
|
|
137
138
|
nodes.push((0, ast_utils_1.generateSpreadElement)('baseConfig'));
|
|
138
139
|
}
|
|
@@ -140,12 +141,12 @@ function createEsLintConfiguration(tree, projectConfig, setParserOptionsProject)
|
|
|
140
141
|
nodes.push((0, ast_utils_1.generateFlatOverride)(override, projectConfig.root));
|
|
141
142
|
});
|
|
142
143
|
const nodeList = (0, ast_utils_1.createNodeList)(importMap, nodes, isCompatNeeded);
|
|
143
|
-
const content = (0, ast_utils_1.stringifyNodeList)(nodeList, projectConfig.root
|
|
144
|
+
const content = (0, ast_utils_1.stringifyNodeList)(nodeList, projectConfig.root);
|
|
144
145
|
tree.write((0, path_1.join)(projectConfig.root, 'eslint.config.js'), content);
|
|
145
146
|
}
|
|
146
147
|
else {
|
|
147
148
|
(0, devkit_1.writeJson)(tree, (0, path_1.join)(projectConfig.root, `.eslintrc.json`), {
|
|
148
|
-
extends:
|
|
149
|
+
extends: extendedRootConfig ? [pathToRootConfig] : undefined,
|
|
149
150
|
// Include project files to be linted since the global one excludes all files.
|
|
150
151
|
ignorePatterns: ['!**/*'],
|
|
151
152
|
overrides,
|
|
@@ -44,7 +44,7 @@ export declare function generatePluginExtendsElement(plugins: string[]): ts.Spre
|
|
|
44
44
|
/**
|
|
45
45
|
* Stringifies TS nodes to file content string
|
|
46
46
|
*/
|
|
47
|
-
export declare function stringifyNodeList(nodes: ts.NodeArray<ts.VariableStatement | ts.Identifier | ts.ExpressionStatement | ts.SourceFile>, root: string
|
|
47
|
+
export declare function stringifyNodeList(nodes: ts.NodeArray<ts.VariableStatement | ts.Identifier | ts.ExpressionStatement | ts.SourceFile>, root: string): string;
|
|
48
48
|
/**
|
|
49
49
|
* generates AST require statement
|
|
50
50
|
*/
|
|
@@ -470,10 +470,15 @@ exports.generatePluginExtendsElement = generatePluginExtendsElement;
|
|
|
470
470
|
/**
|
|
471
471
|
* Stringifies TS nodes to file content string
|
|
472
472
|
*/
|
|
473
|
-
function stringifyNodeList(nodes, root
|
|
473
|
+
function stringifyNodeList(nodes, root) {
|
|
474
474
|
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
|
|
475
|
-
const resultFile = ts.createSourceFile((0, devkit_1.joinPathFragments)(root,
|
|
476
|
-
return printer
|
|
475
|
+
const resultFile = ts.createSourceFile((0, devkit_1.joinPathFragments)(root, ''), '', ts.ScriptTarget.Latest, true, ts.ScriptKind.JS);
|
|
476
|
+
return (printer
|
|
477
|
+
.printList(ts.ListFormat.MultiLine, nodes, resultFile)
|
|
478
|
+
// add new line before compat initialization
|
|
479
|
+
.replace(/const compat = new FlatCompat/, '\nconst compat = new FlatCompat')
|
|
480
|
+
// add new line before module.exports = ...
|
|
481
|
+
.replace(/module\.exports/, '\nmodule.exports'));
|
|
477
482
|
}
|
|
478
483
|
exports.stringifyNodeList = stringifyNodeList;
|
|
479
484
|
/**
|