@nx/eslint-plugin 23.2.0-beta.1 → 23.2.0-beta.11

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/README.md CHANGED
@@ -7,9 +7,9 @@
7
7
 
8
8
  <div style="text-align: center;">
9
9
 
10
- [![License](https://img.shields.io/npm/l/@nx/workspace.svg?style=flat-square)]()
10
+ [![License](https://img.shields.io/npm/l/@nx/workspace.svg?style=flat-square)](<>)
11
11
  [![NPM Version](https://badge.fury.io/js/nx.svg)](https://www.npmjs.com/package/nx)
12
- [![Semantic Release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg?style=flat-square)]()
12
+ [![Semantic Release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg?style=flat-square)](<>)
13
13
  [![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/)
14
14
  [![Join us on the Official Nx Discord Server](https://img.shields.io/discord/1143497901675401286?label=discord)](https://go.nx.dev/community)
15
15
  [![Nx Sandboxing](https://staging.nx.app/workspaces/62d013ea0852fe0a2df74438/sandbox-badge.svg)](https://nx.dev/docs/features/ci-features/sandboxing)
@@ -0,0 +1,2 @@
1
+ import enforceModuleBoundariesRule from './src/rules/enforce-module-boundaries';
2
+ export declare const enforceModuleBoundaries: typeof enforceModuleBoundariesRule;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.enforceModuleBoundaries = void 0;
4
+ const tslib_1 = require("tslib");
5
+ // Semi-private surface for first-party Nx packages; may change without semver.
6
+ // Rules come from here rather than `./nx`, whose `workspaceRules` initializer
7
+ // compiles the consumer's `tools/eslint-rules` just to reach one rule.
8
+ //
9
+ // Keep the `const` assignment: `export { default as … } from` breaks the ESM
10
+ // named import on Node below 24.14. `internal.spec.ts` pins the shape and
11
+ // explains why.
12
+ const enforce_module_boundaries_1 = tslib_1.__importDefault(require("./src/rules/enforce-module-boundaries"));
13
+ // Keep the annotation: the inferred type names RuleModule via a pnpm store path (TS2883).
14
+ exports.enforceModuleBoundaries = enforce_module_boundaries_1.default;
package/dist/nx.d.ts CHANGED
@@ -1,15 +1,6 @@
1
+ import type { TSESLint } from '@typescript-eslint/utils';
1
2
  declare const plugin: {
2
- configs: {};
3
- rules: {
4
- "enforce-module-boundaries": import("@typescript-eslint/utils/ts-eslint").RuleModule<import("./src/rules/enforce-module-boundaries").MessageIds, import("./src/rules/enforce-module-boundaries").Options, unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
5
- name: string;
6
- };
7
- "nx-plugin-checks": import("@typescript-eslint/utils/ts-eslint").RuleModule<import("./src/rules/nx-plugin-checks").MessageIds, import("./src/rules/nx-plugin-checks").Options, unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
8
- name: string;
9
- };
10
- "dependency-checks": import("@typescript-eslint/utils/ts-eslint").RuleModule<import("./src/rules/dependency-checks").MessageIds, import("./src/rules/dependency-checks").Options, unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
11
- name: string;
12
- };
13
- };
3
+ configs: Record<string, unknown>;
4
+ rules: Record<string, TSESLint.RuleModule<string, unknown[]>>;
14
5
  };
15
6
  export default plugin;
package/dist/nx.js CHANGED
@@ -5,6 +5,7 @@ const resolve_workspace_rules_1 = require("./src/resolve-workspace-rules");
5
5
  const dependency_checks_1 = tslib_1.__importStar(require("./src/rules/dependency-checks"));
6
6
  const enforce_module_boundaries_1 = tslib_1.__importStar(require("./src/rules/enforce-module-boundaries"));
7
7
  const nx_plugin_checks_1 = tslib_1.__importStar(require("./src/rules/nx-plugin-checks"));
8
+ // Keep the annotation: the inferred type names RuleModule via a pnpm store path (TS2883).
8
9
  const plugin = {
9
10
  configs: {},
10
11
  rules: {
@@ -1,3 +1,4 @@
1
+ import type { TSESLint } from '@typescript-eslint/utils';
1
2
  import { loadWorkspaceRules } from './resolve-workspace-rules';
2
3
  declare const configs: {
3
4
  typescript: {
@@ -272,17 +273,7 @@ declare const configs: {
272
273
  readonly "flat/angular": typeof import('./flat-configs/angular').default;
273
274
  readonly "flat/angular-template": typeof import('./flat-configs/angular-template').default;
274
275
  };
275
- declare const rules: {
276
- "enforce-module-boundaries": import("@typescript-eslint/utils/ts-eslint").RuleModule<import("./rules/enforce-module-boundaries").MessageIds, import("./rules/enforce-module-boundaries").Options, unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
277
- name: string;
278
- };
279
- "nx-plugin-checks": import("@typescript-eslint/utils/ts-eslint").RuleModule<import("./rules/nx-plugin-checks").MessageIds, import("./rules/nx-plugin-checks").Options, unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
280
- name: string;
281
- };
282
- "dependency-checks": import("@typescript-eslint/utils/ts-eslint").RuleModule<import("./rules/dependency-checks").MessageIds, import("./rules/dependency-checks").Options, unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
283
- name: string;
284
- };
285
- };
276
+ declare const rules: Record<string, TSESLint.RuleModule<string, unknown[]>>;
286
277
  declare const _default: {
287
278
  configs: {
288
279
  typescript: {
@@ -557,17 +548,7 @@ declare const _default: {
557
548
  readonly "flat/angular": typeof import('./flat-configs/angular').default;
558
549
  readonly "flat/angular-template": typeof import('./flat-configs/angular-template').default;
559
550
  };
560
- rules: {
561
- "enforce-module-boundaries": import("@typescript-eslint/utils/ts-eslint").RuleModule<import("./rules/enforce-module-boundaries").MessageIds, import("./rules/enforce-module-boundaries").Options, unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
562
- name: string;
563
- };
564
- "nx-plugin-checks": import("@typescript-eslint/utils/ts-eslint").RuleModule<import("./rules/nx-plugin-checks").MessageIds, import("./rules/nx-plugin-checks").Options, unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
565
- name: string;
566
- };
567
- "dependency-checks": import("@typescript-eslint/utils/ts-eslint").RuleModule<import("./rules/dependency-checks").MessageIds, import("./rules/dependency-checks").Options, unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
568
- name: string;
569
- };
570
- };
551
+ rules: Record<string, TSESLint.RuleModule<string, unknown[], unknown, TSESLint.RuleListener>>;
571
552
  };
572
553
  export default _default;
573
554
  export { configs, rules, loadWorkspaceRules };
package/dist/src/index.js CHANGED
@@ -56,6 +56,7 @@ const configs = {
56
56
  },
57
57
  };
58
58
  exports.configs = configs;
59
+ // Keep the annotation: the inferred type names RuleModule via a pnpm store path (TS2883).
59
60
  const rules = {
60
61
  [enforce_module_boundaries_1.RULE_NAME]: enforce_module_boundaries_1.default,
61
62
  [nx_plugin_checks_1.RULE_NAME]: nx_plugin_checks_1.default,
@@ -112,7 +112,6 @@ exports.default = utils_1.ESLintUtils.RuleCreator(() => `https://github.com/nrwl
112
112
  const projPackageJsonDeps = (0, package_json_utils_1.getProductionDependencies)(packageJson);
113
113
  const rootPackageJsonDeps = (0, package_json_utils_1.getAllDependencies)(rootPackageJson);
114
114
  const catalogManager = (0, internal_1.getCatalogManager)(devkit_1.workspaceRoot);
115
- const catalogDefs = catalogManager?.getCatalogDefinitions(devkit_1.workspaceRoot);
116
115
  function catalogEntryMatchesInstalled(catalogVersionSpec, installedVersion) {
117
116
  if (installedVersion === '*') {
118
117
  return true;
@@ -126,29 +125,7 @@ exports.default = utils_1.ESLintUtils.RuleCreator(() => `https://github.com/nrwl
126
125
  });
127
126
  }
128
127
  function getCatalogVersionForPackage(packageName) {
129
- if (!catalogDefs) {
130
- return null;
131
- }
132
- const matches = [];
133
- // Check default catalog — `catalog` takes precedence over `catalogs.default`.
134
- // Both existing simultaneously is a pnpm error caught by validateCatalogReference.
135
- const defaultEntry = catalogDefs.catalog?.[packageName] ??
136
- catalogDefs.catalogs?.default?.[packageName];
137
- if (defaultEntry) {
138
- matches.push({ catalogRef: 'catalog:', versionSpec: defaultEntry });
139
- }
140
- // Check named catalogs (skip "default" — handled above)
141
- if (catalogDefs.catalogs) {
142
- for (const [name, entries] of Object.entries(catalogDefs.catalogs)) {
143
- if (name === 'default' || !entries?.[packageName]) {
144
- continue;
145
- }
146
- matches.push({
147
- catalogRef: `catalog:${name}`,
148
- versionSpec: entries[packageName],
149
- });
150
- }
151
- }
128
+ const matches = catalogManager?.getCatalogReferencesForPackage(devkit_1.workspaceRoot, packageName) ?? [];
152
129
  if (!matches.length) {
153
130
  return null;
154
131
  }
@@ -4,13 +4,12 @@ exports.RULE_NAME = void 0;
4
4
  const devkit_1 = require("@nx/devkit");
5
5
  const utils_1 = require("@typescript-eslint/utils");
6
6
  const internal_1 = require("@nx/js/internal");
7
- const fileutils_1 = require("nx/src/utils/fileutils");
8
7
  const path_1 = require("path");
9
8
  const ast_utils_1 = require("../utils/ast-utils");
10
9
  const graph_utils_1 = require("../utils/graph-utils");
11
10
  const project_graph_utils_1 = require("../utils/project-graph-utils");
12
11
  const runtime_lint_utils_1 = require("../utils/runtime-lint-utils");
13
- const project_graph_1 = require("nx/src/config/project-graph");
12
+ const internal_2 = require("@nx/devkit/internal");
14
13
  exports.RULE_NAME = 'enforce-module-boundaries';
15
14
  exports.default = utils_1.ESLintUtils.RuleCreator(() => `https://github.com/nrwl/nx/blob/${devkit_1.NX_VERSION}/docs/generated/packages/eslint-plugin/documents/enforce-module-boundaries.md`)({
16
15
  name: exports.RULE_NAME,
@@ -236,7 +235,7 @@ exports.default = utils_1.ESLintUtils.RuleCreator(() => `https://github.com/nrwl
236
235
  (0, runtime_lint_utils_1.findProjectUsingImport)(projectGraph, targetProjectLocator, sourceFilePath, imp);
237
236
  if (!targetProject) {
238
237
  // non-project imports cannot use relative or absolute paths
239
- if ((0, fileutils_1.isRelativePath)(imp) || imp.startsWith('/')) {
238
+ if ((0, internal_2.isRelativePath)(imp) || imp.startsWith('/')) {
240
239
  context.report({
241
240
  node,
242
241
  messageId: 'noRelativeOrAbsoluteExternals',
@@ -264,7 +263,7 @@ exports.default = utils_1.ESLintUtils.RuleCreator(() => `https://github.com/nrwl
264
263
  if (sourceProject === targetProject &&
265
264
  !(0, graph_utils_1.circularPathHasPair)([sourceProject, targetProject], expandedIgnoreCircularDependencies)) {
266
265
  if (!allowCircularSelfDependency &&
267
- !(0, fileutils_1.isRelativePath)(imp) &&
266
+ !(0, internal_2.isRelativePath)(imp) &&
268
267
  !(0, runtime_lint_utils_1.belongsToDifferentEntryPoint)(imp, sourceFilePath, sourceProject.data.root)) {
269
268
  context.report({
270
269
  node,
@@ -343,7 +342,7 @@ exports.default = utils_1.ESLintUtils.RuleCreator(() => `https://github.com/nrwl
343
342
  }
344
343
  return;
345
344
  }
346
- if (!(0, project_graph_1.isProjectGraphProjectNode)(targetProject)) {
345
+ if (!(0, internal_2.isProjectGraphProjectNode)(targetProject)) {
347
346
  return;
348
347
  }
349
348
  targetProject = targetProject;
@@ -11,7 +11,7 @@ export type Options = [
11
11
  tsConfig?: string;
12
12
  }
13
13
  ];
14
- export type MessageIds = 'missingRequiredSchema' | 'invalidSchemaPath' | 'missingImplementation' | 'invalidImplementationPath' | 'invalidImplementationModule' | 'unableToReadImplementationExports' | 'invalidPromptPath' | 'invalidVersion' | 'missingVersion' | 'noGeneratorsOrSchematicsFound' | 'noExecutorsOrBuildersFound' | 'valueShouldBeObject';
14
+ export type MessageIds = 'missingRequiredSchema' | 'invalidSchemaPath' | 'missingImplementation' | 'invalidImplementationPath' | 'invalidImplementationModule' | 'unableToReadImplementationExports' | 'invalidPromptPath' | 'invalidVersion' | 'missingVersion' | 'noGeneratorsOrSchematicsFound' | 'noExecutorsOrBuildersFound' | 'valueShouldBeObject' | 'duplicateKey';
15
15
  export declare const RULE_NAME = "nx-plugin-checks";
16
16
  declare const _default: TSESLint.RuleModule<MessageIds, Options, unknown, TSESLint.RuleListener> & {
17
17
  name: string;
@@ -23,5 +23,12 @@ export declare function validateEntry(baseNode: AST.JSONObjectExpression, key: s
23
23
  export declare function validateImplementationNode(implementationNode: AST.JSONProperty, key: string, context: TSESLint.RuleContext<MessageIds, Options>, projects: Record<string, ProjectConfiguration>): void;
24
24
  export declare function validatePromptNode(promptNode: AST.JSONProperty, key: string, context: TSESLint.RuleContext<MessageIds, Options>): void;
25
25
  export declare function validatePackageGroup(baseNode: AST.JSONObjectExpression, context: TSESLint.RuleContext<MessageIds, Options>): void;
26
+ /**
27
+ * A duplicate key anywhere in these manifests silently drops data:
28
+ * JSON parsers keep only the last occurrence, so a duplicated generator,
29
+ * executor, or migration entry key discards the earlier definition with no
30
+ * error at runtime.
31
+ */
32
+ export declare function validateNoDuplicateKeys(node: AST.JSONObjectExpression | AST.JSONArrayExpression, context: TSESLint.RuleContext<MessageIds, Options>): void;
26
33
  export declare function validateVersionJsonExpression(node: AST.JSONExpression, context: TSESLint.RuleContext<MessageIds, Options>): string | boolean;
27
34
  export declare function checkIfIdentifierIsFunction(filePath: string, identifier: string): boolean;
@@ -7,6 +7,7 @@ exports.validateEntry = validateEntry;
7
7
  exports.validateImplementationNode = validateImplementationNode;
8
8
  exports.validatePromptNode = validatePromptNode;
9
9
  exports.validatePackageGroup = validatePackageGroup;
10
+ exports.validateNoDuplicateKeys = validateNoDuplicateKeys;
10
11
  exports.validateVersionJsonExpression = validateVersionJsonExpression;
11
12
  exports.checkIfIdentifierIsFunction = checkIfIdentifierIsFunction;
12
13
  const tslib_1 = require("tslib");
@@ -82,6 +83,7 @@ exports.default = utils_1.ESLintUtils.RuleCreator(() => ``)({
82
83
  missingImplementation: '{{ key }}: Missing required property - `implementation`',
83
84
  invalidPromptPath: '{{ key }}: Prompt path should point to a valid file',
84
85
  missingVersion: '{{ key }}: Missing required property - `version`',
86
+ duplicateKey: '{{ key }}: Duplicate key. JSON parsers keep only the last occurrence, silently dropping the earlier one',
85
87
  },
86
88
  },
87
89
  defaultOptions: [DEFAULT_OPTIONS],
@@ -109,6 +111,7 @@ exports.default = utils_1.ESLintUtils.RuleCreator(() => ``)({
109
111
  }
110
112
  return {
111
113
  ['JSONExpressionStatement > JSONObjectExpression'](node) {
114
+ validateNoDuplicateKeys(node, context);
112
115
  if (sourceFilePath === generatorsJson) {
113
116
  checkCollectionFileNode(node, 'generator', context, projects);
114
117
  }
@@ -425,6 +428,43 @@ function validatePackageGroup(baseNode, context) {
425
428
  }
426
429
  }
427
430
  }
431
+ /**
432
+ * A duplicate key anywhere in these manifests silently drops data:
433
+ * JSON parsers keep only the last occurrence, so a duplicated generator,
434
+ * executor, or migration entry key discards the earlier definition with no
435
+ * error at runtime.
436
+ */
437
+ function validateNoDuplicateKeys(node, context) {
438
+ if (node.type === 'JSONObjectExpression') {
439
+ const seen = new Set();
440
+ for (const property of node.properties) {
441
+ const key = property.key.type === 'JSONLiteral'
442
+ ? String(property.key.value)
443
+ : property.key.name;
444
+ if (seen.has(key)) {
445
+ context.report({
446
+ messageId: 'duplicateKey',
447
+ data: { key },
448
+ node: property.key,
449
+ });
450
+ }
451
+ seen.add(key);
452
+ if (property.value.type === 'JSONObjectExpression' ||
453
+ property.value.type === 'JSONArrayExpression') {
454
+ validateNoDuplicateKeys(property.value, context);
455
+ }
456
+ }
457
+ }
458
+ else {
459
+ for (const element of node.elements) {
460
+ if (element &&
461
+ (element.type === 'JSONObjectExpression' ||
462
+ element.type === 'JSONArrayExpression')) {
463
+ validateNoDuplicateKeys(element, context);
464
+ }
465
+ }
466
+ }
467
+ }
428
468
  function validateVersionJsonExpression(node, context) {
429
469
  return (node &&
430
470
  node.type === 'JSONLiteral' &&
@@ -7,8 +7,8 @@ exports.circularPathHasPair = circularPathHasPair;
7
7
  exports.findFilesInCircularPath = findFilesInCircularPath;
8
8
  exports.findFilesWithDynamicImports = findFilesWithDynamicImports;
9
9
  exports.expandIgnoredCircularDependencies = expandIgnoredCircularDependencies;
10
- const project_graph_1 = require("nx/src/config/project-graph");
11
- const find_matching_projects_1 = require("nx/src/utils/find-matching-projects");
10
+ const devkit_1 = require("@nx/devkit");
11
+ const internal_1 = require("@nx/devkit/internal");
12
12
  const reach = {
13
13
  graph: null,
14
14
  matrix: null,
@@ -125,7 +125,7 @@ function findFilesInCircularPath(projectFileMap, circularPath) {
125
125
  const next = circularPath[i + 1].name;
126
126
  const files = projectFileMap[circularPath[i].name] || [];
127
127
  filePathChain.push(files
128
- .filter((file) => file.deps && file.deps.find((d) => (0, project_graph_1.fileDataDepTarget)(d) === next))
128
+ .filter((file) => file.deps && file.deps.find((d) => (0, internal_1.fileDataDepTarget)(d) === next))
129
129
  .map((file) => file.file));
130
130
  }
131
131
  return filePathChain;
@@ -135,8 +135,8 @@ function findFilesWithDynamicImports(projectFileMap, sourceProjectName, targetPr
135
135
  projectFileMap[sourceProjectName].forEach((file) => {
136
136
  if (!file.deps)
137
137
  return;
138
- if (file.deps.some((d) => (0, project_graph_1.fileDataDepTarget)(d) === targetProjectName &&
139
- (0, project_graph_1.fileDataDepType)(d) === project_graph_1.DependencyType.dynamic)) {
138
+ if (file.deps.some((d) => (0, internal_1.fileDataDepTarget)(d) === targetProjectName &&
139
+ (0, internal_1.fileDataDepType)(d) === devkit_1.DependencyType.dynamic)) {
140
140
  files.push(file);
141
141
  }
142
142
  });
@@ -145,8 +145,8 @@ function findFilesWithDynamicImports(projectFileMap, sourceProjectName, targetPr
145
145
  function expandIgnoredCircularDependencies(ignoredCircularDependencies, projectGraph) {
146
146
  const allowed = new Map();
147
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));
148
+ const setA = new Set((0, internal_1.findMatchingProjects)([a], projectGraph.nodes));
149
+ const setB = new Set((0, internal_1.findMatchingProjects)([b], projectGraph.nodes));
150
150
  for (const projectA of setA) {
151
151
  if (!allowed.has(projectA)) {
152
152
  allowed.set(projectA, new Set());
@@ -1,4 +1,4 @@
1
- import type { PackageJson } from 'nx/src/utils/package-json';
1
+ import { type PackageJson } from '@nx/devkit/internal';
2
2
  export declare function getAllDependencies(packageJson: PackageJson): Record<string, string>;
3
3
  export declare function getProductionDependencies(packageJson: PackageJson): Record<string, string>;
4
4
  export declare function getPackageJson(path: string): PackageJson;
@@ -1,6 +1,6 @@
1
1
  import { ProjectFileMap, ProjectGraph } from '@nx/devkit';
2
- import { ProjectRootMappings } from 'nx/src/project-graph/utils/find-project-for-path';
3
2
  import { TargetProjectLocator } from '@nx/js/internal';
3
+ import { ProjectRootMappings } from '@nx/devkit/internal';
4
4
  export declare function ensureGlobalProjectGraph(ruleName: string): void;
5
5
  export declare function readProjectGraph(ruleName: string): {
6
6
  projectGraph: ProjectGraph;
@@ -6,10 +6,8 @@ const tslib_1 = require("tslib");
6
6
  const devkit_1 = require("@nx/devkit");
7
7
  const runtime_lint_utils_1 = require("./runtime-lint-utils");
8
8
  const picocolors_1 = tslib_1.__importDefault(require("picocolors"));
9
- const find_project_for_path_1 = require("nx/src/project-graph/utils/find-project-for-path");
10
- const configuration_1 = require("nx/src/config/configuration");
11
9
  const internal_1 = require("@nx/js/internal");
12
- const nx_deps_cache_1 = require("nx/src/project-graph/nx-deps-cache");
10
+ const internal_2 = require("@nx/devkit/internal");
13
11
  function ensureGlobalProjectGraph(ruleName) {
14
12
  /**
15
13
  * Only reuse graph when running from terminal
@@ -19,7 +17,7 @@ function ensureGlobalProjectGraph(ruleName) {
19
17
  !globalThis.projectRootMappings ||
20
18
  !globalThis.projectFileMap ||
21
19
  !(0, runtime_lint_utils_1.isTerminalRun)()) {
22
- const nxJson = (0, configuration_1.readNxJson)();
20
+ const nxJson = (0, internal_2.readNxJsonFromDisk)();
23
21
  globalThis.workspaceLayout = nxJson.workspaceLayout;
24
22
  /**
25
23
  * Because there are a number of ways in which the rule can be invoked (executor vs ESLint CLI vs IDE Plugin),
@@ -28,8 +26,8 @@ function ensureGlobalProjectGraph(ruleName) {
28
26
  try {
29
27
  const projectGraph = (0, devkit_1.readCachedProjectGraph)();
30
28
  globalThis.projectGraph = projectGraph;
31
- globalThis.projectRootMappings = (0, find_project_for_path_1.createProjectRootMappings)(projectGraph.nodes);
32
- globalThis.projectFileMap = (0, nx_deps_cache_1.readFileMapCache)().fileMap.projectFileMap;
29
+ globalThis.projectRootMappings = (0, internal_2.createProjectRootMappings)(projectGraph.nodes);
30
+ globalThis.projectFileMap = (0, internal_2.readFileMapCache)().fileMap.projectFileMap;
33
31
  globalThis.targetProjectLocator = new internal_1.TargetProjectLocator(projectGraph.nodes, projectGraph.externalNodes);
34
32
  }
35
33
  catch {
@@ -1,7 +1,7 @@
1
1
  import { ProjectGraph, ProjectGraphDependency, ProjectGraphExternalNode, ProjectGraphProjectNode } from '@nx/devkit';
2
2
  import { TargetProjectLocator } from '@nx/js/internal';
3
3
  import { TSESLint, TSESTree } from '@typescript-eslint/utils';
4
- import { ProjectRootMappings } from 'nx/src/project-graph/utils/find-project-for-path';
4
+ import { ProjectRootMappings } from '@nx/devkit/internal';
5
5
  export type Deps = {
6
6
  [projectName: string]: ProjectGraphDependency[];
7
7
  };
@@ -30,9 +30,8 @@ const devkit_1 = require("@nx/devkit");
30
30
  const js_1 = require("@nx/js");
31
31
  const utils_1 = require("@typescript-eslint/utils");
32
32
  const path = tslib_1.__importStar(require("node:path"));
33
- const find_project_for_path_1 = require("nx/src/project-graph/utils/find-project-for-path");
34
- const fileutils_1 = require("nx/src/utils/fileutils");
35
33
  const graph_utils_1 = require("./graph-utils");
34
+ const internal_1 = require("@nx/devkit/internal");
36
35
  function stringifyTags(tags) {
37
36
  return tags.map((t) => `"${t}"`).join(', ');
38
37
  }
@@ -114,7 +113,7 @@ function getTargetProjectBasedOnRelativeImport(imp, projectPath, projectGraph, p
114
113
  return findProject(projectGraph, projectRootMappings, targetFile);
115
114
  }
116
115
  function findProject(projectGraph, projectRootMappings, sourceFilePath) {
117
- return projectGraph.nodes[(0, find_project_for_path_1.findProjectForPath)(sourceFilePath, projectRootMappings)];
116
+ return projectGraph.nodes[(0, internal_1.findProjectForPath)(sourceFilePath, projectRootMappings)];
118
117
  }
119
118
  function isAbsoluteImportIntoAnotherProject(imp, workspaceLayout = { libsDir: 'libs', appsDir: 'apps' }) {
120
119
  return (imp.startsWith(`${workspaceLayout.libsDir}/`) ||
@@ -252,7 +251,7 @@ function isDirectDependency(source, target) {
252
251
  packageExistsInPackageJson(target.data.packageName, source.data.root));
253
252
  }
254
253
  function packageExistsInPackageJson(packageName, projectRoot) {
255
- const content = (0, fileutils_1.readFileIfExisting)(path.join(devkit_1.workspaceRoot, projectRoot, 'package.json'));
254
+ const content = (0, internal_1.readFileIfExisting)(path.join(devkit_1.workspaceRoot, projectRoot, 'package.json'));
256
255
  if (content) {
257
256
  const { dependencies, devDependencies, peerDependencies } = (0, devkit_1.parseJson)(content);
258
257
  if (dependencies && dependencies[packageName]) {
@@ -290,11 +289,24 @@ function hasBuildExecutor(projectGraph, buildTargets = ['build']) {
290
289
  const ESLINT_REGEX = /node_modules.*[\/\\]eslint(?:\.js)?$/;
291
290
  const JEST_REGEX = /node_modules\/.bin\/jest$/; // when we run unit tests in jest
292
291
  const NRWL_CLI_REGEX = /nx[\/\\]dist[\/\\]bin[\/\\]run-executor\.js$/;
292
+ // `@nx/oxlint` runs this rule through Oxlint's JS-plugin bridge, where argv[1]
293
+ // is `node_modules/oxlint/bin/oxlint`. Without this, `ensureGlobalProjectGraph`
294
+ // (project-graph-utils.ts) never memoizes and every linted file re-reads the
295
+ // whole project graph.
296
+ const OXLINT_REGEX = /node_modules.*[\/\\]oxlint(?:\.js)?$/;
297
+ // `oxlint --lsp` is the same binary, and it is how the oxc editor extension
298
+ // starts its server — so the language server matches the regex above and has to
299
+ // be excluded by flag instead. JS plugins do load in LSP mode, so without this
300
+ // the long-lived editor process would pin a graph from startup.
301
+ function isOxlintTerminalRun(argv) {
302
+ return !!argv[1].match(OXLINT_REGEX) && !argv.includes('--lsp');
303
+ }
293
304
  function isTerminalRun() {
294
305
  return (process.argv.length > 1 &&
295
306
  (!!process.argv[1].match(NRWL_CLI_REGEX) ||
296
307
  !!process.argv[1].match(JEST_REGEX) ||
297
308
  !!process.argv[1].match(ESLINT_REGEX) ||
309
+ isOxlintTerminalRun(process.argv) ||
298
310
  !!process.argv[1].endsWith('/bin/jest.js')));
299
311
  }
300
312
  /**
@@ -356,7 +368,7 @@ function getEntryPoint(file, projectRoot) {
356
368
  }
357
369
  // for Angular we need to find closest existing ng-package.json
358
370
  // in order to determine if the file matches the secondary entry point
359
- const ngPackageContent = (0, fileutils_1.readFileIfExisting)(path.join(devkit_1.workspaceRoot, parent, 'ng-package.json'));
371
+ const ngPackageContent = (0, internal_1.readFileIfExisting)(path.join(devkit_1.workspaceRoot, parent, 'ng-package.json'));
360
372
  if (ngPackageContent) {
361
373
  // https://github.com/ng-packagr/ng-packagr/blob/23c718d04eea85e015b4c261310b7bd0c39e5311/src/ng-package.schema.json#L54
362
374
  const entryFile = (0, devkit_1.parseJson)(ngPackageContent)?.lib?.entryFile ?? 'src/public_api.ts';
@@ -367,7 +379,7 @@ function getEntryPoint(file, projectRoot) {
367
379
  return undefined;
368
380
  }
369
381
  function getPackageEntryPoints(projectRoot) {
370
- const packageContent = (0, fileutils_1.readFileIfExisting)(path.join(devkit_1.workspaceRoot, projectRoot, 'package.json'));
382
+ const packageContent = (0, internal_1.readFileIfExisting)(path.join(devkit_1.workspaceRoot, projectRoot, 'package.json'));
371
383
  if (!packageContent) {
372
384
  return [];
373
385
  }
@@ -409,8 +421,8 @@ function parseExports(exports, projectRoot, entryPaths, basePath = '.') {
409
421
  * Returns true if the given project contains MFE config with "exposes:" section
410
422
  */
411
423
  function appIsMFERemote(project) {
412
- const mfeConfig = (0, fileutils_1.readFileIfExisting)(path.join(devkit_1.workspaceRoot, project.data.root, 'module-federation.config.js')) ||
413
- (0, fileutils_1.readFileIfExisting)(path.join(devkit_1.workspaceRoot, project.data.root, 'module-federation.config.ts'));
424
+ const mfeConfig = (0, internal_1.readFileIfExisting)(path.join(devkit_1.workspaceRoot, project.data.root, 'module-federation.config.js')) ||
425
+ (0, internal_1.readFileIfExisting)(path.join(devkit_1.workspaceRoot, project.data.root, 'module-federation.config.ts'));
414
426
  if (mfeConfig) {
415
427
  return !!mfeConfig.match(/('|")?exposes('|")?:/);
416
428
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/eslint-plugin",
3
- "version": "23.2.0-beta.1",
3
+ "version": "23.2.0-beta.11",
4
4
  "private": false,
5
5
  "type": "commonjs",
6
6
  "files": [
@@ -32,6 +32,9 @@
32
32
  "nx": [
33
33
  "dist/nx.d.ts"
34
34
  ],
35
+ "internal": [
36
+ "dist/internal.d.ts"
37
+ ],
35
38
  "react": [
36
39
  "dist/react.d.ts"
37
40
  ],
@@ -68,6 +71,11 @@
68
71
  "types": "./dist/nx.d.ts",
69
72
  "default": "./dist/nx.js"
70
73
  },
74
+ "./internal": {
75
+ "@nx/nx-source": "./internal.ts",
76
+ "types": "./dist/internal.d.ts",
77
+ "default": "./dist/internal.js"
78
+ },
71
79
  "./react": {
72
80
  "@nx/nx-source": "./react.ts",
73
81
  "types": "./dist/react.d.ts",
@@ -101,11 +109,11 @@
101
109
  "picocolors": "^1.1.0",
102
110
  "semver": "^7.6.3",
103
111
  "tslib": "^2.3.0",
104
- "@nx/devkit": "23.2.0-beta.1",
105
- "@nx/js": "23.2.0-beta.1"
112
+ "@nx/js": "23.2.0-beta.11",
113
+ "@nx/devkit": "23.2.0-beta.11"
106
114
  },
107
115
  "devDependencies": {
108
- "nx": "23.2.0-beta.1"
116
+ "nx": "23.2.0-beta.11"
109
117
  },
110
118
  "publishConfig": {
111
119
  "access": "public"