@zohodesk/codestandard-validator 1.3.1 → 1.4.1-window-fix

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/.babelrc CHANGED
@@ -4,8 +4,9 @@
4
4
  "@babel/preset-env",
5
5
  {
6
6
  "targets": {
7
- "node": "16"
8
- }
7
+ "node": "18"
8
+ },
9
+ "exclude": ["@babel/plugin-transform-dynamic-import"]
9
10
  }
10
11
  ]
11
12
  ],
File without changes
@@ -349,13 +349,12 @@ async function reviewFiles(filePaths, options = {}) {
349
349
  } : r.value;
350
350
  results.push(out);
351
351
  } else {
352
- var _r$reason;
353
352
  const fp = r.filePath;
354
353
  out = {
355
354
  success: false,
356
355
  fileName: path.basename(fp),
357
356
  filePath: fp,
358
- error: ((_r$reason = r.reason) === null || _r$reason === void 0 ? void 0 : _r$reason.message) || r.reason || 'Unknown error'
357
+ error: r.reason?.message || r.reason || 'Unknown error'
359
358
  };
360
359
  results.push(out);
361
360
  }
@@ -1,6 +1,5 @@
1
1
  "use strict";
2
2
 
3
- var _process;
4
3
  const {
5
4
  execSync
6
5
  } = require('child_process');
@@ -22,7 +21,7 @@ const {
22
21
  gitEndPoint: _gitEndPoint
23
22
  } = getConfigPath(getConfigPathExecute());
24
23
  const gitEndPoint = _gitEndPoint || 'https://zgit.csez.zohocorpin.com';
25
- const compareBranch = ((_process = process) === null || _process === void 0 || (_process = _process.env) === null || _process === void 0 ? void 0 : _process.CHUNK_BRANCH) || 'release';
24
+ const compareBranch = process?.env?.CHUNK_BRANCH || 'release';
26
25
  const configPath = path.resolve(process.cwd(), 'lint.config.js');
