@hs-web-team/eslint-config-node 3.2.0-next.4 → 3.2.0-next.6

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/CLAUDE.md CHANGED
@@ -111,7 +111,7 @@ When testing changes to this package in downstream projects, you'll typically:
111
111
  - Browser export (`./browser`): `browser.js` - Browser/React ESLint configuration
112
112
  - Prettier export (`./.prettierrc.json`): `.prettierrc.json` - Prettier configuration
113
113
  - Stylelint export (`./.stylelintrc.json`): `.stylelintrc.json` - Stylelint configuration
114
- - Cypress export (`./cypress.config`): `cypress.config.cjs` - Cypress configuration
114
+ - Cypress export (`./cypress.config`): `cypress.config.cjs` (runtime), `cypress.config.d.ts` (types)
115
115
  - **Binary command**: `add-prettier` maps to `bin/add-prettier-scripts.js`
116
116
 
117
117
  ### Migration Context
@@ -127,4 +127,5 @@ module.exports = {
127
127
  envs,
128
128
  getDevBaseUrl,
129
129
  getBaseUrls,
130
+ setupNodeEvents,
130
131
  };
@@ -0,0 +1,18 @@
1
+ /// <reference types="cypress" />
2
+
3
+ export declare const envs: {
4
+ currentEnv: string;
5
+ DEV: string;
6
+ QA: string;
7
+ PROD: string;
8
+ };
9
+
10
+ export declare const config: Cypress.ConfigOptions;
11
+
12
+ export declare function setupNodeEvents(
13
+ on: Cypress.PluginEvents,
14
+ config: Cypress.PluginConfigOptions
15
+ ): Promise<Cypress.PluginConfigOptions>;
16
+
17
+ export declare function getDevBaseUrl(): string | null;
18
+ export declare function getBaseUrls(): Record<string, string | null> | null;
@@ -0,0 +1,120 @@
1
+ import yaml from 'js-yaml';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import createBundler from '@bahmutov/cypress-esbuild-preprocessor';
5
+ import { addCucumberPreprocessorPlugin } from '@badeball/cypress-cucumber-preprocessor';
6
+ import { createEsbuildPlugin } from '@badeball/cypress-cucumber-preprocessor/esbuild';
7
+
8
+ const DEV = 'DEV';
9
+ const QA = 'qa';
10
+ const PROD = 'prod';
11
+ const currentEnv = QA;
12
+
13
+ export const envs = {
14
+ currentEnv,
15
+ DEV,
16
+ QA,
17
+ PROD,
18
+ };
19
+
20
+ /**
21
+ * @description Recursively climbs up the filepath, until it finds what directory
22
+ * the directory where the hubspot.config.yml file is located.
23
+ *
24
+ * @param {string} currDir - the current working directory path to search from
25
+ * @returns {string} The absolute path of the project's root directory
26
+ */
27
+ const getRootDir = (currDir: string): string => {
28
+ if (fs.existsSync(path.join(currDir, 'hubspot.config.yml'))) return currDir;
29
+ const parentDir = path.dirname(currDir);
30
+ if (parentDir === currDir) {
31
+ throw new Error('Error: Could not find the hubspot.config.yml file within the projects directories.');
32
+ }
33
+ return getRootDir(parentDir);
34
+ };
35
+
36
+ /**
37
+ * @returns {string|null} The `baseUrl` set for the `DEV` portal in `hubspot.config.yml`
38
+ * or `null` if this is not the dev environment or no such property exists.
39
+ */
40
+ export const getDevBaseUrl = (): string | null => {
41
+ try {
42
+ global.console.log(
43
+ 'To test a dev URL, add the `baseUrl` property to your `DEV` portal configuration in `hubspot.config.yml`',
44
+ );
45
+
46
+ const root = getRootDir(__dirname);
47
+ const configPath = path.resolve(root, 'hubspot.config.yml');
48
+ const fileContents = fs.readFileSync(configPath, 'utf8');
49
+ const { portals } = yaml.load(fileContents) as { portals: Array<{ name: string; baseUrl?: string }> };
50
+ const devPortal = portals.find(portal => portal.name === 'DEV');
51
+ return devPortal?.baseUrl || null;
52
+ } catch (error) {
53
+ global.console.error(error);
54
+ return null;
55
+ }
56
+ };
57
+
58
+ /**
59
+ * @description Get the baseUrls for different environments from the ci config file for local test execution.
60
+ * @returns {object} baseUrls - The base urls object
61
+ */
62
+ export const getBaseUrls = (): Record<string, string | null> | null => {
63
+ let fileContents = '';
64
+ let ciConfig: { regression?: { e2eTestEnvironment?: Array<{ name: string; url: string }> } } = {};
65
+ const baseUrls: Record<string, string | null> = {};
66
+ baseUrls[envs.DEV] = getDevBaseUrl();
67
+
68
+ const fileExist = fs.existsSync('.ci/config.yml');
69
+ if (fileExist) {
70
+ fileContents = fs.readFileSync('.ci/config.yml', 'utf8');
71
+ ciConfig = yaml.load(fileContents) as typeof ciConfig;
72
+ if (ciConfig.regression?.e2eTestEnvironment && ciConfig.regression.e2eTestEnvironment.length > 0) {
73
+ try {
74
+ ciConfig.regression.e2eTestEnvironment.forEach(item => {
75
+ baseUrls[item.name] = item.url;
76
+ });
77
+ } catch (error) {
78
+ console.error('Error reading the base urls from the ci config file:', error);
79
+ return null;
80
+ }
81
+ }
82
+ }
83
+ return baseUrls || null;
84
+ };
85
+
86
+ async function setupNodeEvents(
87
+ on: Cypress.PluginEvents,
88
+ config: Cypress.PluginConfigOptions,
89
+ ): Promise<Cypress.PluginConfigOptions> {
90
+ await addCucumberPreprocessorPlugin(on, config);
91
+ on(
92
+ 'file:preprocessor',
93
+ createBundler({ plugins: [createEsbuildPlugin(config)] }),
94
+ );
95
+ return config;
96
+ }
97
+
98
+ const e2e: Cypress.EndToEndConfigOptions = {
99
+ specPattern: 'cypress/e2e/*.cy.js',
100
+ setupNodeEvents,
101
+ };
102
+
103
+ export const config: Cypress.ConfigOptions = {
104
+ chromeWebSecurity: false,
105
+ defaultCommandTimeout: 20000,
106
+ e2e,
107
+ numTestsKeptInMemory: 0,
108
+ pageLoadTimeout: 20000,
109
+ port: 3500,
110
+ responseTimeout: 20000,
111
+ retries: {
112
+ runMode: 1,
113
+ openMode: 0,
114
+ },
115
+ screenshotOnRunFailure: true,
116
+ trashAssetsBeforeRuns: true,
117
+ video: false,
118
+ viewportHeight: 1080,
119
+ viewportWidth: 1920,
120
+ };
@@ -221,19 +221,22 @@ module.exports = defineConfig({
221
221
 
222
222
  ### Add Custom setupNodeEvents
223
223
 
224
+ `setupNodeEvents` is exported directly and is also embedded inside `config.e2e`. If you override it without calling the package's version first, you'll silently lose the Cucumber preprocessor and esbuild setup.
225
+
226
+ Import `setupNodeEvents` directly and call it before your own logic:
227
+
224
228
  ```javascript
225
229
  const { defineConfig } = require('cypress');
226
- const { config } = require('@hs-web-team/eslint-config-node/cypress.config');
230
+ const { config, setupNodeEvents: wtSetupNodeEvents } = require('@hs-web-team/eslint-config-node/cypress.config');
227
231
 
228
232
  module.exports = defineConfig({
229
233
  ...config,
230
234
  e2e: {
231
235
  ...config.e2e,
232
- async setupNodeEvents(on, cypressConfig) {
233
- // Call shared setup first (includes esbuild preprocessor and Cucumber setup)
234
- const updatedConfig = await config.e2e.setupNodeEvents(on, cypressConfig);
236
+ async setupNodeEvents(on, cfg) {
237
+ // sets up esbuild preprocessor and Cucumber
238
+ await wtSetupNodeEvents(on, cfg);
235
239
 
236
- // Add your custom tasks/events
237
240
  on('task', {
238
241
  log(message) {
239
242
  console.log(message);
@@ -241,12 +244,14 @@ module.exports = defineConfig({
241
244
  },
242
245
  });
243
246
 
244
- return updatedConfig;
247
+ return cfg;
245
248
  },
246
249
  },
247
250
  });
248
251
  ```
249
252
 
253
+ If you don't need custom node events, omit `setupNodeEvents` entirely and just spread `...config.e2e` — the package's setup runs automatically.
254
+
250
255
  ## Integration with CI/CD
251
256
 
252
257
  ### GitHub Actions Example
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hs-web-team/eslint-config-node",
3
- "version": "3.2.0-next.4",
3
+ "version": "3.2.0-next.6",
4
4
  "description": "HubSpot Marketing WebTeam shared configurations for ESLint, Prettier, Stylelint, and Cypress",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -9,7 +9,17 @@
9
9
  "./browser": "./browser.js",
10
10
  "./.prettierrc.json": "./.prettierrc.json",
11
11
  "./.stylelintrc.json": "./.stylelintrc.json",
12
- "./cypress.config": "./cypress.config.cjs"
12
+ "./cypress.config": {
13
+ "types": "./cypress.config.d.ts",
14
+ "require": "./cypress.config.cjs"
15
+ }
16
+ },
17
+ "typesVersions": {
18
+ "*": {
19
+ "cypress.config": [
20
+ "./cypress.config.d.ts"
21
+ ]
22
+ }
13
23
  },
14
24
  "scripts": {
15
25
  "lint": "npx eslint -c ./index.js *.js --fix",
@@ -53,13 +63,13 @@
53
63
  "globals": "^17.3.0",
54
64
  "jiti": "^2.6.1",
55
65
  "prettier": "^3.8.1",
56
- "typescript-eslint": "^8.54.0"
66
+ "typescript-eslint": "^8.54.0",
67
+ "esbuild": "^0.27.2",
68
+ "js-yaml": "^4.1.1"
57
69
  },
58
70
  "peerDependencies": {
59
71
  "@badeball/cypress-cucumber-preprocessor": "^24.0.0",
60
72
  "cypress": "^15.0.0",
61
- "esbuild": "^0.27.2",
62
- "js-yaml": "^4.1.1",
63
73
  "stylelint": "^17.1.1",
64
74
  "stylelint-config-standard": "^40.0.0",
65
75
  "stylelint-config-standard-scss": "^17.0.0"
@@ -76,15 +86,6 @@
76
86
  },
77
87
  "cypress": {
78
88
  "optional": true
79
- },
80
- "@badeball/cypress-cucumber-preprocessor": {
81
- "optional": true
82
- },
83
- "esbuild": {
84
- "optional": true
85
- },
86
- "js-yaml": {
87
- "optional": true
88
89
  }
89
90
  }
90
91
  }