@nx/eslint 19.2.0-canary.20240531-2cb7ecb → 19.2.0-canary.20240604-0594deb

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": "19.2.0-canary.20240531-2cb7ecb",
3
+ "version": "19.2.0-canary.20240604-0594deb",
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": {
@@ -35,12 +35,12 @@
35
35
  "eslint": "^8.0.0 || ^9.0.0"
36
36
  },
37
37
  "dependencies": {
38
- "@nx/devkit": "19.2.0-canary.20240531-2cb7ecb",
39
- "@nx/js": "19.2.0-canary.20240531-2cb7ecb",
38
+ "@nx/devkit": "19.2.0-canary.20240604-0594deb",
39
+ "@nx/js": "19.2.0-canary.20240604-0594deb",
40
40
  "semver": "^7.5.3",
41
41
  "tslib": "^2.3.0",
42
42
  "typescript": "~5.4.2",
43
- "@nx/linter": "19.2.0-canary.20240531-2cb7ecb"
43
+ "@nx/linter": "19.2.0-canary.20240604-0594deb"
44
44
  },
45
45
  "peerDependenciesMeta": {
46
46
  "@zkochan/js-yaml": {
@@ -1,4 +1,4 @@
1
- import { Tree } from '@nx/devkit';
1
+ import { GeneratorCallback, Tree } from '@nx/devkit';
2
2
  import { ConvertToFlatConfigGeneratorSchema } from './schema';
3
- export declare function convertToFlatConfigGenerator(tree: Tree, options: ConvertToFlatConfigGeneratorSchema): Promise<void>;
3
+ export declare function convertToFlatConfigGenerator(tree: Tree, options: ConvertToFlatConfigGeneratorSchema): Promise<void | GeneratorCallback>;
4
4
  export default convertToFlatConfigGenerator;
@@ -6,6 +6,7 @@ const eslint_file_1 = require("../utils/eslint-file");
6
6
  const path_1 = require("path");
7
7
  const versions_1 = require("../../utils/versions");
8
8
  const json_converter_1 = require("./converters/json-converter");
9
+ let shouldInstallDeps = false;
9
10
  async function convertToFlatConfigGenerator(tree, options) {
10
11
  const eslintFile = (0, eslint_file_1.findEslintFile)(tree);
11
12
  if (!eslintFile) {
@@ -32,6 +33,9 @@ async function convertToFlatConfigGenerator(tree, options) {
32
33
  if (!options.skipFormat) {
33
34
  await (0, devkit_1.formatFiles)(tree);
34
35
  }
36
+ if (shouldInstallDeps) {
37
+ return () => (0, devkit_1.installPackagesTask)(tree);
38
+ }
35
39
  }
36
40
  exports.convertToFlatConfigGenerator = convertToFlatConfigGenerator;
37
41
  exports.default = convertToFlatConfigGenerator;
@@ -127,11 +131,13 @@ function processConvertedConfig(tree, root, source, target, { content, addESLint
127
131
  tree.write((0, path_1.join)(root, target), content);
128
132
  // add missing packages
129
133
  if (addESLintRC) {
134
+ shouldInstallDeps = true;
130
135
  (0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
131
136
  '@eslint/eslintrc': versions_1.eslintrcVersion,
132
137
  });
133
138
  }
134
139
  if (addESLintJS) {
140
+ shouldInstallDeps = true;
135
141
  (0, devkit_1.addDependenciesToPackageJson)(tree, {}, {
136
142
  '@eslint/js': versions_1.eslintVersion,
137
143
  });
@@ -8,8 +8,8 @@ const target_options_map_1 = require("./lib/target-options-map");
8
8
  const utils_1 = require("nx/src/tasks-runner/utils");
9
9
  async function convertToInferred(tree, options) {
10
10
  const projectGraph = await (0, devkit_1.createProjectGraphAsync)();
11
- const migratedProjectsModern = await (0, executor_to_plugin_migrator_1.migrateExecutorToPlugin)(tree, projectGraph, '@nx/eslint:lint', '@nx/eslint/plugin', (targetName) => ({ targetName }), postTargetTransformer, plugin_1.createNodes, options.project);
12
- const migratedProjectsLegacy = await (0, executor_to_plugin_migrator_1.migrateExecutorToPlugin)(tree, projectGraph, '@nrwl/linter:eslint', '@nx/eslint/plugin', (targetName) => ({ targetName }), postTargetTransformer, plugin_1.createNodes, options.project);
11
+ const migratedProjectsModern = await (0, executor_to_plugin_migrator_1.migrateExecutorToPlugin)(tree, projectGraph, '@nx/eslint:lint', '@nx/eslint/plugin', (targetName) => ({ targetName }), postTargetTransformer, plugin_1.createNodesV2, options.project);
12
+ const migratedProjectsLegacy = await (0, executor_to_plugin_migrator_1.migrateExecutorToPlugin)(tree, projectGraph, '@nrwl/linter:eslint', '@nx/eslint/plugin', (targetName) => ({ targetName }), postTargetTransformer, plugin_1.createNodesV2, options.project);
13
13
  const migratedProjects = migratedProjectsModern.size + migratedProjectsLegacy.size;
14
14
  if (migratedProjects === 0) {
15
15
  throw new Error('Could not find any targets to migrate.');
@@ -21,14 +21,14 @@ async function convertToInferred(tree, options) {
21
21
  exports.convertToInferred = convertToInferred;
22
22
  function postTargetTransformer(target, tree, projectDetails) {
23
23
  if (target.inputs) {
24
- target.inputs = target.inputs.filter((input) => typeof input === 'string' &&
24
+ const inputs = target.inputs.filter((input) => typeof input === 'string' &&
25
25
  ![
26
26
  'default',
27
27
  '{workspaceRoot}/.eslintrc.json',
28
28
  '{workspaceRoot}/.eslintignore',
29
29
  '{workspaceRoot}/eslint.config.js',
30
30
  ].includes(input));
31
- if (target.inputs.length === 0) {
31
+ if (inputs.length === 0) {
32
32
  delete target.inputs;
33
33
  }
34
34
  }
@@ -48,7 +48,7 @@ async function initEsLint(tree, options) {
48
48
  '_eslint-lint',
49
49
  ];
50
50
  if (rootEslintFile && options.addPlugin && !hasPlugin) {
51
- await (0, add_plugin_1.addPlugin)(tree, graph, '@nx/eslint/plugin', plugin_1.createNodes, {
51
+ await (0, add_plugin_1.addPlugin)(tree, graph, '@nx/eslint/plugin', plugin_1.createNodesV2, {
52
52
  targetName: lintTargetNames,
53
53
  }, options.updatePackageScripts);
54
54
  return () => { };
@@ -58,7 +58,7 @@ async function initEsLint(tree, options) {
58
58
  }
59
59
  updateProductionFileset(tree);
60
60
  if (options.addPlugin) {
61
- await (0, add_plugin_1.addPlugin)(tree, graph, '@nx/eslint/plugin', plugin_1.createNodes, {
61
+ await (0, add_plugin_1.addPlugin)(tree, graph, '@nx/eslint/plugin', plugin_1.createNodesV2, {
62
62
  targetName: lintTargetNames,
63
63
  }, options.updatePackageScripts);
64
64
  }
@@ -16,6 +16,7 @@ interface LintProjectOptions {
16
16
  * @internal
17
17
  */
18
18
  addExplicitTargets?: boolean;
19
+ addPackageJsonDependencyChecks?: boolean;
19
20
  }
20
21
  export declare function lintProjectGenerator(tree: Tree, options: LintProjectOptions): Promise<GeneratorCallback>;
21
22
  export declare function lintProjectGeneratorInternal(tree: Tree, options: LintProjectOptions): Promise<GeneratorCallback>;
@@ -89,7 +89,7 @@ async function lintProjectGeneratorInternal(tree, options) {
89
89
  // additionally, the companion e2e app would have `rootProject: true`
90
90
  // so we need to check for the root path as well
91
91
  if (!options.rootProject || projectConfig.root !== '.') {
92
- createEsLintConfiguration(tree, projectConfig, options.setParserOptionsProject, options.rootProject);
92
+ createEsLintConfiguration(tree, options, projectConfig, options.setParserOptionsProject, options.rootProject);
93
93
  }
94
94
  // Buildable libs need source analysis enabled for linting `package.json`.
95
95
  if (isBuildableLibraryProject(projectConfig) &&
@@ -108,7 +108,7 @@ async function lintProjectGeneratorInternal(tree, options) {
108
108
  return (0, devkit_1.runTasksInSerial)(...tasks);
109
109
  }
110
110
  exports.lintProjectGeneratorInternal = lintProjectGeneratorInternal;
111
- function createEsLintConfiguration(tree, projectConfig, setParserOptionsProject, rootProject) {
111
+ function createEsLintConfiguration(tree, options, projectConfig, setParserOptionsProject, rootProject) {
112
112
  // we are only extending root for non-standalone projects or their complementary e2e apps
113
113
  const extendedRootConfig = rootProject ? undefined : (0, eslint_file_1.findEslintFile)(tree);
114
114
  const pathToRootConfig = extendedRootConfig
@@ -151,7 +151,8 @@ function createEsLintConfiguration(tree, projectConfig, setParserOptionsProject,
151
151
  rules: {},
152
152
  },
153
153
  ];
154
- if (isBuildableLibraryProject(projectConfig)) {
154
+ if (options.addPackageJsonDependencyChecks ||
155
+ isBuildableLibraryProject(projectConfig)) {
155
156
  overrides.push({
156
157
  files: ['*.json'],
157
158
  parser: 'jsonc-eslint-parser',
@@ -1,6 +1,7 @@
1
- import { CreateNodes } from '@nx/devkit';
1
+ import { CreateNodes, CreateNodesV2 } from '@nx/devkit';
2
2
  export interface EslintPluginOptions {
3
3
  targetName?: string;
4
4
  extensions?: string[];
5
5
  }
6
+ export declare const createNodesV2: CreateNodesV2<EslintPluginOptions>;
6
7
  export declare const createNodes: CreateNodes<EslintPluginOptions>;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createNodes = void 0;
3
+ exports.createNodes = exports.createNodesV2 = void 0;
4
+ const devkit_1 = require("@nx/devkit");
4
5
  const node_fs_1 = require("node:fs");
5
6
  const node_path_1 = require("node:path");
6
7
  const globs_1 = require("nx/src/utils/globs");
@@ -8,63 +9,100 @@ const workspace_context_1 = require("nx/src/utils/workspace-context");
8
9
  const config_file_1 = require("../utils/config-file");
9
10
  const resolve_eslint_class_1 = require("../utils/resolve-eslint-class");
10
11
  const semver_1 = require("semver");
12
+ const cache_directory_1 = require("nx/src/utils/cache-directory");
13
+ const file_hasher_1 = require("nx/src/hasher/file-hasher");
14
+ const calculate_hash_for_create_nodes_1 = require("@nx/devkit/src/utils/calculate-hash-for-create-nodes");
11
15
  const DEFAULT_EXTENSIONS = ['ts', 'tsx', 'js', 'jsx', 'html', 'vue'];
12
- exports.createNodes = [
13
- (0, globs_1.combineGlobPatterns)([
14
- ...config_file_1.ESLINT_CONFIG_FILENAMES.map((f) => `**/${f}`),
15
- config_file_1.baseEsLintConfigFile,
16
- config_file_1.baseEsLintFlatConfigFile,
17
- ]),
18
- async (configFilePath, options, context) => {
19
- options = normalizeOptions(options);
20
- const configDir = (0, node_path_1.dirname)(configFilePath);
21
- // Ensure that configFiles are set, e2e-run fails due to them being undefined in CI (does not occur locally)
22
- // TODO(JamesHenry): Further troubleshoot this in CI
23
- context.configFiles = context.configFiles ?? [];
24
- // Create a Set of all the directories containing eslint configs, and a
25
- // list of globs to exclude from child projects
26
- const eslintRoots = new Set();
27
- const nestedEslintRootPatterns = [];
28
- for (const configFile of context.configFiles) {
29
- const eslintRootDir = (0, node_path_1.dirname)(configFile);
30
- eslintRoots.add(eslintRootDir);
31
- if (eslintRootDir !== configDir && isSubDir(configDir, eslintRootDir)) {
32
- nestedEslintRootPatterns.push(`${eslintRootDir}/**/*`);
33
- }
16
+ const ESLINT_CONFIG_GLOB = (0, globs_1.combineGlobPatterns)([
17
+ ...config_file_1.ESLINT_CONFIG_FILENAMES.map((f) => `**/${f}`),
18
+ config_file_1.baseEsLintConfigFile,
19
+ config_file_1.baseEsLintFlatConfigFile,
20
+ ]);
21
+ function readTargetsCache(cachePath) {
22
+ return (0, node_fs_1.existsSync)(cachePath) ? (0, devkit_1.readJsonFile)(cachePath) : {};
23
+ }
24
+ function writeTargetsToCache(cachePath, results) {
25
+ (0, devkit_1.writeJsonFile)(cachePath, results);
26
+ }
27
+ const internalCreateNodes = async (configFilePath, options, context, projectsCache) => {
28
+ options = normalizeOptions(options);
29
+ const configDir = (0, node_path_1.dirname)(configFilePath);
30
+ // Ensure that configFiles are set, e2e-run fails due to them being undefined in CI (does not occur locally)
31
+ // TODO(JamesHenry): Further troubleshoot this in CI
32
+ context.configFiles = context.configFiles ?? [];
33
+ // Create a Set of all the directories containing eslint configs, and a
34
+ // list of globs to exclude from child projects
35
+ const eslintRoots = new Set();
36
+ const nestedEslintRootPatterns = [];
37
+ for (const configFile of context.configFiles) {
38
+ const eslintRootDir = (0, node_path_1.dirname)(configFile);
39
+ eslintRoots.add(eslintRootDir);
40
+ if (eslintRootDir !== configDir && isSubDir(configDir, eslintRootDir)) {
41
+ nestedEslintRootPatterns.push(`${eslintRootDir}/**/*`);
34
42
  }
35
- const projectFiles = (0, workspace_context_1.globWithWorkspaceContext)(context.workspaceRoot, [
36
- 'project.json',
37
- 'package.json',
38
- '**/project.json',
39
- '**/package.json',
40
- ].map((f) => (0, node_path_1.join)(configDir, f)), nestedEslintRootPatterns.length ? nestedEslintRootPatterns : undefined);
41
- // dedupe and sort project roots by depth for more efficient traversal
42
- const dedupedProjectRoots = Array.from(new Set(projectFiles.map((f) => (0, node_path_1.dirname)(f)))).sort((a, b) => (a !== b && isSubDir(a, b) ? -1 : 1));
43
- const excludePatterns = dedupedProjectRoots.map((root) => `${root}/**/*`);
44
- const ESLint = await (0, resolve_eslint_class_1.resolveESLintClass)((0, config_file_1.isFlatConfig)(configFilePath));
45
- const eslintVersion = ESLint.version;
46
- const childProjectRoots = new Set();
47
- await Promise.all(dedupedProjectRoots.map(async (childProjectRoot, index) => {
48
- // anything after is either a nested project or a sibling project, can be excluded
49
- const nestedProjectRootPatterns = excludePatterns.slice(index + 1);
50
- // Ignore project roots where the project does not contain any lintable files
51
- const lintableFiles = (0, workspace_context_1.globWithWorkspaceContext)(context.workspaceRoot, [(0, node_path_1.join)(childProjectRoot, `**/*.{${options.extensions.join(',')}}`)],
52
- // exclude nested eslint roots and nested project roots
53
- [...nestedEslintRootPatterns, ...nestedProjectRootPatterns]);
54
- const eslint = new ESLint({
55
- cwd: (0, node_path_1.join)(context.workspaceRoot, childProjectRoot),
56
- });
57
- for (const file of lintableFiles) {
58
- if (!(await eslint.isPathIgnored((0, node_path_1.join)(context.workspaceRoot, file)))) {
59
- childProjectRoots.add(childProjectRoot);
60
- break;
61
- }
43
+ }
44
+ const projectFiles = await (0, workspace_context_1.globWithWorkspaceContext)(context.workspaceRoot, ['project.json', 'package.json', '**/project.json', '**/package.json'].map((f) => (0, node_path_1.join)(configDir, f)), nestedEslintRootPatterns.length ? nestedEslintRootPatterns : undefined);
45
+ // dedupe and sort project roots by depth for more efficient traversal
46
+ const dedupedProjectRoots = Array.from(new Set(projectFiles.map((f) => (0, node_path_1.dirname)(f)))).sort((a, b) => (a !== b && isSubDir(a, b) ? -1 : 1));
47
+ const excludePatterns = dedupedProjectRoots.map((root) => `${root}/**/*`);
48
+ const ESLint = await (0, resolve_eslint_class_1.resolveESLintClass)((0, config_file_1.isFlatConfig)(configFilePath));
49
+ const eslintVersion = ESLint.version;
50
+ const childProjectRoots = new Set();
51
+ const projects = {};
52
+ await Promise.all(dedupedProjectRoots.map(async (childProjectRoot, index) => {
53
+ // anything after is either a nested project or a sibling project, can be excluded
54
+ const nestedProjectRootPatterns = excludePatterns.slice(index + 1);
55
+ // Ignore project roots where the project does not contain any lintable files
56
+ const lintableFiles = await (0, workspace_context_1.globWithWorkspaceContext)(context.workspaceRoot, [(0, node_path_1.join)(childProjectRoot, `**/*.{${options.extensions.join(',')}}`)],
57
+ // exclude nested eslint roots and nested project roots
58
+ [...nestedEslintRootPatterns, ...nestedProjectRootPatterns]);
59
+ const parentConfigs = context.configFiles.filter((eslintConfig) => isSubDir(childProjectRoot, (0, node_path_1.dirname)(eslintConfig)));
60
+ const hash = await (0, calculate_hash_for_create_nodes_1.calculateHashForCreateNodes)(childProjectRoot, options, context, [...parentConfigs, (0, node_path_1.join)(childProjectRoot, '.eslintignore')]);
61
+ if (projectsCache[hash]) {
62
+ // We can reuse the projects in the cache.
63
+ Object.assign(projects, projectsCache[hash]);
64
+ return;
65
+ }
66
+ const eslint = new ESLint({
67
+ cwd: (0, node_path_1.join)(context.workspaceRoot, childProjectRoot),
68
+ });
69
+ for (const file of lintableFiles) {
70
+ if (!(await eslint.isPathIgnored((0, node_path_1.join)(context.workspaceRoot, file)))) {
71
+ childProjectRoots.add(childProjectRoot);
72
+ break;
62
73
  }
63
- }));
74
+ }
64
75
  const uniqueChildProjectRoots = Array.from(childProjectRoots);
65
- return {
66
- projects: getProjectsUsingESLintConfig(configFilePath, uniqueChildProjectRoots, eslintVersion, options, context),
67
- };
76
+ const projectsForRoot = getProjectsUsingESLintConfig(configFilePath, uniqueChildProjectRoots, eslintVersion, options, context);
77
+ if (Object.keys(projectsForRoot).length > 0) {
78
+ Object.assign(projects, projectsForRoot);
79
+ // Store those projects into the cache;
80
+ projectsCache[hash] = projectsForRoot;
81
+ }
82
+ }));
83
+ return {
84
+ projects,
85
+ };
86
+ };
87
+ exports.createNodesV2 = [
88
+ ESLINT_CONFIG_GLOB,
89
+ async (configFiles, options, context) => {
90
+ const optionsHash = (0, file_hasher_1.hashObject)(options);
91
+ const cachePath = (0, node_path_1.join)(cache_directory_1.projectGraphCacheDirectory, `eslint-${optionsHash}.hash`);
92
+ const targetsCache = readTargetsCache(cachePath);
93
+ try {
94
+ return await (0, devkit_1.createNodesFromFiles)((configFile, options, context) => internalCreateNodes(configFile, options, context, targetsCache), configFiles, options, context);
95
+ }
96
+ finally {
97
+ writeTargetsToCache(cachePath, targetsCache);
98
+ }
99
+ },
100
+ ];
101
+ exports.createNodes = [
102
+ ESLINT_CONFIG_GLOB,
103
+ (configFilePath, options, context) => {
104
+ devkit_1.logger.warn('`createNodes` is deprecated. Update your plugin to utilize createNodesV2 instead. In Nx 20, this will change to the createNodesV2 API.');
105
+ return internalCreateNodes(configFilePath, options, context, {});
68
106
  },
69
107
  ];
70
108
  function getProjectsUsingESLintConfig(configFilePath, childProjectRoots, eslintVersion, options, context) {
@@ -76,11 +114,17 @@ function getProjectsUsingESLintConfig(configFilePath, childProjectRoots, eslintV
76
114
  ].find((f) => (0, node_fs_1.existsSync)((0, node_path_1.join)(context.workspaceRoot, f)));
77
115
  // Add a lint target for each child project without an eslint config, with the root level config as an input
78
116
  for (const projectRoot of childProjectRoots) {
79
- // If there's no src folder, it's not a standalone project, do not add the target at all
80
- const isStandaloneWorkspace = projectRoot === '.' &&
81
- (0, node_fs_1.existsSync)((0, node_path_1.join)(context.workspaceRoot, projectRoot, 'src')) &&
82
- (0, node_fs_1.existsSync)((0, node_path_1.join)(context.workspaceRoot, projectRoot, 'package.json'));
83
- if (projectRoot === '.' && !isStandaloneWorkspace) {
117
+ let standaloneSrcPath;
118
+ if (projectRoot === '.' &&
119
+ (0, node_fs_1.existsSync)((0, node_path_1.join)(context.workspaceRoot, projectRoot, 'package.json'))) {
120
+ if ((0, node_fs_1.existsSync)((0, node_path_1.join)(context.workspaceRoot, projectRoot, 'src'))) {
121
+ standaloneSrcPath = 'src';
122
+ }
123
+ else if ((0, node_fs_1.existsSync)((0, node_path_1.join)(context.workspaceRoot, projectRoot, 'lib'))) {
124
+ standaloneSrcPath = 'lib';
125
+ }
126
+ }
127
+ if (projectRoot === '.' && !standaloneSrcPath) {
84
128
  continue;
85
129
  }
86
130
  const eslintConfigs = [configFilePath];
@@ -88,16 +132,16 @@ function getProjectsUsingESLintConfig(configFilePath, childProjectRoots, eslintV
88
132
  eslintConfigs.unshift(rootEslintConfig);
89
133
  }
90
134
  projects[projectRoot] = {
91
- targets: buildEslintTargets(eslintConfigs, eslintVersion, projectRoot, context.workspaceRoot, options, isStandaloneWorkspace),
135
+ targets: buildEslintTargets(eslintConfigs, eslintVersion, projectRoot, context.workspaceRoot, options, standaloneSrcPath),
92
136
  };
93
137
  }
94
138
  return projects;
95
139
  }
96
- function buildEslintTargets(eslintConfigs, eslintVersion, projectRoot, workspaceRoot, options, isStandaloneWorkspace = false) {
140
+ function buildEslintTargets(eslintConfigs, eslintVersion, projectRoot, workspaceRoot, options, standaloneSrcPath) {
97
141
  const isRootProject = projectRoot === '.';
98
142
  const targets = {};
99
143
  const targetConfig = {
100
- command: `eslint ${isRootProject && isStandaloneWorkspace ? './src' : '.'}`,
144
+ command: `eslint ${isRootProject && standaloneSrcPath ? `./${standaloneSrcPath}` : '.'}`,
101
145
  cache: true,
102
146
  options: {
103
147
  cwd: projectRoot,