@nx/eslint-plugin 0.0.0-pr-22179-271588f

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.
Files changed (48) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +68 -0
  3. package/migrations.json +18 -0
  4. package/package.json +54 -0
  5. package/src/configs/angular-template.d.ts +20 -0
  6. package/src/configs/angular-template.js +21 -0
  7. package/src/configs/angular.d.ts +25 -0
  8. package/src/configs/angular.js +27 -0
  9. package/src/configs/javascript.d.ts +62 -0
  10. package/src/configs/javascript.js +70 -0
  11. package/src/configs/react-base.d.ts +112 -0
  12. package/src/configs/react-base.js +141 -0
  13. package/src/configs/react-jsx.d.ts +71 -0
  14. package/src/configs/react-jsx.js +64 -0
  15. package/src/configs/react-tmp.d.ts +12 -0
  16. package/src/configs/react-tmp.js +17 -0
  17. package/src/configs/react-typescript.d.ts +40 -0
  18. package/src/configs/react-typescript.js +54 -0
  19. package/src/configs/typescript.d.ts +44 -0
  20. package/src/configs/typescript.js +53 -0
  21. package/src/constants.d.ts +13 -0
  22. package/src/constants.js +18 -0
  23. package/src/index.d.ts +1 -0
  24. package/src/index.js +34 -0
  25. package/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.d.ts +2 -0
  26. package/src/migrations/update-16-0-0-add-nx-packages/update-16-0-0-add-nx-packages.js +43 -0
  27. package/src/migrations/update-17-2-6-rename-workspace-rules/rename-workspace-rules.d.ts +2 -0
  28. package/src/migrations/update-17-2-6-rename-workspace-rules/rename-workspace-rules.js +29 -0
  29. package/src/resolve-workspace-rules.d.ts +4 -0
  30. package/src/resolve-workspace-rules.js +38 -0
  31. package/src/rules/dependency-checks.d.ts +17 -0
  32. package/src/rules/dependency-checks.js +240 -0
  33. package/src/rules/enforce-module-boundaries.d.ts +18 -0
  34. package/src/rules/enforce-module-boundaries.js +480 -0
  35. package/src/rules/nx-plugin-checks.d.ts +21 -0
  36. package/src/rules/nx-plugin-checks.js +392 -0
  37. package/src/utils/ast-utils.d.ts +12 -0
  38. package/src/utils/ast-utils.js +220 -0
  39. package/src/utils/config-utils.d.ts +6 -0
  40. package/src/utils/config-utils.js +18 -0
  41. package/src/utils/graph-utils.d.ts +6 -0
  42. package/src/utils/graph-utils.js +129 -0
  43. package/src/utils/package-json-utils.d.ts +4 -0
  44. package/src/utils/package-json-utils.js +37 -0
  45. package/src/utils/project-graph-utils.d.ts +10 -0
  46. package/src/utils/project-graph-utils.js +53 -0
  47. package/src/utils/runtime-lint-utils.d.ts +88 -0
  48. package/src/utils/runtime-lint-utils.js +365 -0
