@nx/eslint-plugin 19.7.0-beta.3 → 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",
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.3",
38
- "@nx/js": "19.7.0-beta.3",
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.3"
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>>;
@@ -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
+ }