@nx/cypress 23.1.0 → 23.1.2

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.
@@ -6,6 +6,10 @@ export interface CypressE2EConfigSchema {
6
6
  directory?: string;
7
7
  js?: boolean;
8
8
  skipFormat?: boolean;
9
+ enableTypedLinting?: boolean;
10
+ /**
11
+ * @deprecated Use `enableTypedLinting` instead. This option will be removed in Nx v24.
12
+ */
9
13
  setParserOptionsProject?: boolean;
10
14
  skipPackageJson?: boolean;
11
15
  bundler?: 'webpack' | 'vite' | 'none';
@@ -60,11 +60,17 @@
60
60
  "default": false,
61
61
  "x-priority": "internal"
62
62
  },
63
- "setParserOptionsProject": {
63
+ "enableTypedLinting": {
64
64
  "type": "boolean",
65
- "description": "Whether or not to configure the ESLint `parserOptions.project` option. We do not do this by default for lint performance reasons.",
65
+ "description": "Whether to enable typed linting. For flat configs, this configures the recommended `parserOptions.projectService` and `tsconfigRootDir`. For legacy `.eslintrc` configs, this configures `parserOptions.project`. We do not enable this by default for lint performance reasons.",
66
66
  "default": false
67
67
  },
68
+ "setParserOptionsProject": {
69
+ "type": "boolean",
70
+ "description": "Deprecated alias for `enableTypedLinting`.",
71
+ "default": false,
72
+ "x-deprecated": "Use `enableTypedLinting` instead. This option will be removed in Nx v24."
73
+ },
68
74
  "skipPackageJson": {
69
75
  "type": "boolean",
70
76
  "default": false,
@@ -50,6 +50,12 @@ function updateDependencies(tree, options) {
50
50
  };
51
51
  if (!(0, versions_1.getInstalledCypressVersion)(tree)) {
52
52
  devDependencies.cypress = versions_1.cypressVersion;
53
+ // The user explicitly asked for cypress, and its postinstall downloads
54
+ // the binary it needs to run at all, so enable it — npm and yarn run it
55
+ // unconditionally. Transitive deps stay denied.
56
+ (0, internal_1.acknowledgeBuildScripts)(tree, (0, devkit_1.detectPackageManager)(tree.root), {
57
+ cypress: true,
58
+ });
53
59
  }
54
60
  tasks.push((0, devkit_1.addDependenciesToPackageJson)(tree, {}, devDependencies, undefined, options.keepExistingVersions ?? true));
55
61
  return (0, devkit_1.runTasksInSerial)(...tasks);
@@ -5,10 +5,6 @@ const internal_1 = require("@nx/devkit/internal");
5
5
  const devkit_1 = require("@nx/devkit");
6
6
  const js_1 = require("@nx/js");
7
7
  const fs_1 = require("fs");
8
- const devkit_internals_1 = require("nx/src/devkit-internals");
9
- const cache_directory_1 = require("nx/src/utils/cache-directory");
10
- const plugin_cache_utils_1 = require("nx/src/utils/plugin-cache-utils");
11
- const workspace_context_1 = require("nx/src/utils/workspace-context");
12
8
  const path_1 = require("path");
13
9
  const constants_1 = require("../utils/constants");
14
10
  const cypressConfigGlob = '**/cypress.config.{js,ts,mjs,cjs}';
@@ -25,9 +21,9 @@ const defaultPatterns = {
25
21
  exports.createNodes = [
26
22
  cypressConfigGlob,
27
23
  async (configFiles, options, context) => {
28
- const optionsHash = (0, devkit_internals_1.hashObject)(options);
29
- const cachePath = (0, path_1.join)(cache_directory_1.workspaceDataDirectory, `cypress-${optionsHash}.hash`);
30
- const pluginCache = new plugin_cache_utils_1.PluginCache(cachePath);
24
+ const optionsHash = (0, internal_1.hashObject)(options);
25
+ const cachePath = (0, path_1.join)(internal_1.workspaceDataDirectory, `cypress-${optionsHash}.hash`);
26
+ const pluginCache = new internal_1.PluginCache(cachePath);
31
27
  const packageManager = (0, devkit_1.detectPackageManager)(context.workspaceRoot);
32
28
  const pmc = (0, devkit_1.getPackageManagerCommand)(packageManager);
33
29
  const lockFileName = (0, js_1.getLockFileName)(packageManager);
@@ -490,7 +486,7 @@ async function getSpecFilesAndPatternsForTestType(cypressConfig, testType, works
490
486
  const excludeSpecPatterns = Array.isArray(excludeSpecPattern)
491
487
  ? excludeSpecPattern.map((p) => (0, path_1.join)(projectRoot, p))
492
488
  : [(0, path_1.join)(projectRoot, excludeSpecPattern)];
493
- const specFiles = await (0, workspace_context_1.globWithWorkspaceContext)(workspaceRoot, specPatterns, excludeSpecPatterns);
489
+ const specFiles = await (0, internal_1.globWithWorkspaceContext)(workspaceRoot, specPatterns, excludeSpecPatterns);
494
490
  return { specFiles, specPatterns, excludeSpecPatterns };
495
491
  }
496
492
  async function filterCypressConfigs(configFiles, context) {
@@ -3,6 +3,10 @@ import { Linter, LinterType } from '@nx/eslint';
3
3
  export interface CyLinterOptions {
4
4
  project: string;
5
5
  linter: Linter | LinterType;
6
+ enableTypedLinting?: boolean;
7
+ /**
8
+ * @deprecated Use `enableTypedLinting` instead. This option will be removed in Nx v24.
9
+ */
6
10
  setParserOptionsProject?: boolean;
7
11
  skipPackageJson?: boolean;
8
12
  rootProject?: boolean;
@@ -12,13 +12,14 @@ async function addLinterToCyProject(tree, options) {
12
12
  const tasks = [];
13
13
  const projectConfig = (0, devkit_1.readProjectConfiguration)(tree, options.project);
14
14
  const eslintFile = (0, internal_1.findEslintFile)(tree, projectConfig.root);
15
+ const enableTypedLinting = (0, internal_1.isTypedLintingEnabled)(options);
15
16
  if (!eslintFile) {
16
17
  tasks.push(await (0, eslint_1.lintProjectGenerator)(tree, {
17
18
  project: options.project,
18
19
  linter: options.linter,
19
20
  skipFormat: true,
20
21
  tsConfigPaths: [(0, devkit_1.joinPathFragments)(projectConfig.root, 'tsconfig.json')],
21
- setParserOptionsProject: options.setParserOptionsProject,
22
+ enableTypedLinting,
22
23
  skipPackageJson: options.skipPackageJson,
23
24
  rootProject: options.rootProject,
24
25
  addPlugin: options.addPlugin,
@@ -35,7 +36,8 @@ async function addLinterToCyProject(tree, options) {
35
36
  if ((0, internal_1.isEslintConfigSupported)(tree, projectConfig.root) ||
36
37
  (0, internal_1.isEslintConfigSupported)(tree)) {
37
38
  const overrides = [];
38
- if ((0, internal_1.useFlatConfig)(tree)) {
39
+ const isFlatConfig = (0, internal_1.useFlatConfig)(tree);
40
+ if (isFlatConfig) {
39
41
  (0, internal_1.addPredefinedConfigToFlatLintConfig)(tree, projectConfig.root, 'recommended', {
40
42
  moduleName: 'cypress',
41
43
  moduleImportPath: 'eslint-plugin-cypress/flat',
@@ -67,39 +69,44 @@ async function addLinterToCyProject(tree, options) {
67
69
  'no-undef': 'off',
68
70
  },
69
71
  };
72
+ // For flat configs typed linting is handled by `lintProjectGenerator` via
73
+ // `parserOptions.projectService`, so we don't emit `parserOptions.project`
74
+ // here. Legacy `.eslintrc` configs are JSON, which can't express the
75
+ // `__dirname` that `tsconfigRootDir` needs, so they keep `project`.
76
+ const legacyParserOptions = !isFlatConfig && enableTypedLinting
77
+ ? { project: `${projectConfig.root}/tsconfig.*?.json` }
78
+ : undefined;
70
79
  if (options.overwriteExisting) {
71
80
  overrides.unshift({
72
- files: (0, internal_1.useFlatConfig)(tree)
81
+ files: isFlatConfig
73
82
  ? // For flat configs we don't need to specify the files
74
83
  undefined
75
84
  : ['*.ts', '*.tsx', '*.js', '*.jsx'],
76
- parserOptions: !options.setParserOptionsProject
77
- ? undefined
78
- : {
79
- project: `${projectConfig.root}/tsconfig.*?.json`,
80
- },
85
+ parserOptions: legacyParserOptions,
81
86
  rules: {},
82
87
  });
83
88
  (0, internal_1.replaceOverridesInLintConfig)(tree, projectConfig.root, overrides);
84
89
  }
85
90
  else {
86
91
  overrides.unshift({
87
- files: (0, internal_1.useFlatConfig)(tree)
92
+ files: isFlatConfig
88
93
  ? // For flat configs we don't need to specify the files
89
94
  undefined
90
95
  : [
91
96
  '*.cy.{ts,js,tsx,jsx}',
92
97
  `${options.cypressDir}/**/*.{ts,js,tsx,jsx}`,
93
98
  ],
94
- parserOptions: !options.setParserOptionsProject
95
- ? undefined
96
- : {
97
- project: `${projectConfig.root}/tsconfig.*?.json`,
98
- },
99
+ parserOptions: legacyParserOptions,
99
100
  rules: {},
100
101
  });
101
102
  overrides.forEach((override) => (0, internal_1.addOverrideToLintConfig)(tree, projectConfig.root, override));
102
103
  }
104
+ // `lintProjectGenerator` only sets up the projectService block when it
105
+ // creates the config, and `replaceOverridesInLintConfig` strips it. For a
106
+ // flat config, re-add it here when typed linting is enabled.
107
+ if (isFlatConfig && enableTypedLinting) {
108
+ (0, internal_1.addTypedLintingToFlatConfig)(tree, projectConfig.root);
109
+ }
103
110
  }
104
111
  return (0, devkit_1.runTasksInSerial)(...tasks);
105
112
  }
@@ -131,7 +131,10 @@ ${jitComment}
131
131
  }`;
132
132
  });
133
133
  }
134
- if (presetImportPath) {
134
+ // Re-running the generator must not prepend a second declaration - Cypress
135
+ // loads TS configs through esbuild, which rejects duplicate bindings.
136
+ const isPresetAlreadyDeclared = tsquery.query(updatedConfigContents, ':matches(ImportSpecifier, BindingElement) Identifier[name="nxComponentTestingPreset"]').length > 0;
137
+ if (presetImportPath && !isPresetAlreadyDeclared) {
135
138
  // Use the path verbatim - callers pass the public exported subpath. Don't
136
139
  // append `.js`: @nx/react and @nx/angular's package exports only declare
137
140
  // the bare `./plugins/component-testing` subpath, so a `.js` suffix
@@ -8,9 +8,7 @@ exports.createExecutorContext = createExecutorContext;
8
8
  const devkit_1 = require("@nx/devkit");
9
9
  const path_1 = require("path");
10
10
  const fs_1 = require("fs");
11
- const find_project_for_path_1 = require("nx/src/project-graph/utils/find-project-for-path");
12
- const project_graph_1 = require("nx/src/project-graph/project-graph");
13
- const configuration_1 = require("nx/src/config/configuration");
11
+ const internal_1 = require("@nx/devkit/internal");
14
12
  exports.CY_FILE_MATCHER = new RegExp(/\.cy\.[tj]sx?$/);
15
13
  /**
16
14
  * return a path to a temp css file
@@ -55,8 +53,8 @@ function getProjectConfigByPath(graph, configPath) {
55
53
  const normalizedPathFromWorkspaceRoot = (0, devkit_1.normalizePath)((0, fs_1.lstatSync)(configPath).isFile()
56
54
  ? configFileFromWorkspaceRoot.replace((0, path_1.extname)(configPath), '')
57
55
  : configFileFromWorkspaceRoot);
58
- const projectRootMappings = (0, find_project_for_path_1.createProjectRootMappings)(graph.nodes);
59
- const componentTestingProjectName = (0, find_project_for_path_1.findProjectForPath)(normalizedPathFromWorkspaceRoot, projectRootMappings);
56
+ const projectRootMappings = (0, internal_1.createProjectRootMappings)(graph.nodes);
57
+ const componentTestingProjectName = (0, internal_1.findProjectForPath)(normalizedPathFromWorkspaceRoot, projectRootMappings);
60
58
  if (!componentTestingProjectName ||
61
59
  !graph.nodes[componentTestingProjectName]?.data) {
62
60
  throw new Error((0, devkit_1.stripIndents) `Unable to find the project configuration that includes ${normalizedPathFromWorkspaceRoot}.
@@ -69,8 +67,8 @@ function getProjectConfigByPath(graph, configPath) {
69
67
  return graph.nodes[componentTestingProjectName].data;
70
68
  }
71
69
  function createExecutorContext(graph, targets, projectName, targetName, configurationName) {
72
- const projectsConfigurations = (0, project_graph_1.readProjectsConfigurationFromProjectGraph)(graph);
73
- const nxJsonConfiguration = (0, configuration_1.readNxJson)();
70
+ const projectsConfigurations = (0, devkit_1.readProjectsConfigurationFromProjectGraph)(graph);
71
+ const nxJsonConfiguration = (0, internal_1.readNxJsonFromDisk)();
74
72
  return {
75
73
  cwd: process.cwd(),
76
74
  projectGraph: graph,
@@ -2,8 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.findBuildConfig = findBuildConfig;
4
4
  const devkit_1 = require("@nx/devkit");
5
- const configuration_1 = require("nx/src/config/configuration");
6
- const project_graph_1 = require("nx/src/project-graph/project-graph");
5
+ const internal_1 = require("@nx/devkit/internal");
7
6
  async function findBuildConfig(tree, options) {
8
7
  try {
9
8
  // attempt to use the provided target
@@ -118,8 +117,8 @@ function findTargetOptionsInProject(tree, graph, projectName, options) {
118
117
  }
119
118
  }
120
119
  function createExecutorContext(graph, targets, projectName, targetName, configurationName) {
121
- const nxJsonConfiguration = (0, configuration_1.readNxJson)();
122
- const projectsConfigurations = (0, project_graph_1.readProjectsConfigurationFromProjectGraph)(graph);
120
+ const nxJsonConfiguration = (0, internal_1.readNxJsonFromDisk)();
121
+ const projectsConfigurations = (0, devkit_1.readProjectsConfigurationFromProjectGraph)(graph);
123
122
  return {
124
123
  cwd: process.cwd(),
125
124
  projectGraph: graph,
@@ -5,9 +5,9 @@ const tslib_1 = require("tslib");
5
5
  const devkit_1 = require("@nx/devkit");
6
6
  const path_1 = require("path");
7
7
  const detect_port_1 = tslib_1.__importDefault(require("detect-port"));
8
- const executor_utils_1 = require("nx/src/command-line/run/executor-utils");
9
8
  const fs_1 = require("fs");
10
9
  const os_1 = require("os");
10
+ const internal_1 = require("@nx/devkit/internal");
11
11
  const PORT_LOCK_DIR = (0, path_1.join)((0, os_1.tmpdir)(), 'nx-cypress-port-locks');
12
12
  async function* startDevServer(opts, context) {
13
13
  // no dev server, return the provisioned base url
@@ -136,8 +136,8 @@ ${e.message || e}`);
136
136
  // so we double check the schema if readTargetOptions didn't return a value for the property
137
137
  const projectConfig = context.projectsConfigurations?.projects?.[target.project];
138
138
  const targetConfig = projectConfig.targets[target.target];
139
- const [collection, executor] = (0, executor_utils_1.parseExecutor)(targetConfig.executor);
140
- const { schema } = (0, executor_utils_1.getExecutorInformation)(collection, executor, context.root, context.projectsConfigurations.projects);
139
+ const [collection, executor] = (0, internal_1.parseExecutor)(targetConfig.executor);
140
+ const { schema } = (0, internal_1.getExecutorInformation)(collection, executor, context.root, context.projectsConfigurations.projects);
141
141
  // NOTE: schema won't have a default since readTargetOptions would have
142
142
  // already set that and this check wouldn't need to be made
143
143
  targetHasOpt = Object.keys(schema.properties).includes(property);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nx/cypress",
3
- "version": "23.1.0",
3
+ "version": "23.1.2",
4
4
  "private": false,
5
5
  "type": "commonjs",
6
6
  "files": [
@@ -89,12 +89,12 @@
89
89
  "semver": "^7.6.3",
90
90
  "tree-kill": "^1.2.2",
91
91
  "tslib": "^2.3.0",
92
- "@nx/devkit": "23.1.0",
93
- "@nx/eslint": "23.1.0",
94
- "@nx/js": "23.1.0"
92
+ "@nx/devkit": "23.1.2",
93
+ "@nx/eslint": "23.1.2",
94
+ "@nx/js": "23.1.2"
95
95
  },
96
96
  "devDependencies": {
97
- "nx": "23.1.0"
97
+ "nx": "23.1.2"
98
98
  },
99
99
  "peerDependencies": {
100
100
  "cypress": ">= 13 < 16"