27
26
  function getGitProjectId() {
28
27
  try {
@@ -75,7 +74,7 @@ function createBranchDiffChunk(branchName) {
75
74
  }
76
75
  function parserReleaseDiffRemoteAPI(rawresponse) {
77
76
  var formatted = [];
78
- if (rawresponse !== null && rawresponse !== void 0 && rawresponse.diffs) {
77
+ if (rawresponse?.diffs) {
79
78
  formatted = rawresponse.diffs.map(changeset => {
80
79
  if (isTestOrUATFile(changeset.new_path)) {
81
80
  return null;
@@ -178,7 +177,7 @@ if (shouldEnable) {
178
177
  const RESET = '\x1b[0m';
179
178
  (async function () {
180
179
  Logger.log(`****************************** Calculation Chunk Size *******************************`);
181
- if (!(globalThis !== null && globalThis !== void 0 && globalThis.chunkSize)) {
180
+ if (!globalThis?.chunkSize) {
182
181
  globalThis.chunkSize = {
183
182
  $modifieldLines: 0,
184
183
  $removedLines: 0
@@ -35,10 +35,11 @@ async function preCommitHook() {
35
35
  return;
36
36
  }
37
37
  const {
38
- JsFiles
38
+ JsFiles,
39
+ featureFiles
39
40
  } = filterFiles(stagedFiles, [".eslintrc.js"], true);
40
41
  const branch = await safeGetBranch();
41
- const shouldAbort = await runLintWorkflow(JsFiles, branch);
42
+ const shouldAbort = await runLintWorkflow([...JsFiles, ...featureFiles], branch);
42
43
  if (shouldAbort) {
43
44
  Logger.log(Logger.FAILURE_TYPE, "There are linter errors/warnings. Commit aborted 🙁.");
44
45
  process.exit(1);
@@ -45,9 +45,10 @@ async function lintFiles(filePath) {
45
45
  return [];
46
46
  }
47
47
  async function findEslintErrors(file) {
48
- const nodeModulesPath = getNodeModulesPath();
48
+ const nodeModulesPath = path.resolve(getNodeModulesPath());
49
49
  const eslintPath = getEslintExecutablePath();
50
- const eslintConfig = `${nodeModulesPath}/.eslintrc.js`;
50
+ const eslintConfig = path.join(nodeModulesPath, '.eslintrc.js');
51
+ const resolvePluginsPath = path.join(nodeModulesPath, 'node_modules');
51
52
  if (!fs.existsSync(nodeModulesPath)) {
52
53
  Logger.log(Logger.INFO_TYPE, 'node_modules not found');
53
54
  return [];
@@ -56,7 +57,7 @@ async function findEslintErrors(file) {
56
57
  Logger.log(Logger.INFO_TYPE, 'Eslint executable not found. Make sure eslint plugin is installed');
57
58
  return [];
58
59
  }
59
- return execSync(`npx --ignore-existing "${eslintPath}" --config "${eslintConfig}" --no-inline-config --resolve-plugins-relative-to="${nodeModulesPath}/node_modules" ${path.resolve(getRootDirectory(), file)}`).then(({
60
+ return execSync(`npx --ignore-existing "${eslintPath}" --config "${eslintConfig}" --no-inline-config --resolve-plugins-relative-to="${resolvePluginsPath}" ${path.resolve(getRootDirectory(), file)}`).then(({
60
61
  stderr
61
62
  }) => stderr ? stderr.toString().trim().split('\n') : []).catch(err => {
62
63
  Logger.log(Logger.FAILURE_TYPE, err);
@@ -113,15 +113,16 @@ async function lintFiles(filePath) {
113
113
  */
114
114
 
115
115
  function findEslintErrors(file) {
116
- let nodeModulesPathOfProject = `${getNodeModulesPath()}`;
116
+ let nodeModulesPathOfProject = path.resolve(getNodeModulesPath());
117
117
  let eslintExecutablePath = getEslintExecutablePath();
118
- let eslintConfigurationFilePath = `${nodeModulesPathOfProject}/.eslintrc.js`;
118
+ let eslintConfigurationFilePath = path.join(nodeModulesPathOfProject, '.eslintrc.js');
119
+ let resolvePluginsPath = path.join(nodeModulesPathOfProject, 'node_modules');
119
120
  let isEslintExecutablePresent = fs.existsSync(eslintExecutablePath) ? true : false;
120
121
  let isNodeModulesPresent = fs.existsSync(nodeModulesPathOfProject);
121
122
  if (isNodeModulesPresent) {
122
123
  if (isEslintExecutablePresent) {
123
124
  return new Promise((resolve, reject) => {
124
- exec(`npx --ignore-existing "${eslintExecutablePath}" --config "${eslintConfigurationFilePath}" --no-inline-config --resolve-plugins-relative-to="${nodeModulesPathOfProject}/node_modules" ${path.resolve(getRootDirectory(), file)}`, (error, stderr, stdout) => {
125
+ exec(`npx --ignore-existing "${eslintExecutablePath}" --config "${eslintConfigurationFilePath}" --no-inline-config --resolve-plugins-relative-to="${resolvePluginsPath}" ${path.resolve(getRootDirectory(), file)}`, (error, stderr, stdout) => {
125
126
  if (stderr) {
126
127
  resolve(stderr.trim().split('\n'));
127
128
  } else if (error) {
@@ -54,8 +54,13 @@ async function hooks() {
54
54
  }
55
55
  }
56
56
  (async function () {
57
- await initConfig(getConfigPathExecute());
58
- postInstallExecution();
59
- await require("../chunk/chunk_Restriction");
60
- hooks();
57
+ try {
58
+ await initConfig(getConfigPathExecute());
59
+ await Promise.resolve(postInstallExecution());
60
+ require("../chunk/chunk_Restriction");
61
+ await hooks();
62
+ } catch (error) {
63
+ Logger.log(Logger.FAILURE_TYPE, `Pre-commit initialization failed: ${error.message}`);
64
+ process.exit(1);
65
+ }
61
66
  })();
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
 
3
3
  var MutationRunner = require('./mutationRunner');
4
- var StrykerConfigBuilder = require('./strykerConfigBuilder');
4
+ var path = require('path');
5
5
 
6
6
  /**
7
7
  * MutationCli — CLI argument parser and executor for mutation testing.
@@ -25,6 +25,7 @@ var StrykerConfigBuilder = require('./strykerConfigBuilder');
25
25
  * --concurrency=<n> (default: cpu count - 1)
26
26
  * --timeoutMS=<ms> (default: 60000)
27
27
  * --strykerConfig=<path> (external stryker.conf.js)
28
+ * --jestConfig=<path> (external jest.config.js)
28
29
  *
29
30
  * Compatible with Node 16+.
30
31
  */
@@ -46,7 +47,8 @@ MutationCli.prototype.parseArgs = function (args) {
46
47
  logLevel: 'info',
47
48
  concurrency: null,
48
49
  timeoutMS: null,
49
- strykerConfig: null
50
+ strykerConfig: null,
51
+ jestConfig: null
50
52
  };
51
53
  for (var i = 0; i < args.length; i++) {
52
54
  var arg = args[i];
@@ -72,8 +74,10 @@ MutationCli.prototype.parseArgs = function (args) {
72
74
  parsed.concurrency = arg.split('=')[1];
73
75
  } else if (arg.indexOf('--timeoutMS=') === 0) {
74
76
  parsed.timeoutMS = arg.split('=')[1];
75
- } else if (arg.indexOf('--strykerConfig=') === 0) {
77
+ } else if (arg.indexOf('--mutationConfigPath=') === 0) {
76
78
  parsed.strykerConfig = arg.split('=')[1];
79
+ } else if (arg.indexOf('--jestConfigPath=') === 0) {
80
+ parsed.jestConfig = arg.split('=')[1];
77
81
  }
78
82
  }
79
83
  if (parsed.release == null || parsed.release === '') {
@@ -109,26 +113,26 @@ MutationCli.prototype.validate = function (parsed) {
109
113
  /* ------------------------------------------------------------------ */
110
114
 
111
115
  MutationCli.prototype._buildConfig = function (parsed) {
112
- var builder = new StrykerConfigBuilder();
113
- if (parsed.strykerConfig || this._options.strykerConfigpath) {
114
- builder.fromConfigFile(parsed.strykerConfig || this._options.strykerConfigpath);
116
+ var config = {};
117
+
118
+ // Load config from file if specified
119
+ var configPath = parsed.strykerConfig || this._options.mutationConfigPath;
120
+ if (configPath) {
121
+ var resolved = path.resolve(configPath);
122
+ config = Object.assign({}, require(resolved));
115
123
  }
116
- builder.setLogLevel(parsed.logLevel || this._options.logLevel || 'info');
124
+
125
+ // Apply CLI overrides
126
+ config.logLevel = parsed.logLevel || this._options.logLevel || 'info';
117
127
  var concurrency = parsed.concurrency || this._options.concurrency;
118
128
  if (concurrency != null) {
119
- builder.setConcurrency(concurrency);
129
+ config.concurrency = Number(concurrency);
120
130
  }
121
131
  var timeoutMS = parsed.timeoutMS || this._options.timeoutMS;
122
132
  if (timeoutMS != null) {
123
- builder.setTimeoutMS(timeoutMS);
124
- }
125
- if (this._options.jestConfig) {
126
- builder.setJest(Object.assign({
127
- projectType: 'custom',
128
- enableFindRelatedTests: true
129
- }, this._options.jestConfig));
133
+ config.timeoutMS = Number(timeoutMS);
130
134
  }
131
- return builder;
135
+ return config;
132
136
  };
133
137
 
134
138
  /* ------------------------------------------------------------------ */
@@ -144,12 +148,12 @@ MutationCli.prototype.execute = function (args) {
144
148
  error: validation.error
145
149
  });
146
150
  }
147
- var configBuilder = this._buildConfig(parsed);
151
+ var mutationConfig = this._buildConfig(parsed);
148
152
  var runner = new MutationRunner({
149
153
  ...this._options,
150
154
  cwd: this._options.cwd,
151
- configBuilder: configBuilder,
152
- jestConfig: this._options.jestConfig,
155
+ mutationConfig: mutationConfig,
156
+ jestConfigPath: parsed.jestConfig || this._options.jestConfig || null,
153
157
  outputDir: parsed.outputDir || this._options.outputDir,
154
158
  outputFileName: parsed.outputFileName || this._options.outputFileName
155
159
  });
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
 
3
3
  var StrykerWrapper = require('./strykerWrapper');
4
- var StrykerConfigBuilder = require('./strykerConfigBuilder');
5
4
  var BranchDiff = require('./branchDiff');
6
5
  var FileResolver = require('./fileResolver');
7
6
  var ReportGenerator = require('./reportGenerator');
@@ -30,24 +29,8 @@ var path = require('path');
30
29
  function MutationRunner(options) {
31
30
  options = options || {};
32
31
  this._cwd = options.cwd || process.cwd();
33
- var configBuilder = options.configBuilder;
34
- if (!configBuilder) {
35
- configBuilder = new StrykerConfigBuilder();
36
- if (options.strykerConfigpath) {
37
- configBuilder.fromConfigFile(options.strykerConfigpath);
38
- }
39
- if (options.concurrency != null) configBuilder.setConcurrency(options.concurrency);
40
- if (options.timeoutMS != null) configBuilder.setTimeoutMS(options.timeoutMS);
41
- if (options.logLevel) configBuilder.setLogLevel(options.logLevel);
42
- if (options.reportPath) {
43
- configBuilder.setHtmlReporter({
44
- fileName: options.reportPath
45
- }).setJsonReporter({
46
- fileName: options.reportPath
47
- });
48
- }
49
- }
50
- this._stryker = new StrykerWrapper(configBuilder);
32
+ var mutationConfig = options.mutationConfig || {};
33
+ this._stryker = new StrykerWrapper(mutationConfig);
51
34
  this._branchDiff = new BranchDiff({
52
35
  cwd: this._cwd,
53
36
  token: options.token,
@@ -64,7 +47,7 @@ function MutationRunner(options) {
64
47
  outputDir: options.outputDir || 'reports/mutation',
65
48
  outputFileName: options.outputFileName || 'mutation-report.json'
66
49
  });
67
- this._jestConfig = options.jestConfig || {};
50
+ this._jestConfigPath = options.jestConfigPath || null;
68
51
  }
69
52
 
70
53
  /* ------------------------------------------------------------------ */
@@ -187,13 +170,7 @@ MutationRunner.prototype._runMutation = function (sourceFiles, testFiles, ctx) {
187
170
  var strykerOpts = {
188
171
  rootDirectory: this._branchDiff.getRootDirectory(),
189
172
  testFiles: testsToRun,
190
- jest: Object.assign({}, self._jestConfig, {
191
- config: {
192
- testMatch: testsToRun,
193
- reporters: ['json']
194
- },
195
- enableFindRelatedTests: true
196
- })
173
+ jestConfigPath: this._jestConfigPath
197
174
  };
198
175
  return self._stryker.run(sourcesToMutate, strykerOpts).then(function (mutationResult) {
199
176
  var out3 = self._reportGenerator.generateAndWrite(mutationResult, {
@@ -1,49 +1,37 @@
1
1
  "use strict";
2
2
 
3
- function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
4
3
  var path = require('path');
4
+ var os = require('os');
5
5
  var patternConfig = require('./mutatePattern.json');
6
- var StrykerConfigBuilder = require('./strykerConfigBuilder');
7
6
  var DEFAULT_MUTATE_PATTERN = patternConfig.defaultPattern;
7
+ var DEFAULTS = {
8
+ packageManager: 'npm',
9
+ testRunner: 'jest',
10
+ coverageAnalysis: 'perTest',
11
+ reporters: ['html', 'json'],
12
+ logLevel: 'info',
13
+ timeoutMS: 60000,
14
+ timeoutFactor: 1.5,
15
+ cleanTempDir: true,
16
+ allowEmpty: true,
17
+ thresholds: {
18
+ high: 80,
19
+ low: 60,
20
+ break: null
21
+ }
22
+ };
8
23
 
9
24
  /**
10
- * StrykerWrapper — thin wrapper around @stryker-mutator/core v5.
25
+ * StrykerWrapper — thin wrapper around @stryker-mutator/core.
11
26
  *
12
- * Accepts a StrykerConfigBuilder (or a raw options hash for backwards
13
- * compatibility) to produce the Stryker config, runs mutation testing,
14
- * and normalizes results.
27
+ * Accepts a plain config object (loaded from a config file or defaults),
28
+ * merges with DEFAULTS, runs mutation testing, and normalizes results.
15
29
  *
16
30
  * Compatible with Node 16+.
17
31
  */
18
- function StrykerWrapper(options) {
19
- options = options || {};
32
+ function StrykerWrapper(config) {
20
33
  this._strykerModule = null;
21
- if (options instanceof StrykerConfigBuilder) {
22
- this._configBuilder = options;
23
- } else if (options.strykerConfigpath) {
24
- this._configBuilder = new StrykerConfigBuilder().fromConfigFile(options.strykerConfigpath);
25
- } else {
26
- this._configBuilder = new StrykerConfigBuilder().setTestRunner('jest').setCoverageAnalysis('perTest').setAllowEmpty(true).setReporters(['html', 'json']).setCleanTempDir(true);
27
- if (options.reportPath) {
28
- this._configBuilder.setHtmlReporter({
29
- fileName: options.reportPath
30
- }).setJsonReporter({
31
- fileName: options.reportPath
32
- });
33
- }
34
- if (options.concurrency != null) {
35
- this._configBuilder.setConcurrency(options.concurrency);
36
- }
37
- if (options.timeoutMS != null) {
38
- this._configBuilder.setTimeoutMS(options.timeoutMS);
39
- }
40
- if (options.timeoutFactor != null) {
41
- this._configBuilder.setTimeoutFactor(options.timeoutFactor);
42
- }
43
- if (options.logLevel) {
44
- this._configBuilder.setLogLevel(options.logLevel);
45
- }
46
- }
34
+ this._baseConfig = config && typeof config === 'object' ? Object.assign({}, config) : {};
47
35
  }
48
36
 
49
37
  /* ------------------------------------------------------------------ */
@@ -56,13 +44,13 @@ StrykerWrapper.prototype._loadStryker = async function () {
56
44
  return Promise.resolve(self._strykerModule);
57
45
  }
58
46
  try {
59
- self._strykerModule = await Promise.resolve().then(() => _interopRequireWildcard(require('@stryker-mutator/core')));
47
+ self._strykerModule = await import('@stryker-mutator/core');
60
48
  return Promise.resolve(self._strykerModule);
61
49
  } catch (err) {
62
50
  return Promise.reject(new Error('Failed to load @stryker-mutator/core. Install it:\n' + ' npm i --save-dev @stryker-mutator/core@5 @stryker-mutator/jest-runner@5\n' + err.message));
63
51
  }
64
52
  };
65
- StrykerWrapper.prototype._buildMutatePatterns = function (sourceFiles, options) {
53
+ StrykerWrapper.prototype._buildSourceToRun = function (sourceFiles, options) {
66
54
  if (!sourceFiles || sourceFiles.length === 0) {
67
55
  return [DEFAULT_MUTATE_PATTERN];
68
56
  }
@@ -75,45 +63,88 @@ StrykerWrapper.prototype._buildMutatePatterns = function (sourceFiles, options)
75
63
  };
76
64
 
77
65
  /**
78
- * Build the final Stryker config by cloning the base builder and
79
- * layering per-run overrides (mutate patterns, test files, jest, etc.).
66
+ * Load a jest config file (JS or JSON). Handles both object and
67
+ * function exports (jest supports `module.exports = async (cfg) => ({...})`).
68
+ *
69
+ * Returns null if filePath is falsy or the file cannot be loaded.
70
+ */
71
+ StrykerWrapper.prototype._loadJestConfigFile = function (filePath) {
72
+ if (!filePath) return null;
73
+ try {
74
+ var resolved = path.resolve(filePath);
75
+ var exported = require(resolved);
76
+ if (typeof exported === 'function') {
77
+ exported = exported();
78
+ }
79
+ return exported && typeof exported === 'object' ? exported : null;
80
+ } catch (err) {
81
+ throw new Error('Failed to load jest config from "' + filePath + '": ' + err.message);
82
+ }
83
+ };
84
+
85
+ /**
86
+ * Build the final Stryker config by merging DEFAULTS, base config,
87
+ * and per-run overrides.
88
+ *
89
+ * Jest config resolution (highest → lowest precedence inside Stryker):
90
+ * configFromFile (loaded via Jest's native pipeline — handles preset, <rootDir>, transform)
91
+ * ↓ merged with
92
+ * jest.config (inline override object — safe for testMatch, reporters, etc.)
93
+ * ↓ merged with
94
+ * JEST_OVERRIDE_OPTIONS (Stryker's own forced keys — always wins)
80
95
  */
81
96
  StrykerWrapper.prototype._buildStrykerConfig = function (sourceFiles, options) {
82
97
  options = options || {};
83
- var mutatePatterns = this._buildMutatePatterns(sourceFiles, options);
84
- var builder = this._configBuilder.clone().setMutate(mutatePatterns);
85
- if (options.testFiles) {
86
- builder.setTestRunner('command');
87
- var testPattern = options.testFiles.map(function (f) {
88
- var base = path.basename(f);
89
- return base.replace(/\.(test|spec)\.(js|ts|jsx|tsx|mjs|cjs)$/, '');
90
- }).join('|');
91
- var cdCmd = options.rootDirectory ? 'cd ' + options.rootDirectory + ' && ' : '';
92
- builder.setCommandRunner({
93
- command: 'npx ZDTestingFramework unit-test'
94
- });
98
+
99
+ // 1. Start with defaults, overlay base config
100
+ var config = Object.assign({}, DEFAULTS, this._baseConfig);
101
+
102
+ // 2. Compute concurrency if not set
103
+ if (config.concurrency == null) {
104
+ config.concurrency = Math.max(1, os.cpus().length - 1);
95
105
  }
96
- if (options.jest) {
97
- builder.setJest(Object.assign({
98
- projectType: 'custom',
99
- enableFindRelatedTests: true
100
- }, options.jest));
106
+
107
+ // 3. Set mutate = resolved source files (sourceToRun)
108
+ config.mutate = this._buildSourceToRun(sourceFiles, options);
109
+
110
+ // 4. Build jest section
111
+ var jestSection = {
112
+ projectType: 'custom',
113
+ enableFindRelatedTests: false
114
+ };
115
+ if (options.jestConfigPath) {
116
+ jestSection.configFile = options.jestConfigPath;
117
+ }
118
+ if (options.testFiles && options.testFiles.length > 0) {
119
+ // Convert absolute test paths to <rootDir>-relative paths
120
+ var rootDir = options.rootDirectory || process.cwd();
121
+ var rootDirRelativeTests = options.testFiles.map(function (f) {
122
+ var absPath = path.isAbsolute(f) ? f : path.resolve(rootDir, f);
123
+ var relativePath = path.relative(rootDir, absPath);
124
+ return '<rootDir>/' + relativePath.replace(/\\/g, '/');
125
+ });
126
+ jestSection.config = Object.assign({}, this._loadJestConfigFile(options.jestConfigPath), {
127
+ testMatch: rootDirRelativeTests
128
+ });
101
129
  }
130
+ config.jest = jestSection;
131
+
132
+ // 5. Per-run overrides
102
133
  if (options.configFile) {
103
- builder.setConfigFile(options.configFile);
134
+ config.configFile = options.configFile;
104
135
  }
105
136
  if (options.reportPath) {
106
- builder.setJsonReporter({
137
+ config.jsonReporter = {
107
138
  fileName: options.reportPath
108
- });
139
+ };
109
140
  }
110
141
  if (options.tempDirName) {
111
- builder.setTempDirName(options.tempDirName);
142
+ config.tempDirName = options.tempDirName;
112
143
  }
113
144
  if (options.thresholds) {
114
- builder.setThresholds(options.thresholds);
145
+ config.thresholds = options.thresholds;
115
146
  }
116
- return builder.build();
147
+ return config;
117
148
  };
118
149
 
119
150
  /* ------------------------------------------------------------------ */
@@ -230,7 +261,11 @@ StrykerWrapper.prototype._emptyNormalizedResult = function () {
230
261
  };
231
262
  };
232
263
  StrykerWrapper.prototype.getDefaultConfig = function () {
233
- return this._configBuilder.build();
264
+ var config = Object.assign({}, DEFAULTS, this._baseConfig);
265
+ if (config.concurrency == null) {
266
+ config.concurrency = Math.max(1, os.cpus().length - 1);
267
+ }
268
+ return config;
234
269
  };
235
270
  module.exports = StrykerWrapper;
236
271
  module.exports.DEFAULT_MUTATE_PATTERN = DEFAULT_MUTATE_PATTERN;
@@ -13,12 +13,18 @@ const {
13
13
  const {
14
14
  getLibraryInstalledLocation
15
15
  } = require('../General/getLibraryInstalledLocation');
16
+ function getProjectNodeModulesPath(projectPath) {
17
+ const normalizedPath = path.resolve(projectPath);
18
+ return path.basename(normalizedPath) === 'node_modules' ? normalizedPath : path.join(normalizedPath, 'node_modules');
19
+ }
16
20
  function getEslintExecutablePath() {
17
21
  let eslintLibraryName = 'eslint';
18
- let librariesInNodeModulesOfProject = executeSynchronizedCommands(readdirSync, [path.join(getNodeModulesPath(), 'node_modules')], '', 'Unable to get the plugins inside node_modules', true, false);
22
+ let nodeModulesPath = getProjectNodeModulesPath(getNodeModulesPath());
23
+ let librariesInNodeModulesOfProject = executeSynchronizedCommands(readdirSync, [nodeModulesPath], '', 'Unable to get the plugins inside node_modules', true, false);
19
24
  let isEslintInstalledinProject = librariesInNodeModulesOfProject.some(library => library === eslintLibraryName);
20
- return isEslintInstalledinProject ? path.join(getNodeModulesPath(), 'node_modules', eslintLibraryName, 'bin', 'eslint.js') : path.join(getLibraryInstalledLocation(), 'node_modules', eslintLibraryName, 'bin', 'eslint.js');
25
+ return isEslintInstalledinProject ? path.join(nodeModulesPath, eslintLibraryName, 'bin', 'eslint.js') : path.join(getLibraryInstalledLocation(), 'node_modules', eslintLibraryName, 'bin', 'eslint.js');
21
26
  }
22
27
  module.exports = {
23
- getEslintExecutablePath
28
+ getEslintExecutablePath,
29
+ getProjectNodeModulesPath
24
30
  };
@@ -70,13 +70,26 @@ function getSupportedLanguage() {
70
70
  _language.push('.tsx');
71
71
  _language.push('.css');
72
72
  _language.push('.scss');
73
+ _language.push('.feature');
73
74
  return [...new Set(_language)];
74
75
  }
75
76
  function getRunningEnv() {
76
- const command = "npm config get lint_env";
77
- return execSync(command, {
78
- shell: true
79
- }).toString().trim();
77
+ if (process.env.npm_config_lint_env) {
78
+ return String(process.env.npm_config_lint_env).trim();
79
+ }
80
+ if (process.env.LINT_ENV) {
81
+ return String(process.env.LINT_ENV).trim();
82
+ }
83
+ if (process.env.CI === "true" || process.env.CI === "1") {
84
+ return "CI";
85
+ }
86
+ try {
87
+ return execSync("npm config get lint_env", {
88
+ shell: true
89
+ }).toString().trim();
90
+ } catch {
91
+ return "";
92
+ }
80
93
  }
81
94
 
82
95
  /**
@@ -89,9 +102,12 @@ function getRunningEnv() {
89
102
 
90
103
  function getLastCommitHash() {
91
104
  try {
92
- var _JSON$parse$;
93
105
  const cmd = `curl --header "PRIVATE-TOKEN: ${process.env.TOOL_TOKEN}" --url ${commitHashEndPoint}`;
94
- return (_JSON$parse$ = JSON.parse(execSync(cmd))[0]) === null || _JSON$parse$ === void 0 ? void 0 : _JSON$parse$.id;
106
+ const response = execSync(cmd, {
107
+ encoding: 'utf-8',
108
+ timeout: 10000
109
+ });
110
+ return JSON.parse(response)[0]?.id;
95
111
  } catch (err) {
96
112
  Logger.log(Logger.FAILURE_TYPE, err);
97
113
  return null;
@@ -117,7 +133,9 @@ function updateJsonFile(filePath, modifier) {
117
133
  const rawData = fs.readFileSync(absolutePath, "utf-8");
118
134
  const jsonData = JSON.parse(rawData);
119
135
  const updatedData = modifier(jsonData);
120
- fs.writeFileSync(absolutePath, JSON.stringify(updatedData, null, 2), "utf-8");
136
+ const tempPath = `${absolutePath}.${process.pid}.${Date.now()}.tmp`;
137
+ fs.writeFileSync(tempPath, JSON.stringify(updatedData, null, 2), "utf-8");
138
+ fs.renameSync(tempPath, absolutePath);
121
139
  } catch (error) {
122
140
  Logger.log(Logger.FAILURE_TYPE, "Error updating JSON file");
123
141
  }
@@ -10,13 +10,24 @@ const {
10
10
  const {
11
11
  getLastCommitHash
12
12
  } = require('./getGeneralInfo');
13
+ function getProjectRootFromInstallPath(currentPath) {
14
+ const isWindowsAbsolutePath = /^[A-Za-z]:[\\/]/.test(String(currentPath));
15
+ const normalizedPath = (isWindowsAbsolutePath ? String(currentPath) : path.resolve(currentPath)).replace(/\\/g, '/');
16
+ const packageSuffix = '/node_modules/@zohodesk/codestandard-validator';
17
+ const suffixIndex = normalizedPath.lastIndexOf(packageSuffix);
18
+ if (suffixIndex !== -1) {
19
+ return path.normalize(normalizedPath.slice(0, suffixIndex));
20
+ }
21
+ return path.resolve(currentPath, '..', '..', '..');
22
+ }
13
23
  function writeFsPaths() {
14
24
  var fileContent = {
15
- nodeModulesPath: path.resolve(process.cwd(), '..', '..', '..'),
25
+ nodeModulesPath: getProjectRootFromInstallPath(process.cwd()),
16
26
  commitHash: getLastCommitHash()
17
27
  };
18
28
  return executeSynchronizedCommands(writeFileSync, [path.join(process.cwd(), 'jsonUtils', 'fsUtils.json'), JSON.stringify(fileContent), 'utf-8'], 'node_modules path updated in json file', 'Unable to write node_modules path to json file', false, true);
19
29
  }
20
30
  module.exports = {
21
- writeFsPaths
31
+ writeFsPaths,
32
+ getProjectRootFromInstallPath
22
33
  };
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
 
3
3
  const {
4
- existsSync
4
+ existsSync,
5
+ readFileSync
5
6
  } = require('fs');
6
7
  const path = require('path');
7
8
  const {
@@ -59,7 +60,8 @@ function checkIfPluginsAreInstalled() {
59
60
  isPluginPresent,
60
61
  pluginPath
61
62
  } = checkPluginsPresentInNodemodules(packageName); // circular installation loop so comment out
62
- if (isPluginPresent && checkPluginHasProperVersion(packageName, pluginPath, version)) {
63
+ // checkPluginHasProperVersion(packageName,pluginPath,version) remove version check due to unnecess
64
+ if (isPluginPresent) {
63
65
  return false;
64
66
  }
65
67
  return `${packageName}@${version}`;
@@ -110,7 +112,7 @@ function getPluginsToInstall() {
110
112
  * @returns {string} - which represents exactPluginVersion
111
113
  */
112
114
  function returnExactPluginVersion(pluginVersion) {
113
- return pluginVersion.replace(/[\^~]/, '');
115
+ return String(pluginVersion || '').replace(/[\^~]/, '');
114
116
  }
115
117
 
116
118
  /**
@@ -120,16 +122,24 @@ function returnExactPluginVersion(pluginVersion) {
120
122
  */
121
123
  function checkPluginsPresentInNodemodules(rulePluginName) {
122
124
  try {
123
- const pluginPath = require.resolve(rulePluginName.toString());
125
+ const pluginPath = require.resolve(path.join(rulePluginName.toString(), 'package.json'));
124
126
  return {
125
127
  pluginPath: pluginPath,
126
128
  isPluginPresent: existsSync(pluginPath)
127
129
  };
128
130
  } catch (error) {
129
- return {
130
- pluginPath: "",
131
- isPluginPresent: false
132
- };
131
+ try {
132
+ const pluginPath = require.resolve(rulePluginName.toString());
133
+ return {
134
+ pluginPath: path.join(path.dirname(pluginPath), 'package.json'),
135
+ isPluginPresent: existsSync(pluginPath)
136
+ };
137
+ } catch (_innerError) {
138
+ return {
139
+ pluginPath: "",
140
+ isPluginPresent: false
141
+ };
142
+ }
133
143
  }
134
144
  }
135
145
 
@@ -142,11 +152,15 @@ function checkPluginsPresentInNodemodules(rulePluginName) {
142
152
  */
143
153
 
144
154
  function checkPluginHasProperVersion(rulePluginName, installationPath, remotePluginVersion) {
145
- const pluginPathArray = installationPath.toString().split(rulePluginName);
146
- const rulePluginPackageJSONPath = path.join(pluginPathArray[0], rulePluginName, 'package.json');
147
- const remotePluginExactVersion = returnExactPluginVersion(remotePluginVersion);
148
- const packageJsonPluginExactVersion = returnExactPluginVersion(require(rulePluginPackageJSONPath).version);
149
- return remotePluginExactVersion == packageJsonPluginExactVersion ? true : false;
155
+ try {
156
+ const rulePluginPackageJSONPath = installationPath || require.resolve(path.join(rulePluginName.toString(), 'package.json'));
157
+ const remotePluginExactVersion = returnExactPluginVersion(remotePluginVersion);
158
+ const packageJsonPluginExactVersion = returnExactPluginVersion(JSON.parse(readFileSync(rulePluginPackageJSONPath, 'utf-8')).version);
159
+ return remotePluginExactVersion === packageJsonPluginExactVersion;
160
+ } catch (error) {
161
+ Logger.log(Logger.FAILURE_TYPE, `Unable to check plugin version for ${rulePluginName}`);
162
+ return false;
163
+ }
150
164
  }
151
165
  module.exports = {
152
166
  getPluginsToInstall,
package/changeLog.md CHANGED
@@ -37,29 +37,38 @@
37
37
 
38
38
  # 1.1.0 - SonarQube Enable
39
39
 
40
- 1. Enable sonarqube with flag with backward compactibility
40
+ 1. Enable sonarqube with flag with backward compactibility
41
41
 
42
42
  # 1.1.3 - SonarQube Enable
43
43
 
44
- 1. Remote Installtion flow moved to before and handled process.exit removed
44
+ 1. Remote Installtion flow moved to before and handled process.exit removed
45
45
 
46
46
  # 1.1.4 - Minor Bug Fixes
47
47
 
48
- 1. ProjectId api revamp
49
- 2. code standard analytics bin bind to code standard validator bin
48
+ 1. ProjectId api revamp
49
+ 2. code standard analytics bin bind to code standard validator bin
50
50
 
51
51
  # 1.2.4
52
52
 
53
- 1. Refactor configuration loading and linting process, update mandatory rules handling, and improve pre-commit hook functionality
53
+ 1. Refactor configuration loading and linting process, update mandatory rules handling, and improve pre-commit hook functionality
54
54
 
55
55
  # 1.3.4
56
56
 
57
- 1. Fix typo in environment variable name: `MANDARORY_RULES` corrected to `MANDATORY_RULES`
58
- 2. Fix typo in Config.js: `intialize` corrected to `initialize` for post-install execution
59
- 3. Remove unused `jest.setup.js` placeholder file
60
- 4. Version bump from `1.2.4-exp-7` to `1.2.4-exp-9`
57
+ 1. Fix typo in environment variable name: `MANDARORY_RULES` corrected to `MANDATORY_RULES`
58
+ 2. Fix typo in Config.js: `intialize` corrected to `initialize` for post-install execution
59
+ 3. Remove unused `jest.setup.js` placeholder file
60
+ 4. Version bump from `1.2.4-exp-7` to `1.2.4-exp-9`
61
61
 
62
62
  # 1.3.1 - Bug Fixes
63
63
 
64
- 1. Replace asynchronous `fs.rm` with synchronous `fs.rmSync` in folder cleanup utility to align with synchronized command execution.
65
- 2. Update package version from `1.3.0` to `1.3.1`.
64
+ 1. Replace asynchronous `fs.rm` with synchronous `fs.rmSync` in folder cleanup utility to align with synchronized command execution.
65
+ 2. Update package version from `1.3.0` to `1.3.1`.
66
+
67
+ # 1.4.0 - Mutation Refactor & Environment Detection
68
+
69
+ 1. Remove `StrykerConfigBuilder` class and simplify Stryker configuration to use a plain defaults object in `strykerWrapper.js`
70
+ 2. Refactor `mutationCli.js` and `mutationRunner.js` to work without the config builder abstraction
71
+ 3. Improve `getRunningEnv()` to read environment from `npm_config_lint_env`, `LINT_ENV`, and `CI` env vars before falling back to `npm config get`
72
+ 4. Add `.feature` file support in `getSupportedLanguage()` and include feature files in pre-commit hook linting
73
+ 5. Update `@zohodesk/codestandard-analytics` dependency to `1.1.6-node-18`
74
+ 6. Update unit tests for mutation modules to match refactored API
package/jest.config.js CHANGED
@@ -1,5 +1,4 @@
1
1
  module.exports = {
2
2
  testEnvironment: 'node',
3
- clearMocks: true,
4
- setupFilesAfterEnv: ['<rootDir>/jest.setup.js']
3
+ clearMocks: true
5
4
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zohodesk/codestandard-validator",
3
- "version": "1.3.1",
3
+ "version": "1.4.1-window-fix",
4
4
  "description": "library to enforce code standard using eslint",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -21,7 +21,7 @@
21
21
  "@stryker-mutator/jest-runner": "8.7.1",
22
22
  "@stryker-mutator/typescript-checker": "8.7.1",
23
23
  "@zohodesk-private/client_deployment_tool": "0.0.5",
24
- "@zohodesk/codestandard-analytics": "1.1.5",
24
+ "@zohodesk/codestandard-analytics": "1.2.0",
25
25
  "eslint": "8.26.0",
26
26
  "glob": "8.1.0",
27
27
  "jest": "29.7.0",