Repository: sasstools/sass-lint (js)

Issue:
Sass Syntax - Clean import paths issues
There are issues with the `clean-import-paths` rule when using the sass syntax as it's valid syntax to use without quotes. See guide http://sass-lang.com/guide

This in turn breaks the way we're detecting strings and validating them so a new way will need to be thought up.

Pull request:
Hotfix master - Fix Sass syntax issue with clean-import-paths rule
clean-import-paths doesn't work with Sass syntax. This fixes that issue.

Fixes #179 

DCO 1.1 Signed-off-by: Ben Griffith gt11687@gmail.com

Patch:
diff --git a/lib/helpers.js b/lib/helpers.js
index 2be0630..03834c2 100644
--- a/lib/helpers.js
+++ b/lib/helpers.js
@@ -149,4 +149,8 @@ helpers.loadConfigFile = function (configPath) {
   return file;
 };
 
+helpers.stripQuotes = function (str) {
+  return str.substring(1, str.length - 1);
+};
+
 module.exports = helpers;
diff --git a/lib/rules/clean-import-paths.js b/lib/rules/clean-import-paths.js
index d4bb8bb..47cda29 100644
--- a/lib/rules/clean-import-paths.js
+++ b/lib/rules/clean-import-paths.js
@@ -3,16 +3,50 @@
 var helpers = require('../helpers'),
     path = require('path');
 
-var stripQuotes = function (str) {
-  return str.substring(1, str.length - 1);
-};
+var getImportPath = function (parent, syntax) {
+  if (parent.first('uri')) {
+    return parent.first('uri');
+  }
 
-var getImportPath = function (parent) {
   if (parent.first('string')) {
-    return parent.first('string');
+    return helpers.stripQuotes(parent.first('string').content);
   }
-  else if (parent.first('uri')) {
-    return parent.first('uri');
+
+  if (parent.first('ident')) {
+
+    if (syntax === 'sass') {
+      var output = '',
+          isFinished = false;
+
+      parent.forEach(function (item) {
+        // Force an end if we've appended a 'class'.. aka file extension
+        if (!isFinished) {
+          // Since we don't have quotes, gonzales-pe will parse file path as
+          // multiple different types
+          if (
+            item.type === 'string'
+            || item.type === 'operator'
+            || item.type === 'ident'
+          ) {
+            output += item.content;
+          }
+
+          // Gonzales-pe parses file extensions as classes if they are not
+          // wrapped in quotes...
+          if (item.type === 'class') {
+            if (item.first('ident')) {
+              output += '.' + item.first('ident').content;
+            }
+
+            isFinished = true;
+          }
+        }
+      });
+
+      return output.trim();
+    }
+
+    return parent.first('ident');
   }
 
   return false;
@@ -28,59 +62,60 @@ module.exports = {
     var result = [];
 
     ast.traverseByType('atkeyword', function (keyword, i, parent) {
-      keyword.traverse(function (item) {
+      keyword.forEach(function (item) {
         if (item.content === 'import') {
-          var importPathNode = getImportPath(parent);
-
-          if (importPathNode && importPathNode.type === 'string') {
-            var importPath = stripQuotes(importPathNode.content),
-                filename = path.basename(importPath),
-                fileExtension = path.extname(filename);
-
-            if (fileExtension !== '.css') {
-              if (filename.charAt(0) === '_') {
-                if (!parser.options['leading-underscore']) {
-                  result = helpers.addUnique(result, {
-                    'ruleId': parser.rule.name,
-                    'line': item.start.line,
-                    'column': item.start.column,
-                    'message': 'Leading underscores are not allowed',
-                    'severity': parser.severity
-                  });
+          var importPath = getImportPath(parent, keyword.syntax);
+
+          if (importPath) {
+            if (typeof importPath === 'string') {
+              var filename = path.basename(importPath),
+                  fileExtension = path.extname(filename);
+
+              if (fileExtension !== '.css') {
+                if (filename.charAt(0) === '_') {
+                  if (!parser.options['leading-underscore']) {
+                    result = helpers.addUnique(result, {
+                      'ruleId': parser.rule.name,
+                      'line': item.start.line,
+                      'column': item.start.column,
+                      'message': 'Leading underscores are not allowed',
+                      'severity': parser.severity
+                    });
+                  }
                 }
-              }
-              else {
-                if (parser.options['leading-underscore']) {
-                  result = helpers.addUnique(result, {
-                    'ruleId': parser.rule.name,
-                    'line': item.start.line,
-                    'column': item.start.column,
-                    'message': 'Leading underscores are required',
-                    'severity': parser.severity
-                  });
+                else {
+                  if (parser.options['leading-underscore']) {
+                    result = helpers.addUnique(result, {
+                      'ruleId': parser.rule.name,
+                      'line': item.start.line,
+                      'column': item.start.column,
+                      'message': 'Leading underscores are required',
+                      'severity': parser.severity
+                    });
+                  }
                 }
-              }
 
-              if (fileExtension) {
-                if (!parser.options['filename-extension']) {
-                  result = helpers.addUnique(result, {
-                    'ruleId': parser.rule.name,
-                    'line': item.start.line,
-                    'column': item.start.column,
-                    'message': 'File extensions are not allowed',
-                    'severity': parser.severity
-                  });
+                if (fileExtension) {
+                  if (!parser.options['filename-extension']) {
+                    result = helpers.addUnique(result, {
+                      'ruleId': parser.rule.name,
+                      'line': item.start.line,
+                      'column': item.start.column,
+                      'message': 'File extensions are not allowed',
+                      'severity': parser.severity
+                    });
+                  }
                 }
-              }
-              else {
-                if (parser.options['filename-extension']) {
-                  result = helpers.addUnique(result, {
-                    'ruleId': parser.rule.name,
-                    'line': item.start.line,
-                    'column': item.start.column,
-                    'message': 'File extensions are required',
-                    'severity': parser.severity
-                  });
+                else {
+                  if (parser.options['filename-extension']) {
+                    result = helpers.addUnique(result, {
+                      'ruleId': parser.rule.name,
+                      'line': item.start.line,
+                      'column': item.start.column,
+                      'message': 'File extensions are required',
+                      'severity': parser.severity
+                    });
+                  }
                 }
               }
             }


Test patch:
diff --git a/tests/helpers.js b/tests/helpers.js
index 2dad1b3..07ba6d2 100644
--- a/tests/helpers.js
+++ b/tests/helpers.js
@@ -533,4 +533,24 @@ describe('helpers', function () {
     assert.equal(expect, result);
     done();
   });
+
+  //////////////////////////////
+  // Strip quotes
+  //////////////////////////////
+
+  it('stripQuotes - [double quotes]', function (done) {
+    var result = helpers.stripQuotes('"This is a string"'),
+        expect = 'This is a string';
+
+    assert.equal(expect, result);
+    done();
+  });
+
+  it('stripQuotes - [single quotes]', function (done) {
+    var result = helpers.stripQuotes('\'This is a string\''),
+        expect = 'This is a string';
+
+    assert.equal(expect, result);
+    done();
+  });
 });