@nx/eslint 19.0.0-canary.20240423-b37bfdb → 19.0.0-canary.20240426-ac9ad35
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 +4 -4
- package/src/plugins/plugin.js +68 -27
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@nx/eslint",
|
3
|
-
"version": "19.0.0-canary.
|
3
|
+
"version": "19.0.0-canary.20240426-ac9ad35",
|
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": {
|
@@ -33,12 +33,12 @@
|
|
33
33
|
"js-yaml": "4.1.0"
|
34
34
|
},
|
35
35
|
"dependencies": {
|
36
|
-
"@nx/devkit": "19.0.0-canary.
|
37
|
-
"@nx/js": "19.0.0-canary.
|
36
|
+
"@nx/devkit": "19.0.0-canary.20240426-ac9ad35",
|
37
|
+
"@nx/js": "19.0.0-canary.20240426-ac9ad35",
|
38
38
|
"eslint": "^8.0.0",
|
39
39
|
"tslib": "^2.3.0",
|
40
40
|
"typescript": "~5.4.2",
|
41
|
-
"@nx/linter": "19.0.0-canary.
|
41
|
+
"@nx/linter": "19.0.0-canary.20240426-ac9ad35"
|
42
42
|
},
|
43
43
|
"peerDependenciesMeta": {
|
44
44
|
"js-yaml": {
|
package/src/plugins/plugin.js
CHANGED
@@ -13,41 +13,52 @@ exports.createNodes = [
|
|
13
13
|
config_file_1.baseEsLintConfigFile,
|
14
14
|
config_file_1.baseEsLintFlatConfigFile,
|
15
15
|
]),
|
16
|
-
(configFilePath, options, context) => {
|
16
|
+
async (configFilePath, options, context) => {
|
17
17
|
options = normalizeOptions(options);
|
18
|
+
const configDir = (0, node_path_1.dirname)(configFilePath);
|
18
19
|
// Ensure that configFiles are set, e2e-run fails due to them being undefined in CI (does not occur locally)
|
19
20
|
// TODO(JamesHenry): Further troubleshoot this in CI
|
20
21
|
context.configFiles = context.configFiles ?? [];
|
21
|
-
// Create a Set of all the directories containing eslint configs
|
22
|
-
|
23
|
-
const
|
24
|
-
const
|
22
|
+
// Create a Set of all the directories containing eslint configs, and a
|
23
|
+
// list of globs to exclude from child projects
|
24
|
+
const eslintRoots = new Set();
|
25
|
+
const nestedEslintRootPatterns = [];
|
26
|
+
for (const configFile of context.configFiles) {
|
27
|
+
const eslintRootDir = (0, node_path_1.dirname)(configFile);
|
28
|
+
eslintRoots.add(eslintRootDir);
|
29
|
+
if (eslintRootDir !== configDir && isSubDir(configDir, eslintRootDir)) {
|
30
|
+
nestedEslintRootPatterns.push(`${eslintRootDir}/**/*`);
|
31
|
+
}
|
32
|
+
}
|
33
|
+
const projectFiles = (0, workspace_context_1.globWithWorkspaceContext)(context.workspaceRoot, [
|
25
34
|
'project.json',
|
26
35
|
'package.json',
|
27
36
|
'**/project.json',
|
28
37
|
'**/package.json',
|
29
|
-
].map((f) => (0, node_path_1.join)(configDir, f)))
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
+
].map((f) => (0, node_path_1.join)(configDir, f)), nestedEslintRootPatterns.length ? nestedEslintRootPatterns : undefined);
|
39
|
+
// dedupe and sort project roots by depth for more efficient traversal
|
40
|
+
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));
|
41
|
+
const excludePatterns = dedupedProjectRoots.map((root) => `${root}/**/*`);
|
42
|
+
const ESLint = resolveESLintClass((0, config_file_1.isFlatConfig)(configFilePath));
|
43
|
+
const childProjectRoots = new Set();
|
44
|
+
await Promise.all(dedupedProjectRoots.map(async (childProjectRoot, index) => {
|
45
|
+
// anything after is either a nested project or a sibling project, can be excluded
|
46
|
+
const nestedProjectRootPatterns = excludePatterns.slice(index + 1);
|
47
|
+
// Ignore project roots where the project does not contain any lintable files
|
48
|
+
const lintableFiles = (0, workspace_context_1.globWithWorkspaceContext)(context.workspaceRoot, [(0, node_path_1.join)(childProjectRoot, `**/*.{${options.extensions.join(',')}}`)],
|
49
|
+
// exclude nested eslint roots and nested project roots
|
50
|
+
[...nestedEslintRootPatterns, ...nestedProjectRootPatterns]);
|
51
|
+
const eslint = new ESLint({
|
52
|
+
cwd: (0, node_path_1.join)(context.workspaceRoot, childProjectRoot),
|
53
|
+
});
|
54
|
+
for (const file of lintableFiles) {
|
55
|
+
if (!(await eslint.isPathIgnored((0, node_path_1.join)(context.workspaceRoot, file)))) {
|
56
|
+
childProjectRoots.add(childProjectRoot);
|
57
|
+
break;
|
38
58
|
}
|
39
|
-
root = (0, node_path_1.dirname)(root);
|
40
59
|
}
|
41
|
-
|
42
|
-
|
43
|
-
.filter((dir) => {
|
44
|
-
// Ignore project roots where the project does not contain any lintable files
|
45
|
-
const lintableFiles = (0, workspace_context_1.globWithWorkspaceContext)(context.workspaceRoot, [
|
46
|
-
(0, node_path_1.join)(dir, `**/*.{${options.extensions.join(',')}}`),
|
47
|
-
]);
|
48
|
-
return lintableFiles.length > 0;
|
49
|
-
});
|
50
|
-
const uniqueChildProjectRoots = Array.from(new Set(childProjectRoots));
|
60
|
+
}));
|
61
|
+
const uniqueChildProjectRoots = Array.from(childProjectRoots);
|
51
62
|
return {
|
52
63
|
projects: getProjectsUsingESLintConfig(configFilePath, uniqueChildProjectRoots, options, context),
|
53
64
|
};
|
@@ -72,12 +83,12 @@ function getProjectsUsingESLintConfig(configFilePath, childProjectRoots, options
|
|
72
83
|
eslintConfigs.unshift(rootEslintConfig);
|
73
84
|
}
|
74
85
|
projects[projectRoot] = {
|
75
|
-
targets: buildEslintTargets(eslintConfigs, projectRoot, options, isStandaloneWorkspace),
|
86
|
+
targets: buildEslintTargets(eslintConfigs, projectRoot, context.workspaceRoot, options, isStandaloneWorkspace),
|
76
87
|
};
|
77
88
|
}
|
78
89
|
return projects;
|
79
90
|
}
|
80
|
-
function buildEslintTargets(eslintConfigs, projectRoot, options, isStandaloneWorkspace = false) {
|
91
|
+
function buildEslintTargets(eslintConfigs, projectRoot, workspaceRoot, options, isStandaloneWorkspace = false) {
|
81
92
|
const isRootProject = projectRoot === '.';
|
82
93
|
const targets = {};
|
83
94
|
const targetConfig = {
|
@@ -91,6 +102,9 @@ function buildEslintTargets(eslintConfigs, projectRoot, options, isStandaloneWor
|
|
91
102
|
// Certain lint rules can be impacted by changes to dependencies
|
92
103
|
'^default',
|
93
104
|
...eslintConfigs.map((config) => `{workspaceRoot}/${config}`.replace(`{workspaceRoot}/${projectRoot}`, isRootProject ? '{projectRoot}/' : '{projectRoot}')),
|
105
|
+
...((0, node_fs_1.existsSync)((0, node_path_1.join)(workspaceRoot, projectRoot, '.eslintignore'))
|
106
|
+
? ['{projectRoot}/.eslintignore']
|
107
|
+
: []),
|
94
108
|
'{workspaceRoot}/tools/eslint-rules/**/*',
|
95
109
|
{ externalDependencies: ['eslint'] },
|
96
110
|
],
|
@@ -115,3 +129,30 @@ function normalizeOptions(options) {
|
|
115
129
|
}
|
116
130
|
return options;
|
117
131
|
}
|
132
|
+
function resolveESLintClass(useFlatConfig = false) {
|
133
|
+
try {
|
134
|
+
if (!useFlatConfig) {
|
135
|
+
return require('eslint').ESLint;
|
136
|
+
}
|
137
|
+
return require('eslint/use-at-your-own-risk').FlatESLint;
|
138
|
+
}
|
139
|
+
catch {
|
140
|
+
throw new Error('Unable to find ESLint. Ensure ESLint is installed.');
|
141
|
+
}
|
142
|
+
}
|
143
|
+
/**
|
144
|
+
* Determines if `child` is a subdirectory of `parent`. This is a simplified
|
145
|
+
* version that takes into account that paths are always relative to the
|
146
|
+
* workspace root.
|
147
|
+
*/
|
148
|
+
function isSubDir(parent, child) {
|
149
|
+
if (parent === '.') {
|
150
|
+
return true;
|
151
|
+
}
|
152
|
+
parent = (0, node_path_1.normalize)(parent);
|
153
|
+
child = (0, node_path_1.normalize)(child);
|
154
|
+
if (!parent.endsWith(node_path_1.sep)) {
|
155
|
+
parent += node_path_1.sep;
|
156
|
+
}
|
157
|
+
return child.startsWith(parent);
|
158
|
+
}
|