@nx/eslint-plugin 19.7.0-beta.2 → 19.7.0-beta.4
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-plugin",
|
|
3
|
-
"version": "19.7.0-beta.
|
|
3
|
+
"version": "19.7.0-beta.4",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "The eslint-plugin package is an ESLint plugin that contains a collection of recommended ESLint rule configurations which you can extend from in your own ESLint configs, as well as an Nx-specific lint rule called enforce-module-boundaries.",
|
|
6
6
|
"repository": {
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
}
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@nx/devkit": "19.7.0-beta.
|
|
38
|
-
"@nx/js": "19.7.0-beta.
|
|
37
|
+
"@nx/devkit": "19.7.0-beta.4",
|
|
38
|
+
"@nx/js": "19.7.0-beta.4",
|
|
39
39
|
"@typescript-eslint/type-utils": "^7.16.0",
|
|
40
40
|
"@typescript-eslint/utils": "^7.16.0",
|
|
41
41
|
"chalk": "^4.1.0",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"jsonc-eslint-parser": "^2.1.0",
|
|
44
44
|
"semver": "^7.5.3",
|
|
45
45
|
"tslib": "^2.3.0",
|
|
46
|
-
"@nrwl/eslint-plugin-nx": "19.7.0-beta.
|
|
46
|
+
"@nrwl/eslint-plugin-nx": "19.7.0-beta.4"
|
|
47
47
|
},
|
|
48
48
|
"publishConfig": {
|
|
49
49
|
"access": "public"
|
|
@@ -7,6 +7,7 @@ type Options = [
|
|
|
7
7
|
depConstraints: DepConstraint[];
|
|
8
8
|
enforceBuildableLibDependency: boolean;
|
|
9
9
|
allowCircularSelfDependency: boolean;
|
|
10
|
+
ignoredCircularDependencies: Array<[string, string]>;
|
|
10
11
|
checkDynamicDependenciesExceptions: string[];
|
|
11
12
|
banTransitiveDependencies: boolean;
|
|
12
13
|
checkNestedExternalImports: boolean;
|
|
@@ -30,6 +30,15 @@ exports.default = utils_1.ESLintUtils.RuleCreator(() => `https://github.com/nrwl
|
|
|
30
30
|
type: 'array',
|
|
31
31
|
items: { type: 'string' },
|
|
32
32
|
},
|
|
33
|
+
ignoredCircularDependencies: {
|
|
34
|
+
type: 'array',
|
|
35
|
+
items: {
|
|
36
|
+
type: 'array',
|
|
37
|
+
items: { type: 'string' },
|
|
38
|
+
minItems: 2,
|
|
39
|
+
maxItems: 2,
|
|
40
|
+
},
|
|
41
|
+
},
|
|
33
42
|
banTransitiveDependencies: { type: 'boolean' },
|
|
34
43
|
checkNestedExternalImports: { type: 'boolean' },
|
|
35
44
|
allow: { type: 'array', items: { type: 'string' } },
|
|
@@ -121,11 +130,12 @@ exports.default = utils_1.ESLintUtils.RuleCreator(() => `https://github.com/nrwl
|
|
|
121
130
|
enforceBuildableLibDependency: false,
|
|
122
131
|
allowCircularSelfDependency: false,
|
|
123
132
|
checkDynamicDependenciesExceptions: [],
|
|
133
|
+
ignoredCircularDependencies: [],
|
|
124
134
|
banTransitiveDependencies: false,
|
|
125
135
|
checkNestedExternalImports: false,
|
|
126
136
|
},
|
|
127
137
|
],
|
|
128
|
-
create(context, [{ allow, buildTargets, depConstraints, enforceBuildableLibDependency, allowCircularSelfDependency, checkDynamicDependenciesExceptions, banTransitiveDependencies, checkNestedExternalImports, },]) {
|
|
138
|
+
create(context, [{ allow, buildTargets, depConstraints, enforceBuildableLibDependency, allowCircularSelfDependency, checkDynamicDependenciesExceptions, ignoredCircularDependencies, banTransitiveDependencies, checkNestedExternalImports, },]) {
|
|
129
139
|
/**
|
|
130
140
|
* Globally cached info about workspace
|
|
131
141
|
*/
|
|
@@ -136,6 +146,7 @@ exports.default = utils_1.ESLintUtils.RuleCreator(() => `https://github.com/nrwl
|
|
|
136
146
|
return {};
|
|
137
147
|
}
|
|
138
148
|
const workspaceLayout = global.workspaceLayout;
|
|
149
|
+
const expandedIgnoreCircularDependencies = (0, graph_utils_1.expandIgnoredCircularDependencies)(ignoredCircularDependencies, projectGraph);
|
|
139
150
|
function run(node) {
|
|
140
151
|
// Ignoring ExportNamedDeclarations like:
|
|
141
152
|
// export class Foo {}
|
|
@@ -236,7 +247,8 @@ exports.default = utils_1.ESLintUtils.RuleCreator(() => `https://github.com/nrwl
|
|
|
236
247
|
}
|
|
237
248
|
// we only allow relative paths within the same project
|
|
238
249
|
// and if it's not a secondary entrypoint in an angular lib
|
|
239
|
-
if (sourceProject === targetProject
|
|
250
|
+
if (sourceProject === targetProject &&
|
|
251
|
+
!(0, graph_utils_1.circularPathHasPair)([sourceProject, targetProject], expandedIgnoreCircularDependencies)) {
|
|
240
252
|
if (!allowCircularSelfDependency &&
|
|
241
253
|
!(0, fileutils_1.isRelativePath)(imp) &&
|
|
242
254
|
!(0, runtime_lint_utils_1.belongsToDifferentNgEntryPoint)(imp, sourceFilePath, sourceProject.data.root)) {
|
|
@@ -320,7 +332,8 @@ exports.default = utils_1.ESLintUtils.RuleCreator(() => `https://github.com/nrwl
|
|
|
320
332
|
// check constraints between libs and apps
|
|
321
333
|
// check for circular dependency
|
|
322
334
|
const circularPath = (0, graph_utils_1.checkCircularPath)(projectGraph, sourceProject, targetProject);
|
|
323
|
-
if (circularPath.length !== 0
|
|
335
|
+
if (circularPath.length !== 0 &&
|
|
336
|
+
!(0, graph_utils_1.circularPathHasPair)(circularPath, expandedIgnoreCircularDependencies)) {
|
|
324
337
|
const circularFilePath = (0, graph_utils_1.findFilesInCircularPath)(projectFileMap, circularPath);
|
|
325
338
|
// spacer text used for indirect dependencies when printing one line per file.
|
|
326
339
|
// without this, we can end up with a very long line that does not display well in the terminal.
|
|
@@ -2,5 +2,7 @@ import type { FileData, ProjectFileMap, ProjectGraph, ProjectGraphProjectNode }
|
|
|
2
2
|
export declare function getPath(graph: ProjectGraph, sourceProjectName: string, targetProjectName: string): Array<ProjectGraphProjectNode>;
|
|
3
3
|
export declare function pathExists(graph: ProjectGraph, sourceProjectName: string, targetProjectName: string): boolean;
|
|
4
4
|
export declare function checkCircularPath(graph: ProjectGraph, sourceProject: ProjectGraphProjectNode, targetProject: ProjectGraphProjectNode): ProjectGraphProjectNode[];
|
|
5
|
+
export declare function circularPathHasPair(circularPath: ProjectGraphProjectNode[], ignored: Map<string, Set<string>>): boolean;
|
|
5
6
|
export declare function findFilesInCircularPath(projectFileMap: ProjectFileMap, circularPath: ProjectGraphProjectNode[]): Array<string[]>;
|
|
6
7
|
export declare function findFilesWithDynamicImports(projectFileMap: ProjectFileMap, sourceProjectName: string, targetProjectName: string): FileData[];
|
|
8
|
+
export declare function expandIgnoredCircularDependencies(ignoredCircularDependencies: Array<[string, string]>, projectGraph: ProjectGraph): Map<string, Set<string>>;
|
package/src/utils/graph-utils.js
CHANGED
|
@@ -3,9 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.getPath = getPath;
|
|
4
4
|
exports.pathExists = pathExists;
|
|
5
5
|
exports.checkCircularPath = checkCircularPath;
|
|
6
|
+
exports.circularPathHasPair = circularPathHasPair;
|
|
6
7
|
exports.findFilesInCircularPath = findFilesInCircularPath;
|
|
7
8
|
exports.findFilesWithDynamicImports = findFilesWithDynamicImports;
|
|
9
|
+
exports.expandIgnoredCircularDependencies = expandIgnoredCircularDependencies;
|
|
8
10
|
const project_graph_1 = require("nx/src/config/project-graph");
|
|
11
|
+
const find_matching_projects_1 = require("nx/src/utils/find-matching-projects");
|
|
9
12
|
const reach = {
|
|
10
13
|
graph: null,
|
|
11
14
|
matrix: null,
|
|
@@ -103,6 +106,19 @@ function checkCircularPath(graph, sourceProject, targetProject) {
|
|
|
103
106
|
return [];
|
|
104
107
|
return getPath(graph, targetProject.name, sourceProject.name);
|
|
105
108
|
}
|
|
109
|
+
function circularPathHasPair(circularPath, ignored) {
|
|
110
|
+
if (circularPath.length < 2)
|
|
111
|
+
return false;
|
|
112
|
+
for (let i = 0; i < circularPath.length - 1; i++) {
|
|
113
|
+
const dependencyIsIgnored = ignored
|
|
114
|
+
.get(circularPath[i].name)
|
|
115
|
+
?.has(circularPath[i + 1].name);
|
|
116
|
+
if (dependencyIsIgnored) {
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
106
122
|
function findFilesInCircularPath(projectFileMap, circularPath) {
|
|
107
123
|
const filePathChain = [];
|
|
108
124
|
for (let i = 0; i < circularPath.length - 1; i++) {
|
|
@@ -126,3 +142,29 @@ function findFilesWithDynamicImports(projectFileMap, sourceProjectName, targetPr
|
|
|
126
142
|
});
|
|
127
143
|
return files;
|
|
128
144
|
}
|
|
145
|
+
function expandIgnoredCircularDependencies(ignoredCircularDependencies, projectGraph) {
|
|
146
|
+
const allowed = new Map();
|
|
147
|
+
for (const [a, b] of ignoredCircularDependencies) {
|
|
148
|
+
const setA = new Set((0, find_matching_projects_1.findMatchingProjects)([a], projectGraph.nodes));
|
|
149
|
+
const setB = new Set((0, find_matching_projects_1.findMatchingProjects)([b], projectGraph.nodes));
|
|
150
|
+
for (const projectA of setA) {
|
|
151
|
+
if (!allowed.has(projectA)) {
|
|
152
|
+
allowed.set(projectA, new Set());
|
|
153
|
+
}
|
|
154
|
+
const currentSetA = allowed.get(projectA);
|
|
155
|
+
for (const projectB of setB) {
|
|
156
|
+
currentSetA.add(projectB);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
for (const projectB of setB) {
|
|
160
|
+
if (!allowed.has(projectB)) {
|
|
161
|
+
allowed.set(projectB, new Set());
|
|
162
|
+
}
|
|
163
|
+
const currentSetB = allowed.get(projectB);
|
|
164
|
+
for (const projectA of setA) {
|
|
165
|
+
currentSetB.add(projectA);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return allowed;
|
|
170
|
+
}
|