From 37732495d05aaab22e4d899b801de103e90d88a1 Mon Sep 17 00:00:00 2001 From: Jesse Sopel Date: Fri, 10 Nov 2017 22:17:17 -0500 Subject: [PATCH] Add: SASSLintBear Closes https://github.com/coala/coala-bears/issues/982 --- bear-requirements.yaml | 2 + bears/scss/SASSLintBear.py | 56 ++++++++++++++ package.json | 1 + tests/scss/SASSLintBearTest.py | 111 ++++++++++++++++++++++++++++ tests/scss/test_files/sass-lint.yml | 4 + 5 files changed, 174 insertions(+) create mode 100644 bears/scss/SASSLintBear.py create mode 100644 tests/scss/SASSLintBearTest.py create mode 100644 tests/scss/test_files/sass-lint.yml diff --git a/bear-requirements.yaml b/bear-requirements.yaml index 84ba9a909e..b051958afc 100644 --- a/bear-requirements.yaml +++ b/bear-requirements.yaml @@ -59,6 +59,8 @@ npm_requirements: version: ~5 remark-validate-links: version: ~5 + sass-lint: + version: ~1.12.1 standard: version: ~10 stylelint: diff --git a/bears/scss/SASSLintBear.py b/bears/scss/SASSLintBear.py new file mode 100644 index 0000000000..f53602c1ee --- /dev/null +++ b/bears/scss/SASSLintBear.py @@ -0,0 +1,56 @@ +import json +import os + +from coalib.bearlib.abstractions.Linter import linter +from dependency_management.requirements.NpmRequirement import NpmRequirement +from coalib.results.RESULT_SEVERITY import RESULT_SEVERITY +from coalib.results.Result import Result + + +@linter(executable='sass-lint') +class SASSLintBear: + """ + Check SCSS/SASS code to keep it clean and readable. + """ + + LANGUAGES = {'SCSS', 'SASS'} + REQUIREMENTS = {NpmRequirement('sass-lint', '1.12.1')} + AUTHORS = {'The coala developers'} + AUTHORS_EMAILS = {'coala-devel@googlegroups.com'} + LICENSE = 'AGPL-3.0' + CAN_DETECT = {'Syntax', 'Formatting'} + SEE_MORE = 'https://github.com/sasstools/sass-lint' + + severity_map = {2: RESULT_SEVERITY.MAJOR, + 1: RESULT_SEVERITY.NORMAL, + 0: RESULT_SEVERITY.INFO} + + @staticmethod + def create_arguments(filename, file, config_file, + sasslint_config: str = ''): + """ + :param sasslint_config: The location of the sass-lint config file. + """ + args = tuple() + if os.path.splitext(filename)[1] == '.scss': + args += ('--syntax=scss',) + if sasslint_config: + args += ('--config=' + sasslint_config,) + args += ('--format=json', '--verbose', '--no-exit', filename) + return args + + def process_output(self, output, filename, file): + if not file or not output: + return + + output = json.loads(output) + + for result in output[0]['messages']: + origin = ( + '{class_name} ({rule})'.format(class_name=type(self).__name__, + rule=result['ruleId']) + if result['ruleId'] is not None else self) + yield Result.from_values( + origin=origin, message=result['message'], + file=filename, line=result['line'], diffs=None, + severity=self.severity_map[result['severity']]) diff --git a/package.json b/package.json index 7ce8c3d3a3..dc5c6217ed 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "remark-cli": "~2", "remark-lint": "~5", "remark-validate-links": "~5", + "sass-lint": "~1.12.1", "standard": "~10", "stylelint": "~7", "stylint": "~1.5.9", diff --git a/tests/scss/SASSLintBearTest.py b/tests/scss/SASSLintBearTest.py new file mode 100644 index 0000000000..d81f698b5b --- /dev/null +++ b/tests/scss/SASSLintBearTest.py @@ -0,0 +1,111 @@ +import os + +from bears.scss.SASSLintBear import SASSLintBear +from coalib.testing.LocalBearTestHelper import verify_local_bear + +# Test examples from http://sass-lang.com/guide +good_sass_file = ''' +nav + ul + list-style: none + margin: 0 + padding: 0 + + li + display: inline-block + + a + display: block + padding: 6px 12px + text-decoration: none +''' + +bad_sass_file = ''' +nav + ul + margin: 0 + padding: 0 !important + err-style: none + + li + display: inline-block + + a + display: block + padding: 6px 12px + text-decoration: none +''' + +good_sass_file_with_config = ''' +nav + ul + margin: 0 + padding: 0 !important + + li + display: inline-block +''' + +good_scss_file = """ +nav { + ul { + list-style: none; + margin: 0; + padding: 0; + } + + li { display: inline-block; } + + a { + display: block; + padding: 6px 12px; + text-decoration: none; + } +} +""" + +bad_scss_file = """ +nav { + ul { + margin: 0 + padding: 0 + list-style: none + } + + li { display: inline-block; } + + a { + display: block; + padding: 6px 12px; + text-decoration: none; +} +""" + +test_dir = os.path.join(os.path.dirname(__file__), 'test_files') + +SASSLintBearTest = verify_local_bear( + SASSLintBear, + valid_files=(good_sass_file,), + invalid_files=(bad_sass_file,), + tempfile_kwargs={'suffix': '.sass'}) + +SASSLintBearSCSSTest = verify_local_bear( + SASSLintBear, + valid_files=(good_scss_file,), + invalid_files=(bad_scss_file,), + tempfile_kwargs={'suffix': '.scss'}) + +SASSLintBearConfigTest = verify_local_bear( + SASSLintBear, + valid_files=(good_sass_file_with_config,), + invalid_files=(bad_sass_file,), + tempfile_kwargs={'suffix': '.sass'}, + settings={'sasslint_config': os.path.join(test_dir, 'sass-lint.yml')}) + +SASSLintBearEmptyFileTest = verify_local_bear( + SASSLintBear, + valid_files=('',), + invalid_files=tuple(), + filename=os.path.join(test_dir, 'test.scss'), + tempfile_kwargs={'suffix': '.scss'}, + create_tempfile=False) diff --git a/tests/scss/test_files/sass-lint.yml b/tests/scss/test_files/sass-lint.yml new file mode 100644 index 0000000000..c6d202d6c4 --- /dev/null +++ b/tests/scss/test_files/sass-lint.yml @@ -0,0 +1,4 @@ +# Config file to allow !important to ensure it's loaded + +rules: + no-important: 0