@@ -0,0 +1,240 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RULE_NAME = void 0;
4
+ const path_1 = require("path");
5
+ const semver_1 = require("semver");
6
+ const devkit_1 = require("@nx/devkit");
7
+ const find_npm_dependencies_1 = require("@nx/js/src/utils/find-npm-dependencies");
8
+ const project_graph_utils_1 = require("../utils/project-graph-utils");
9
+ const runtime_lint_utils_1 = require("../utils/runtime-lint-utils");
10
+ const package_json_utils_1 = require("../utils/package-json-utils");
11
+ const utils_1 = require("@typescript-eslint/utils");
12
+ exports.RULE_NAME = 'dependency-checks';
13
+ exports.default = utils_1.ESLintUtils.RuleCreator(() => `https://github.com/nrwl/nx/blob/${devkit_1.NX_VERSION}/docs/generated/packages/eslint-plugin/documents/dependency-checks.md`)({
14
+ name: exports.RULE_NAME,
15
+ meta: {
16
+ type: 'suggestion',
17
+ docs: {
18
+ description: `Checks dependencies in project's package.json for version mismatches`,
19
+ recommended: 'recommended',
20
+ },
21
+ fixable: 'code',
22
+ schema: [
23
+ {
24
+ type: 'object',
25
+ properties: {
26
+ buildTargets: { type: 'array', items: { type: 'string' } },
27
+ ignoredDependencies: { type: 'array', items: { type: 'string' } },
28
+ ignoredFiles: { type: 'array', items: { type: 'string' } },
29
+ checkMissingDependencies: { type: 'boolean' },
30
+ checkObsoleteDependencies: { type: 'boolean' },
31
+ checkVersionMismatches: { type: 'boolean' },
32
+ includeTransitiveDependencies: { type: 'boolean' },
33
+ useLocalPathsForWorkspaceDependencies: { type: 'boolean' },
34
+ },
35
+ additionalProperties: false,
36
+ },
37
+ ],
38
+ messages: {
39
+ missingDependency: `The "{{projectName}}" project uses the following packages, but they are missing from "{{section}}":{{packageNames}}`,
40
+ obsoleteDependency: `The "{{packageName}}" package is not used by "{{projectName}}" project.`,
41
+ versionMismatch: `The version specifier does not contain the installed version of "{{packageName}}" package: {{version}}.`,
42
+ missingDependencySection: `Dependency sections are missing from the "package.json" but following dependencies were detected:{{dependencies}}`,
43
+ },
44
+ },
45
+ defaultOptions: [
46
+ {
47
+ buildTargets: ['build'],
48
+ checkMissingDependencies: true,
49
+ checkObsoleteDependencies: true,
50
+ checkVersionMismatches: true,
51
+ ignoredDependencies: [],
52
+ ignoredFiles: [],
53
+ includeTransitiveDependencies: false,
54
+ useLocalPathsForWorkspaceDependencies: false,
55
+ },
56
+ ],
57
+ create(context, [{ buildTargets, ignoredDependencies, ignoredFiles, checkMissingDependencies, checkObsoleteDependencies, checkVersionMismatches, includeTransitiveDependencies, useLocalPathsForWorkspaceDependencies, },]) {
58
+ if (!context.parserServices.isJSON) {
59
+ return {};
60
+ }
61
+ const fileName = (0, devkit_1.normalizePath)(context.getFilename());
62
+ // support only package.json
63
+ if (!fileName.endsWith('/package.json')) {
64
+ return {};
65
+ }
66
+ const sourceFilePath = (0, runtime_lint_utils_1.getSourceFilePath)(fileName, devkit_1.workspaceRoot);
67
+ const { projectGraph, projectRootMappings, projectFileMap } = (0, project_graph_utils_1.readProjectGraph)(exports.RULE_NAME);
68
+ if (!projectGraph) {
69
+ return {};
70
+ }
71
+ const sourceProject = (0, runtime_lint_utils_1.findProject)(projectGraph, projectRootMappings, sourceFilePath);
72
+ // check if source project exists
73
+ if (!sourceProject) {
74
+ return {};
75
+ }
76
+ // check if library has a build target
77
+ const buildTarget = buildTargets.find((t) => sourceProject.data.targets?.[t]);
78
+ if (!buildTarget) {
79
+ return {};
80
+ }
81
+ const rootPackageJson = (0, package_json_utils_1.getPackageJson)((0, path_1.join)(devkit_1.workspaceRoot, 'package.json'));
82
+ const npmDependencies = (0, find_npm_dependencies_1.findNpmDependencies)(devkit_1.workspaceRoot, sourceProject, projectGraph, projectFileMap, buildTarget, // TODO: What if child library has a build target different from the parent?
83
+ {
84
+ includeTransitiveDependencies,
85
+ ignoredFiles,
86
+ useLocalPathsForWorkspaceDependencies,
87
+ });
88
+ const expectedDependencyNames = Object.keys(npmDependencies);
89
+ const projPackageJsonPath = (0, path_1.join)(devkit_1.workspaceRoot, sourceProject.data.root, 'package.json');
90
+ const projPackageJsonDeps = (0, package_json_utils_1.getProductionDependencies)(projPackageJsonPath);
91
+ const rootPackageJsonDeps = (0, package_json_utils_1.getAllDependencies)(rootPackageJson);
92
+ function validateMissingDependencies(node) {
93
+ if (!checkMissingDependencies) {
94
+ return;
95
+ }
96
+ const missingDeps = expectedDependencyNames.filter((d) => !projPackageJsonDeps[d] && !ignoredDependencies.includes(d));
97
+ if (missingDeps.length) {
98
+ context.report({
99
+ node: node,
100
+ messageId: 'missingDependency',
101
+ data: {
102
+ packageNames: missingDeps.map((d) => `\n - ${d}`).join(''),
103
+ section: node.key.value,
104
+ projectName: sourceProject.name,
105
+ },
106
+ fix(fixer) {
107
+ missingDeps.forEach((d) => {
108
+ projPackageJsonDeps[d] =
109
+ rootPackageJsonDeps[d] || npmDependencies[d];
110
+ });
111
+ const deps = node.value.properties;
112
+ const mappedDeps = missingDeps
113
+ .map((d) => `\n "${d}": "${projPackageJsonDeps[d]}"`)
114
+ .join(',');
115
+ if (deps.length) {
116
+ return fixer.insertTextAfter(deps[deps.length - 1], `,${mappedDeps}`);
117
+ }
118
+ else {
119
+ return fixer.insertTextAfterRange([node.value.range[0] + 1, node.value.range[1] - 1], `${mappedDeps}\n `);
120
+ }
121
+ },
122
+ });
123
+ }
124
+ }
125
+ function validateVersionMatchesInstalled(node, packageName, packageRange) {
126
+ if (!checkVersionMismatches) {
127
+ return;
128
+ }
129
+ if (npmDependencies[packageName].startsWith('file:') ||
130
+ packageRange.startsWith('file:') ||
131
+ npmDependencies[packageName] === '*' ||
132
+ packageRange === '*' ||
133
+ (0, semver_1.satisfies)(npmDependencies[packageName], packageRange, {
134
+ includePrerelease: true,
135
+ })) {
136
+ return;
137
+ }
138
+ context.report({
139
+ node: node,
140
+ messageId: 'versionMismatch',
141
+ data: {
142
+ packageName: packageName,
143
+ version: npmDependencies[packageName],
144
+ },
145
+ fix: (fixer) => fixer.replaceText(node, `"${packageName}": "${rootPackageJsonDeps[packageName] || npmDependencies[packageName]}"`),
146
+ });
147
+ }
148
+ function reportObsoleteDependency(node, packageName) {
149
+ if (!checkObsoleteDependencies) {
150
+ return;
151
+ }
152
+ context.report({
153
+ node: node,
154
+ messageId: 'obsoleteDependency',
155
+ data: { packageName: packageName, projectName: sourceProject.name },
156
+ fix: (fixer) => {
157
+ const isLastProperty = node.parent.properties[node.parent.properties.length - 1] === node;
158
+ const index = node.parent.properties.findIndex((n) => n === node);
159
+ if (index > 0) {
160
+ const previousNode = node.parent.properties[index - 1];
161
+ return fixer.removeRange([
162
+ previousNode.range[1] + (isLastProperty ? 0 : 1),
163
+ node.range[1] + (isLastProperty ? 0 : 1),
164
+ ]);
165
+ }
166
+ else {
167
+ const parent = node.parent;
168
+ // it's the only property
169
+ if (isLastProperty) {
170
+ return fixer.removeRange([
171
+ parent.range[0] + 1,
172
+ parent.range[1] - 1,
173
+ ]);
174
+ }
175
+ else {
176
+ return fixer.removeRange([
177
+ parent.range[0] + 1,
178
+ node.range[1] + 1,
179
+ ]);
180
+ }
181
+ }
182
+ },
183
+ });
184
+ }
185
+ function validateDependenciesSectionExistance(node) {
186
+ if (!expectedDependencyNames.length ||
187
+ !expectedDependencyNames.some((d) => !ignoredDependencies.includes(d))) {
188
+ return;
189
+ }
190
+ if (!node.properties ||
191
+ !node.properties.some((p) => ['dependencies', 'peerDependencies', 'optionalDependencies'].includes(p.key.value))) {
192
+ context.report({
193
+ node: node,
194
+ messageId: 'missingDependencySection',
195
+ data: {
196
+ dependencies: expectedDependencyNames
197
+ .map((d) => `\n- "${d}"`)
198
+ .join(),
199
+ },
200
+ fix: (fixer) => {
201
+ expectedDependencyNames.sort().reduce((acc, d) => {
202
+ acc[d] = rootPackageJsonDeps[d] || npmDependencies[d];
203
+ return acc;
204
+ }, projPackageJsonDeps);
205
+ const dependencies = Object.keys(projPackageJsonDeps)
206
+ .map((d) => `\n "${d}": "${projPackageJsonDeps[d]}"`)
207
+ .join(',');
208
+ if (!node.properties.length) {
209
+ return fixer.replaceText(node, `{\n "dependencies": {${dependencies}\n }\n}`);
210
+ }
211
+ else {
212
+ return fixer.insertTextAfter(node.properties[node.properties.length - 1], `,\n "dependencies": {${dependencies}\n }`);
213
+ }
214
+ },
215
+ });
216
+ }
217
+ }
218
+ return {
219
+ ['JSONExpressionStatement > JSONObjectExpression > JSONProperty[key.value=/^(peer|optional)?dependencies$/i]'](node) {
220
+ validateMissingDependencies(node);
221
+ },
222
+ ['JSONExpressionStatement > JSONObjectExpression > JSONProperty[key.value=/^(peer|optional)?dependencies$/i] > JSONObjectExpression > JSONProperty'](node) {
223
+ const packageName = node.key.value;
224
+ const packageRange = node.value.value;
225
+ if (ignoredDependencies.includes(packageName)) {
226
+ return;
227
+ }
228
+ if (expectedDependencyNames.includes(packageName)) {
229
+ validateVersionMatchesInstalled(node, packageName, packageRange);
230
+ }
231
+ else {
232
+ reportObsoleteDependency(node, packageName);
233
+ }
234
+ },
235
+ ['JSONExpressionStatement > JSONObjectExpression'](node) {
236
+ validateDependenciesSectionExistance(node);
237
+ },
238
+ };
239
+ },
240
+ });
@@ -0,0 +1,18 @@
1
+ import { DepConstraint } from '../utils/runtime-lint-utils';
2
+ import { ESLintUtils } from '@typescript-eslint/utils';
3
+ type Options = [
4
+ {
5
+ allow: string[];
6
+ buildTargets: string[];
7
+ depConstraints: DepConstraint[];
8
+ enforceBuildableLibDependency: boolean;
9
+ allowCircularSelfDependency: boolean;
10
+ checkDynamicDependenciesExceptions: string[];
11
+ banTransitiveDependencies: boolean;
12
+ checkNestedExternalImports: boolean;
13
+ }
14
+ ];
15
+ export type MessageIds = 'noRelativeOrAbsoluteImportsAcrossLibraries' | 'noRelativeOrAbsoluteExternals' | 'noSelfCircularDependencies' | 'noCircularDependencies' | 'noImportsOfApps' | 'noImportsOfE2e' | 'noImportOfNonBuildableLibraries' | 'noImportsOfLazyLoadedLibraries' | 'projectWithoutTagsCannotHaveDependencies' | 'bannedExternalImportsViolation' | 'nestedBannedExternalImportsViolation' | 'noTransitiveDependencies' | 'onlyTagsConstraintViolation' | 'emptyOnlyTagsConstraintViolation' | 'notTagsConstraintViolation';
16
+ export declare const RULE_NAME = "enforce-module-boundaries";
17
+ declare const _default: ESLintUtils.RuleModule<MessageIds, Options, ESLintUtils.RuleListener>;
18
+ export default _default;