@zohodesk/codestandard-validator 1.4.0 → 1.4.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.
@@ -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
  })();
@@ -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
  };
@@ -103,7 +103,11 @@ function getRunningEnv() {
103
103
  function getLastCommitHash() {
104
104
  try {
105
105
  const cmd = `curl --header "PRIVATE-TOKEN: ${process.env.TOOL_TOKEN}" --url ${commitHashEndPoint}`;
106
- return JSON.parse(execSync(cmd))[0]?.id;
106
+ const response = execSync(cmd, {
107
+ encoding: 'utf-8',
108
+ timeout: 10000
109
+ });
110
+ return JSON.parse(response)[0]?.id;
107
111
  } catch (err) {
108
112
  Logger.log(Logger.FAILURE_TYPE, err);
109
113
  return null;
@@ -129,7 +133,9 @@ function updateJsonFile(filePath, modifier) {
129
133
  const rawData = fs.readFileSync(absolutePath, "utf-8");
130
134
  const jsonData = JSON.parse(rawData);
131
135
  const updatedData = modifier(jsonData);
132
- 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);
133
139
  } catch (error) {
134
140
  Logger.log(Logger.FAILURE_TYPE, "Error updating JSON file");
135
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,
@@ -29,7 +29,7 @@ async function installPlugins(pluginsToBeInstalled) {
29
29
  Logger.log(Logger.INFO_TYPE, `Install command being executed: npm ${args.join(' ')}`);
30
30
  const result = spawnSync('npm', args, {
31
31
  cwd: getNodeModulesPath(),
32
- shell: false,
32
+ shell: true,
33
33
  encoding: 'utf8'
34
34
  });
35
35
  if (result.stdout) {
package/changeLog.md CHANGED
@@ -72,3 +72,14 @@
72
72
  4. Add `.feature` file support in `getSupportedLanguage()` and include feature files in pre-commit hook linting
73
73
  5. Update `@zohodesk/codestandard-analytics` dependency to `1.1.6-node-18`
74
74
  6. Update unit tests for mutation modules to match refactored API
75
+
76
+ # 1.4.1 - Windows Path and Pre-commit Stability Fixes
77
+
78
+ 1. Fix plugin discovery path handling for scoped packages by resolving `package.json` directly, preventing malformed module paths on Windows.
79
+ 2. Improve plugin version parsing and error handling to avoid hard failures during plugin validation when metadata is unavailable.
80
+ 3. Harden pre-commit initialization flow by adding deterministic async ordering and centralized startup error handling.
81
+ 4. Add timeout protection for remote commit-hash fetch to prevent long blocking in hook execution.
82
+ 5. Improve fsUtils update safety using temporary file write + rename to reduce partial-write risk.
83
+ 6. Derive project root from install path suffix instead of fixed directory traversal for cross-platform compatibility.
84
+ 7. Normalize ESLint config and plugin resolution paths in pre-commit lint flows for Windows/macOS/Linux parity.
85
+ 8. Add and update unit tests for plugin checks, install-path derivation, JSON update flow, and ESLint path resolution.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zohodesk/codestandard-validator",
3
- "version": "1.4.0",
3
+ "version": "1.4.2",
4
4
  "description": "library to enforce code standard using eslint",
5
5
  "main": "index.js",
6
6
  "scripts": {