@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/eslint",
3
- "version": "17.2.0-beta.3",
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.3",
38
- "@nx/js": "17.2.0-beta.3",
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.3"
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, sourceFile: string, destinationFile: string, ignorePaths: string[]): void;
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, sourceFile, destinationFile, ignorePaths) {
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
- isFlatCompatNeeded = addExtends(importsMap, exportElements, config, tree);
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
- const content = (0, ast_utils_1.stringifyNodeList)(nodeList, root, destinationFile);
102
- tree.write((0, path_1.join)(root, destinationFile), content);
103
- if (isFlatCompatNeeded) {
104
- (0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
105
- '@eslint/eslintrc': versions_1.eslintrcVersion,
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, tree) {
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
- (0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
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
- (0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
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 (!eslintFile.endsWith('.json')) {
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 (eslintFile.endsWith('.base.json')) {
38
- convertConfigToFlatConfig(tree, '', '.eslintrc.base.json', 'eslint.base.config.js');
40
+ if (/\.base\.(js|json|yml|yaml)$/.test(eslintFile)) {
41
+ convertConfigToFlatConfig(tree, '', eslintFile, 'eslint.base.config.js');
39
42
  }
40
- convertConfigToFlatConfig(tree, '', '.eslintrc.json', 'eslint.config.js');
43
+ convertConfigToFlatConfig(tree, '', eslintFile.replace('.base.', '.'), 'eslint.config.js');
41
44
  }
42
45
  function convertProjectToFlatConfig(tree, project, projectConfig, nxJson, eslintIgnoreFiles) {
43
- if (tree.exists(`${projectConfig.root}/.eslintrc.json`)) {
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, '.eslintrc.json', 'eslint.config.js', ignorePath);
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
- (0, json_converter_1.convertEslintJsonToFlatConfig)(tree, root, source, target, ignorePaths);
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, '', 'eslint.config.js');
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
- const eslintConfig = (0, eslint_file_1.findEslintFile)(tree);
82
- const pathToRootConfig = eslintConfig
83
- ? `${(0, devkit_1.offsetFromRoot)(projectConfig.root)}${eslintConfig}`
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 (eslintConfig) {
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, 'eslint.config.js');
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: eslintConfig ? [pathToRootConfig] : undefined,
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, fileName: string): 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, fileName) {
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, fileName), '', ts.ScriptTarget.Latest, true, ts.ScriptKind.JS);
476
- return printer.printList(ts.ListFormat.MultiLine, nodes, resultFile);
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
  /**