Repository: tclindner/npm-package-json-lint
Pull request #36 (2017-05-22 19:04:30)

Add absolute version (dev)dependencies rule
I want my dependencies to be absolute versions (prefixed with '='), so that I get repeatable results (and application behavior) on repeated installs.

This pull request should add the needed rules for that.

If I missed anything, please tell me, I'm happy to improve this PR.

tclindner: Hi @chr1shaefn3r! Thank you so much for submitting a PR. This is a great addition. I would love to hear if you have other improvement ideas. 

Patch:
diff --git a/src/rules/prefer-absolute-version-dependencies.js b/src/rules/prefer-absolute-version-dependencies.js
new file mode 100644
index 0000000..588f0b4
--- /dev/null
+++ b/src/rules/prefer-absolute-version-dependencies.js
@@ -0,0 +1,21 @@
+'use strict';
+
+const areVersRangesValid = require('./../validators/dependency-audit').areVersRangesValid;
+const LintIssue = require('./../LintIssue');
+const lintId = 'prefer-absolute-version-dependencies';
+const nodeName = 'dependencies';
+const message = 'You are using an invalid version range. Please use absolute versions.';
+const ruleType = 'dependencies-version-range';
+
+const lint = function(packageJsonData, lintType) {
+  const rangeSpecifier = '=';
+
+  if (!areVersRangesValid(packageJsonData, nodeName, rangeSpecifier)) {
+    return new LintIssue(lintId, lintType, nodeName, message);
+  }
+
+  return true;
+};
+
+module.exports.lint = lint;
+module.exports.ruleType = ruleType;
diff --git a/src/rules/prefer-absolute-version-devDependencies.js b/src/rules/prefer-absolute-version-devDependencies.js
new file mode 100644
index 0000000..f3ec66e
--- /dev/null
+++ b/src/rules/prefer-absolute-version-devDependencies.js
@@ -0,0 +1,21 @@
+'use strict';
+
+const areVersRangesValid = require('./../validators/dependency-audit').areVersRangesValid;
+const LintIssue = require('./../LintIssue');
+const lintId = 'prefer-absolute-version-devDependencies';
+const nodeName = 'devDependencies';
+const message = 'You are using an invalid version range. Please use absolute versions.';
+const ruleType = 'devDependencies-version-range';
+
+const lint = function(packageJsonData, lintType) {
+  const rangeSpecifier = '=';
+
+  if (!areVersRangesValid(packageJsonData, nodeName, rangeSpecifier)) {
+    return new LintIssue(lintId, lintType, nodeName, message);
+  }
+
+  return true;
+};
+
+module.exports.lint = lint;
+module.exports.ruleType = ruleType;


Test patch:
diff --git a/tests/unit/rules/prefer-absolute-version-dependenciesTest.js b/tests/unit/rules/prefer-absolute-version-dependenciesTest.js
new file mode 100644
index 0000000..cea9834
--- /dev/null
+++ b/tests/unit/rules/prefer-absolute-version-dependenciesTest.js
@@ -0,0 +1,45 @@
+'use strict';
+
+const should = require('should');
+const requireHelper = require('../../require_helper');
+const lint = requireHelper('rules/prefer-absolute-version-dependencies').lint;
+
+describe('prefer-absolute-version-dependencies Unit Tests', function() {
+  context('when package.json has node with an invalid value', function() {
+    it('LintIssue object should be returned', function() {
+      const packageJsonData = {
+        dependencies: {
+          'npm-package-json-lint': '~1.0.0'
+        }
+      };
+      const response = lint(packageJsonData, 'error');
+
+      response.lintId.should.equal('prefer-absolute-version-dependencies');
+      response.lintType.should.equal('error');
+      response.node.should.equal('dependencies');
+      response.lintMessage.should.equal('You are using an invalid version range. Please use absolute versions.');
+    });
+  });
+
+  context('when package.json has node with a valid value (= prefixed)', function() {
+    it('LintIssue object should be returned', function() {
+      const packageJsonData = {
+        dependencies: {
+          'gulp-npm-package-json-lint': '=1.0.0'
+        }
+      };
+      const response = lint(packageJsonData, 'error');
+
+      response.should.be.true();
+    });
+  });
+
+  context('when package.json does not have node', function() {
+    it('true should be returned', function() {
+      const packageJsonData = {};
+      const response = lint(packageJsonData, 'error');
+
+      response.should.be.true();
+    });
+  });
+});
diff --git a/tests/unit/rules/prefer-absolute-version-devDependenciesTest.js b/tests/unit/rules/prefer-absolute-version-devDependenciesTest.js
new file mode 100644
index 0000000..64bd9a3
--- /dev/null
+++ b/tests/unit/rules/prefer-absolute-version-devDependenciesTest.js
@@ -0,0 +1,45 @@
+'use strict';
+
+const should = require('should');
+const requireHelper = require('../../require_helper');
+const lint = requireHelper('rules/prefer-absolute-version-devDependencies').lint;
+
+describe('prefer-absolute-version-devDependencies Unit Tests', function() {
+  context('when package.json has node with an invalid value', function() {
+    it('LintIssue object should be returned', function() {
+      const packageJsonData = {
+        devDependencies: {
+          'npm-package-json-lint': '~1.0.0'
+        }
+      };
+      const response = lint(packageJsonData, 'error');
+
+      response.lintId.should.equal('prefer-absolute-version-devDependencies');
+      response.lintType.should.equal('error');
+      response.node.should.equal('devDependencies');
+      response.lintMessage.should.equal('You are using an invalid version range. Please use absolute versions.');
+    });
+  });
+
+  context('when package.json has node with a valid value (= prefixed)', function() {
+    it('LintIssue object should be returned', function() {
+      const packageJsonData = {
+        devDependencies: {
+          'gulp-npm-package-json-lint': '=1.0.0'
+        }
+      };
+      const response = lint(packageJsonData, 'error');
+
+      response.should.be.true();
+    });
+  });
+
+  context('when package.json does not have node', function() {
+    it('true should be returned', function() {
+      const packageJsonData = {};
+      const response = lint(packageJsonData, 'error');
+
+      response.should.be.true();
+    });
+  });
+});