class RubySecurityBear:
    """
    Checks the Security issues of Ruby Applications.

    It uses ``brakeman``.
    """

    LANGUAGES = {'Ruby'}
    REQUIREMENTS = {GemRequirement('brakeman', '4.1.1')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Security'}
    SEE_MORE = 'https://brakemanscanner.org/'

    severity_map = {
        'High': RESULT_SEVERITY.MAJOR,
        'Medium': RESULT_SEVERITY.NORMAL,
        'Weak': RESULT_SEVERITY.INFO
    }

    def create_arguments(self, config_file):
        files = tuple(self.file_dict.keys())
        app = os.path.dirname(os.path.commonprefix(files))
        return '-f', 'json', app

    def process_output(self, output, file, filename):
        if not output:  # backwards compatible no results
            return

        outputs = json.loads(output)
        for message_type, values in outputs.items():
            if message_type != 'warnings':
                continue

            for value in values:
                sourceranges = [
                    SourceRange.from_values(file=value['file'],
                                            start_line=value['line'],
                                            end_line=value['line'])
                ]

                if value['code'] is None:
                    message = "'{}': {}".format(value['check_name'],
                                                value['message'])

                else:
                    message = "'{}' (in '{}'): {}.".format(
                        value['check_name'], value['code'], value['message'])

                yield Result(
                    origin='{} ({})'.format(self.__class__.__name__,
                                            value['warning_type']),
                    message=message,
                    affected_code=sourceranges,
                    severity=self.severity_map[value['confidence']],
                    additional_info='More information is available at {}'
                    '.'.format(value['link']))
Esempio n. 2
0
class RubySyntaxBear:
    """
    Checks the code with ``ruby -wc`` on each file separately.
    """
    LANGUAGES = {'Ruby'}
    REQUIREMENTS = {GemRequirement('ruby', '2.1.5')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Syntax'}

    @staticmethod
    def create_arguments(filename, file, config_file):
        return '-wc', filename
class TravisLintBear:
    """
    A validator for your ``.travis.yml`` that attempts to reduce common build
    errors such as:

    - invalid YAML
    - missing language key
    - unsupported runtime versions of Ruby, PHP, OTP, etc.
    - deprecated features or runtime aliases
    """

    LANGUAGES = {'YAML'}
    REQUIREMENTS = {GemRequirement('travis', '1.8.8')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Formatting', 'Syntax'}
    SEE_MORE = 'https://docs.travis-ci.com/user/travis-lint'

    @classmethod
    def check_prerequisites(cls):
        base_check = super().check_prerequisites()
        if base_check is not True:
            return base_check

        check_connection_url = 'https://travis-ci.org/'
        url_status = cls.get_url_status(check_connection_url)

        try:
            if url_status is None:
                return 'You are not connected to the internet.'
            else:
                url_status.raise_for_status()
                return True
        except requests.exceptions.HTTPError:
            return 'Failed to establish a connection to {}.'.format(
                check_connection_url)

    @staticmethod
    def get_url_status(url):
        try:
            return requests.head(url, allow_redirects=False)
        except requests.exceptions.RequestException:
            return None

    @staticmethod
    def create_arguments(filename, file, config_file):
        return 'lint', filename
Esempio n. 4
0
class SQLintBear:
    """
    Check the given SQL files for syntax errors or warnings.

    This bear supports ANSI syntax. Check out
    <https://github.com/purcell/sqlint> for more detailed information.
    """

    LANGUAGES = {'SQL'}
    REQUIREMENTS = {GemRequirement('sqlint', '0.1.5')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Syntax'}

    @staticmethod
    def create_arguments(filename, file, config_file):
        return ()
Esempio n. 5
0
class PuppetLintBear:
    '''
    Check and correct puppet configuration files using ``puppet-lint``.

    See <http://puppet-lint.com/> for details about the tool.
    '''

    LANGUAGES = {'Puppet'}
    REQUIREMENTS = {GemRequirement('puppet-lint', '2.1.1')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    ASCIINEMA_URL = 'https://asciinema.org/a/87751'
    CAN_FIX = {'Syntax'}

    @staticmethod
    def create_arguments(filename, file, config_file):
        return ('--log-format', '%{line}:%{column}:%{kind}:%{message}',
                filename)
Esempio n. 6
0
class RubyFastererBear:
    """
    The ``RubyFastererBear`` will suggest some speed improvements which you
    can check in details at the <https://github.com/JuanitoFatas/fast-ruby>.

    It uses ``fasterer``. See <https://www.rubydoc.info/gems/fasterer/0.4.1>
    for more info.
    """

    LANGUAGES = {'Ruby'}
    REQUIREMENTS = {GemRequirement('fasterer', '0.4.1')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Complexity'}
    SEE_MORE = 'https://github.com/DamirSvrtan/fasterer'

    @staticmethod
    def create_arguments(filename, file, config_file):
        return filename,
Esempio n. 7
0
class TravisLintBear:
    """
    A validator for your ``.travis.yml`` that attempts to reduce common build
    errors such as:

    - invalid YAML
    - missing language key
    - unsupported runtime versions of Ruby, PHP, OTP, etc.
    - deprecated features or runtime aliases
    """

    LANGUAGES = {'YAML'}
    REQUIREMENTS = {GemRequirement('travis', '1.8.8')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Formatting', 'Syntax'}
    SEE_MORE = 'https://docs.travis-ci.com/user/travis-lint'

    @staticmethod
    def create_arguments(filename, file, config_file):
        return 'lint', filename
Esempio n. 8
0
class SCSSLintBear:
    """
    Check SCSS code to keep it clean and readable.

    More information is available at <https://github.com/brigade/scss-lint>.
    """

    LANGUAGES = {'SCSS'}
    REQUIREMENTS = {
        GemRequirement('scss-lint', '', 'false'),
        PipRequirement('pyyaml', '3.12')
    }
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Syntax', 'Formatting'}

    @staticmethod
    def create_arguments(filename, file, config_file):
        return filename, '--config', config_file

    @staticmethod
    def generate_config(filename,
                        file,
                        space_around_bang: list = [True, False],
                        allow_chained_classes: bool = False,
                        prefer_color_keywords: bool = False,
                        use_color_variables: bool = True,
                        allow_debug_statement: bool = False,
                        check_declaration_order: bool = True,
                        allow_duplicate_properties: bool = False,
                        allow_consecutives_duplicate_property: bool = False,
                        else_on_same_line: bool = True,
                        force_empty_line_between_blocks: bool = True,
                        allow_empty_rules: bool = False,
                        use_short_hexadecimal_length_style: bool = True,
                        use_lowercase_hexadecimal: bool = True,
                        validate_hexadecimal: bool = True,
                        allow_id_selector: bool = False,
                        allow_important_rule_in_properties: bool = False,
                        use_spaces: bool = True,
                        indent_size: int = 2,
                        exclude_leading_zero: bool = True,
                        allow_mergeable_selectors: bool = False,
                        allow_leading_underscore: bool = True,
                        function_naming_convention: str = 'hyphen',
                        mixin_naming_convention: str = 'hyphen',
                        variable_naming_convention: str = 'hyphen',
                        placeholder_naming_convention: str = 'hyphen',
                        max_nesting_depth: int = 3,
                        use_placeholder_selector_in_extend: bool = True,
                        max_properties: int = 10,
                        allow_unit_on_zero_values: bool = False,
                        check_ulrs_format: bool = True,
                        urls_in_quotes: bool = True,
                        allow_unnecesseary_parent_reference: bool = False,
                        allow_unnecessary_mantissa: bool = False,
                        allow_trailing_whitespaces: bool = False,
                        allow_trailing_semicolon: bool = True,
                        check_imports_path: bool = True,
                        allow_filename_leading_underscore: bool = False,
                        allow_filename_extension: bool = False,
                        use_length_variables: bool = True,
                        check_properties_spelling: bool = True,
                        extra_properties: list = (),
                        disabled_properties: list = (),
                        check_pseudo_elements: bool = True,
                        spaces_between_parentheses: int = 0,
                        spaces_around_operators: str = 1):
        """
        :param space_around_bang:
            Enforces a space before and/or after ``!`` (the "bang").
        :param allow_chained_classes:
            Allows defining a rule set using a selector with chained classes.
        :param prefer_color_keywords:
            Prefers color keywords over hexadecimal color codes.
        :param use_color_variables:
            Prefers color literals (keywords or hexadecimal codes) to be used
            only in variable declarations.
        :param allow_debug_statement:
            Allows ``@debug`` statements.
        :param check_declaration_order:
            Rule sets should be ordered as follows: ``@extend`` declarations,
            ``@include`` declarations without inner ``@content``, properties,
            ``@include`` declarations with inner ``@content``, then nested rule
            sets.
        :param allow_duplicate_properties:
            Allows defining the same property twice in a single rule set.
        :param allow_consecutives_duplicate_property:
            Allows defining the same property consecutively in a single rule
            set.
        :param else_on_same_line:
            Places ``@else`` statements on the same line as the preceding curly
            brace.
        :param force_empty_line_between_blocks:
            Separate rule, function, and mixin declarations with empty lines.
        :param allow_empty_rules:
            Allows empty rule set.
        :param use_short_hexadecimal_length_style:
            Prefer shorthand or long-form hexadecimal colors by setting the
            style option to short or long, respectively.
        :param use_lowercase_hexadecimal:
            Checks if hexadecimal colors are written in lowercase or uppercase.
        :param validate_hexadecimal:
            Ensure hexadecimal colors are valid (either three or six digits).
        :param allow_id_selector:
            Allows using ID selectors.
        :param allow_important_rule_in_property:
            Allows using ``!important`` in properties.
        :param use_spaces:
            Use spaces for indentation (tabs otherwise).
        :param indent_size:
            Number of spaces per indentation level.
        :param exclude_leading_zero:
            Determines whether leading zeros should be written or not in
            numeric values with a decimal point.
        :param allow_mergeable_selectors:
            Allows defining the same selector twice in a single sheet.
        :param allow_leading_underscore:
            Allows names to start with a single underscore.
        :param function_naming_convention:
            Name of convention (``hyphen``(use lowercase letters and hyphens)
            (default), ``camel``, ``snake``), or a ``regex`` the name must
            match (eg: ``^[a-zA-Z]+$``) to use for functions.
        :param mixin_naming_convention:
            Name of convention (``hyphen`` (default), ``camel``, ``snake``), or
            a regex the name must match (eg: ``^[a-zA-Z]+$``) to use for
            mixins.
        :param variable_naming_convention:
            Name of convention (``hyphen`` (default), ``camel``, ``snake``), or
            a regex the name must match (eg: ``^[a-zA-Z]+$``) to use for
            variables.
        :param placeholder_naming_convention:
            Name of convention (``hyphen`` (default), ``camel``, ``snake``), or
            a regex the name must match (eg: ``^[a-zA-Z]+$``) to use for
            placeholders.
        :param max_nesting_depth:
            Maximum nesting depth.
        :param use_placeholder_selector_in_extend:
            Enforces using placeholder selectors in ``@extend``.
        :param max_properties:
            Enforces a limit on the number of properties in a rule set.
        :param allow_unit_on_zero_values:
            Allow omitting length units on zero values.
        :param check_urls_format:
            URLs should be valid and not contain protocols or domain names.
        :param urls_in_quotes:
            URLs should always be enclosed within quotes.
        :param allow_unnecessary_parent_reference:
            Allows use of the parent selector references ``&`` even when they
            are not unnecessary.
        :param allow_unnecessary_mantissa:
            Numeric values can contain unnecessary fractional portions.
        :param allow_traling_whitespaces:
            Unables trailing whitespace.
        :param allow_trailing_semicolon:
            Property values; ``@extend``, ``@include``, and ``@import``
            directives; and variable declarations should always end with a
            semicolon.
        :param check_imports_path:
            The basenames of ``@import``ed SCSS partials should not begin with
            an underscore and should not include the filename extension.
            These requirements can be modified by changing
            ``allow_filename_leading_underscore``, and ``allow_extensions``.
        :param allow_filename_leading_underscore:
            Requires basenames of ``@import``ed SCSS partials to begin with an
            underscore.  This setting require ``check_import_paths`` to be
            enabled.
        :param allow_filename_extension:
            Requires basenames of ``@import``ed SCSS partials to include
            filename extension, this setting require ``check_import_paths`` to
            be enabled.
        :param use_length_variables:
            Prefer length literals (numbers with units) to be used only in
            variable declarations.

            ::
                 div {
                   width: 100px;
                 }

            Is not valid, whereas

            ::
                 $column-width: 100px;

                 div {
                   width: $column-width;
                 }
            is valid.
        :param check_properties_spelling:
            Reports when an unknown or disabled CSS property is used
            (ignoring vendor-prefixed properties).
        :param extra_properties:
            List of extra properties to allow.
        :param disabled_properties:
            List of existing properties to deny.
        :param check_pseudo_elements:
            Pseudo-elements, like ``::before``, and ``::first-letter``,
            should be declared with two colons. Pseudo-classes, like ``:hover``
            and ``:first-child``, should be declared with one colon.

            ::
                p::before {
                  content: '>'
                }

                p:hover {
                  color: red;
                }

        :param spaces_between_parentheses:
            Spaces to require between parentheses.
        :param spaces_around_operators:
            Operators should be formatted with a single space on both sides of
            an infix operator. The different value for this setting are ``1``,
            ``0`` or a number greater that ``1``.
        """
        naming_convention_map = {
            'camel': 'camel_case',
            'snake': 'snake_case',
            'hyphen': 'hyphenated_lowercase'
        }
        space_setting_map = {'one_space': 1, 'no_space': 0}
        options = {
            'BangFormat': {
                'enabled': True,
                'space_before_bang': space_around_bang[0],
                'space_after_bang': space_around_bang[1]
            },
            'ChainedClasses': {
                'enabled': not allow_chained_classes
            },
            'ColorKeyword': {
                'enabled': not prefer_color_keywords
            },
            'ColorVariable': {
                'enabled': use_color_variables
            },
            'DebugStatement': {
                'enabled': not allow_debug_statement
            },
            'DeclarationOrder': {
                'enabled': check_declaration_order
            },
            'DuplicateProperty': {
                'enabled': not allow_duplicate_properties,
                'ignore_consecutive': allow_consecutives_duplicate_property
            },
            'ElsePlacement': {
                'enabled': True,
                'style': ('same_line' if else_on_same_line else '')
            },
            'EmptyLineBetweenBlocks': {
                'enabled': force_empty_line_between_blocks,
                'ignore_single_line_blocks': True
            },
            'EmptyRule': {
                'enabled': not allow_empty_rules
            },
            'HexLength': {
                'enabled':
                True,
                'style':
                ('short' if use_short_hexadecimal_length_style else 'long')
            },
            'HexNotation': {
                'enabled':
                True,
                'style':
                ('lowercase' if use_lowercase_hexadecimal else 'uppercase')
            },
            'HexValidation': {
                'enabled': validate_hexadecimal
            },
            'IdSelector': {
                'enabled': not allow_id_selector
            },
            'ImportantRule': {
                'enabled': not allow_important_rule_in_properties
            },
            'Indentation': {
                'enabled': True,
                'allow_non_nested_indentation': False,
                'character': ('space' if use_spaces else 'tab'),
                'width': indent_size
            },
            'LeadingZero': {
                'enabled':
                True,
                'style':
                ('exclude_zero' if exclude_leading_zero else 'include_zero')
            },
            'MergeableSelector': {
                'enabled': allow_mergeable_selectors,
                'force_nesting': True
            },
            'NestingDepth': {
                'enabled': True,
                'max_depth': max_nesting_depth,
                'ignore_parent_selectors': False
            },
            'NameFormat': {
                'enabled':
                True,
                'allow_leading_underscore':
                allow_leading_underscore,
                'function_convention':
                naming_convention_map.get(function_naming_convention,
                                          function_naming_convention),
                'mixin_convention':
                naming_convention_map.get(mixin_naming_convention,
                                          mixin_naming_convention),
                'variable_convention':
                naming_convention_map.get(variable_naming_convention,
                                          variable_naming_convention),
                'placeholder_convention':
                naming_convention_map.get(placeholder_naming_convention,
                                          placeholder_naming_convention)
            },
            'PlaceholderInExtend': {
                'enabled': use_placeholder_selector_in_extend
            },
            'PropertyCount': {
                'enabled': False,
                'include_nested': False,
                'max_properties': max_properties
            },
            'ZeroUnit': {
                'enabled': not allow_unit_on_zero_values
            },
            'UrlFormat': {
                'enabled': check_ulrs_format
            },
            'UrlQuotes': {
                'enabled': urls_in_quotes
            },
            'UnnecessaryMantissa': {
                'enabled': not allow_unnecessary_mantissa
            },
            'UnnecessaryParentReference': {
                'enabled': not allow_unnecesseary_parent_reference
            },
            'TrailingSemicolon': {
                'enabled': allow_trailing_semicolon
            },
            'TrailingWhitespace': {
                'enabled': not allow_trailing_whitespaces
            },
            'ImportPath': {
                'enabled': check_imports_path,
                'leading_underscore': allow_filename_leading_underscore,
                'filename_extension': allow_filename_extension
            },
            'LengthVariable': {
                'enabled': use_length_variables
            },
            'PropertySpelling': {
                'enabled': check_properties_spelling,
                'extra_properties': extra_properties,
                'disabled_properties': disabled_properties
            },
            'SpaceBetweenParens': {
                'enabled': True,
                'spaces': spaces_between_parentheses
            },
            'SpaceAroundOperator': {
                'enabled':
                True,
                'style':
                space_setting_map.get(spaces_around_operators,
                                      'at_least_one_space')
            }
        }
        configs = {'linters': options}
        return yaml.dump(configs, default_flow_style=False)
Esempio n. 9
0
class CSVLintBear:
    """
    Verifies using ``csvlint`` if ``.csv`` files are valid CSV or not.
    """

    LANGUAGES = {'CSV'}
    REQUIREMENTS = {GemRequirement('csvlint')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Syntax'}
    ASCIINEMA_URL = 'https://asciinema.org/a/8fmp2pny34kpqw7t1eoy7phhc'

    regex = re.compile(r'\n\d+\.\s(?P<origin>(?P<severity>\w+))\.\s'
                       r'(Row:\s(?P<line>[0-9]+)\.\s)?(?P<message>.*)?')

    severity_map = {
        'wrong_content_type': RESULT_SEVERITY.MAJOR,
        'ragged_rows': RESULT_SEVERITY.MAJOR,
        'blank_rows': RESULT_SEVERITY.MAJOR,
        'invalid_encoding': RESULT_SEVERITY.MAJOR,
        'not_found': RESULT_SEVERITY.MAJOR,
        'stray_quote': RESULT_SEVERITY.MAJOR,
        'unclosed_quote': RESULT_SEVERITY.MAJOR,
        'whitespace': RESULT_SEVERITY.MAJOR,
        'line_breaks': RESULT_SEVERITY.MAJOR,
        'no_encoding': RESULT_SEVERITY.NORMAL,
        'encoding': RESULT_SEVERITY.NORMAL,
        'no_content_type': RESULT_SEVERITY.NORMAL,
        'excel': RESULT_SEVERITY.NORMAL,
        'check_options': RESULT_SEVERITY.NORMAL,
        'inconsistent_values': RESULT_SEVERITY.NORMAL,
        'empty_column_name': RESULT_SEVERITY.NORMAL,
        'duplicate_column_name': RESULT_SEVERITY.NORMAL,
        'title_row': RESULT_SEVERITY.NORMAL,
        'nonrfc_line_breaks': RESULT_SEVERITY.INFO,
        'assumed_header': RESULT_SEVERITY.INFO}

    message_dict = {
        'wrong_content_type': 'Content type is not text/csv.',
        'ragged_rows': 'Row has a different number of columns. (than the first'
                        ' row in the file)',
        'blank_rows': 'Completely empty row, e.g. blank line or a line where'
                       ' all column values are empty.',
        'invalid_encoding': 'Encoding error when parsing row, e.g. because of'
                             ' invalid characters.',
        'not_found': 'HTTP 404 error when retrieving the data.',
        'stray_quotd': 'Missing or stray quote.',
        'unclosed_quotd': 'Unclosed quoted field.',
        'whitespacd': 'A quoted column has leading or trailing whitespace.',
        'line_breakd': 'Line breaks were inconsistent or incorrectly'
                         ' specified.',
        'no_encodind': 'The Content-Type header returned in the HTTP request'
                         ' does not have a charset parameter.',
        'encoding': 'The character set is not UTF-8.',
        'no_content_type': 'File is being served without a Content-Type'
                           ' header.',
        'excel': 'No Content-Type header and the file extension is .xls.',
        'check_optiond': 'CSV file appears to contain only a single column.',
        'inconsistent_valued': 'Inconsistent values in the same column.'
                               ' Reported if <90% of values seem to have same'
                               ' data type. (either numeric or alphanumeric'
                               ' including punctuation)',
        'empty_column_name': 'A column in the CSV header has an empty name.',
        'duplicate_column_name': 'A column in the CSV header has a duplicate'
                                 ' name.',
        'title_rod': 'There appears to be a title field in the first row of'
                      ' the CSV.',
        'nonrfc_line_breakd': 'Uses non-CRLF line breaks, so does not conform'
                              ' to RFC4180.',
        'assumed_headed': 'The validator has assumed that a header is present.'
    }

    @staticmethod
    def create_arguments(filename, file, config_file):
        return filename,

    @classmethod
    def process_output(self, output, filename, file, result_message=None):
        for match in re.finditer(self.regex, str(output)):
            groups = match.groupdict()
            result_message = ' ' + groups['message'] if groups[
                'line'] is None else ''
            yield self._convert_output_regex_match_to_result(
                self,
                match, filename, severity_map=self.severity_map,
                result_message=self.message_dict[groups['origin']] +
                               result_message)
Esempio n. 10
0
class RuboCopBear:
    """
    Check Ruby code for syntactic, formatting as well as semantic problems.

    See <https://github.com/bbatsov/rubocop#cops> for more information.
    """

    LANGUAGES = {'Ruby'}
    REQUIREMENTS = {
        GemRequirement('rubocop', '0.47.1'),
        PipRequirement('pyyaml', '3.12')
    }
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    ASCIINEMA_URL = 'https://asciinema.org/a/39241'
    CAN_DETECT = {'Simplification'}
    CAN_FIX = {'Syntax', 'Formatting'}

    severity_map = {
        'error': RESULT_SEVERITY.MAJOR,
        'warning': RESULT_SEVERITY.NORMAL,
        'convention': RESULT_SEVERITY.INFO
    }

    @staticmethod
    def create_arguments(filename,
                         file,
                         config_file,
                         rubocop_config: str = ''):
        # Need both stdin and filename. Explained in this comment:
        # https://github.com/bbatsov/rubocop/pull/2146#issuecomment-131403694
        args = (filename, '--stdin', '--format=json')
        if rubocop_config:
            args += ('--config', rubocop_config)
        else:
            args += ('--config', config_file)
        return args

    @staticmethod
    @deprecate_settings(indent_size='tab_width',
                        method_length_count_comments='method_count_comments',
                        method_naming_convention='method_name_case',
                        variable_naming_convention='variable_name_case')
    def generate_config(filename,
                        file,
                        access_modifier_indentation: str = 'indent',
                        preferred_alias: str = 'prefer_alias',
                        align_hash_rocket_by: str = 'key',
                        align_colon_by: str = 'key',
                        inspect_last_argument_hash: str = 'always_inspect',
                        align_parameters: str = 'with_first_parameter',
                        class_check: str = 'is_a?',
                        comment_keywords: tuple = ('TODO', 'FIXME', 'OPTIMIZE',
                                                   'HACK', 'REVIEW'),
                        min_if_unless_guard: int = 1,
                        indent_size: int = 2,
                        method_naming_convention: str = 'snake',
                        string_literals: str = 'single_quotes',
                        variable_naming_convention: str = 'snake',
                        max_class_length: int = 100,
                        class_length_count_comments: bool = False,
                        max_module_length: int = 100,
                        module_length_count_comments: bool = False,
                        cyclomatic_complexity: int = 6,
                        max_line_length: int = 79,
                        line_length_allow_here_doc: bool = True,
                        line_length_allow_uri: bool = True,
                        max_method_length: int = 10,
                        method_length_count_comments: bool = False,
                        max_parameters: int = 5,
                        count_keyword_args: bool = True,
                        ignore_unused_block_args_if_empty: bool = True,
                        allow_unused_block_keyword_arguments: bool = False,
                        ignore_unused_method_args_if_empty: bool = True,
                        allow_unused_method_keyword_args: bool = False,
                        rubocop_config: str = ''):
        """
        Not all settings added.
        Notable settings missing: Rails settings.

        :param access_modifier_indentation:
            Indent private/protected/public as deep as method definitions
            options:
                ``indent`` :  Indent modifiers like class members.
                ``outdent`` : Indent modifiers one level less than
                              class members.
        :param preferred_alias:
            Which method to use for aliasing in ruby.
            options : ``alias`` , ``alias_method``.
        :param align_hash_rocket_by:
            Alignment of entries using hash rocket as separator.
        :param align_colon_by:
            Alignment of entries using colon as separator.
        :param inspect_last_argument_hash:
            Select whether hashes that are the last argument in a method call
            should be inspected.
            options: ``always_inspect``, ``always_ignore``,
                     ``ignore_implicit``, ``ignore_explicit``.
        :param align_parameters:
            Alignment of parameters in multi-line method calls.

            options:
                ``with_first_parameter``: Aligns the following lines
                                          along the same column as the
                                          first parameter.

                ``with_fixed_indentation``: Aligns the following lines with one
                                            level of indentation relative to
                                            the start of the line with the
                                            method call.
        :param class_check:
            How to check type of class.
            options: ``is_a?``, ``kind_of?``.
        :param comment_keywords:
            Checks formatting of special comments based on keywords like
            TODO, FIXME etc.
        :param min_if_unless_guard:
            The number of lines that are tolerable within an if/unless block,
            more than these lines call for the usage of a guard clause.
        :param indent_size:
            Number of spaces per indentation level.
        :param method_naming_convention:
            Case of a method's name.
            options: ``snake``, ``camel``.
        :param string_literals:
            Use ' or " as string literals.
            options: ``single_quotes``, ``double_quotes``.
        :param variable_naming_convention:
            Case of a variable's name.
            options: ``snake``, ``camel``.
        :param max_class_length:
            Max lines in a class.
        :param class_length_count_comments:
            Whether or not to count comments while calculating the class
            length.
        :param max_module_length:
            Max lines in a module.
        :param module_length_count_comments:
            Whether or not to count comments while calculating
            the module length.
        :param cyclomatic_complexity:
            Cyclomatic Complexity of the file.
        :param max_line_length:
            Max length of a line.
        :param line_length_allow_here_doc:
            Allow here-doc lines to be more than the max line length.
        :param line_length_allow_uri:
            To make it possible to copy or click on URIs in the code,
            we allow ignore long lines containing a URI to be longer than max
            line length.
        :param max_method_length:
            Max number of lines in a method.
        :param method_length_count_comments:
            Whether or not to count full line comments while calculating
            method length.
        :param max_parameters:
            Max number of parameters in parameter list.
        :param count_keyword_args:
            Count keyword args while counting all arguments?
        :param ignore_unused_block_args_if_empty:
            Ignore unused block arguments if block is empty.
        :param allow_unused_block_keyword_arguments:
            Allow unused block keyword arguments.
        :param ignore_unused_method_args_if_empty:
            Allows unused method argument if method is empty.
        :param allow_unused_method_keyword_args:
            Allows unused keyword arguments in a method.
        """
        if rubocop_config:
            return None

        naming_convention = {'camel': 'camelCase', 'snake': 'snake_case'}
        options = {
            'Style/AccessModifierIndentation': {
                'EnforcedStyle': access_modifier_indentation
            },
            'Style/Alias': {
                'EnforcedStyle': preferred_alias
            },
            'Style/AlignHash': {
                'EnforcedHashRocketStyle': align_hash_rocket_by,
                'EnforcedColonStyle': align_colon_by,
                'EnforcedLastArgumentHashStyle': inspect_last_argument_hash
            },
            'Style/AlignParameters': {
                'EnforcedStyle': align_parameters
            },
            'Style/ClassCheck': {
                'EnforcedStyle': class_check
            },
            'Style/CommentAnnotation': {
                'Keywords': comment_keywords
            },
            'Style/GuardClause': {
                'MinBodyLength': min_if_unless_guard
            },
            'Style/IndentationWidth': {
                'Width': indent_size
            },
            'Style/MethodName': {
                'EnforcedStyle':
                naming_convention.get(method_naming_convention,
                                      method_naming_convention)
            },
            'Style/StringLiterals': {
                'EnforcedStyle': string_literals
            },
            'Style/VariableName': {
                'EnforcedStyle':
                naming_convention.get(variable_naming_convention,
                                      variable_naming_convention)
            },
            'Metrics/ClassLength': {
                'Max': max_class_length,
                'CountComments': class_length_count_comments
            },
            'Metrics/ModuleLength': {
                'CountComments': module_length_count_comments,
                'Max': max_module_length
            },
            'Metrics/CyclomaticComplexity': {
                'Max': cyclomatic_complexity
            },
            'Metrics/LineLength': {
                'Max': max_line_length,
                'AllowHeredoc': line_length_allow_here_doc,
                'AllowURI': line_length_allow_uri
            },
            'Metrics/MethodLength': {
                'CountComments': method_length_count_comments,
                'Max': max_method_length
            },
            'Metrics/ParameterLists': {
                'Max': max_parameters,
                'CountKeywordArgs': count_keyword_args
            },
            'Lint/UnusedBlockArgument': {
                'IgnoreEmptyBlocks': ignore_unused_block_args_if_empty,
                'AllowUnusedKeywordArguments':
                allow_unused_block_keyword_arguments
            },
            'Lint/UnusedMethodArgument': {
                'AllowUnusedKeywordArguments':
                allow_unused_method_keyword_args,
                'IgnoreEmptyMethods': ignore_unused_method_args_if_empty
            },
        }
        return yaml.dump(options, default_flow_style=False)

    def process_output(self, output, filename, file):
        output = json.loads(output)
        assert len(output['files']) == 1
        for result in output['files'][0]['offenses']:
            # TODO: Add condition for auto-correct, when rubocop is updated.
            # Relevant Issue: https://github.com/bbatsov/rubocop/issues/2932
            yield Result.from_values(
                origin='{class_name} ({rule})'.format(
                    class_name=self.__class__.__name__,
                    rule=result['cop_name']),
                message=result['message'],
                file=filename,
                diffs=None,
                severity=self.severity_map[result['severity']],
                line=result['location']['line'],
                column=result['location']['column'],
                # Tested with linebreaks, it's secure.
                end_column=result['location']['column'] +
                result['location']['length'])
Esempio n. 11
0
class RubySmellBear:
    """
    Detect code smells in Ruby source code.

    For more information about the detected smells, see
    <https://github.com/troessner/reek/blob/master/docs/Code-Smells.md>.
    """

    LANGUAGES = {'Ruby'}
    REQUIREMENTS = {GemRequirement('reek')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Smell'}

    @staticmethod
    def create_arguments(filename, file, config_file):
        return '--format', 'json', '-c', config_file

    def process_output(self, output, filename, file):
        output = json.loads(output) if output else ()
        for issue in output:
            sourceranges = []
            for line in issue['lines']:
                sourceranges.append(
                    SourceRange.from_values(file=filename, start_line=line))

            if 'name' in issue:
                message = "'{}' (in '{}') {}.".format(issue['name'],
                                                      issue['context'],
                                                      issue['message'])
            else:
                message = "'{}' {}".format(issue['context'], issue['message'])

            yield Result(origin='{} ({})'.format(self.__class__.__name__,
                                                 issue['smell_type']),
                         message=message,
                         affected_code=sourceranges,
                         additional_info='More information is available at {}'
                         '.'.format(issue['wiki_link']))

    @deprecate_settings(
        allow_duplicate_method=('duplicate_method_call', negate),
        allow_data_clump=('data_clump', negate),
        allow_control_parameters=('control_parameter', negate),
        allow_class_variables=('class_variable', negate),
        allow_boolean_parameter_in_functions=('boolean_parameter', negate),
        allow_setter_in_classes=('attribute', negate),
        allow_unused_private_methods=('unused_private_method', negate),
        allow_unused_variables=('unused_params', negate))
    def generate_config(
        self,
        allow_setter_in_classes: bool = False,
        allow_boolean_parameter_in_functions: bool = False,
        allow_class_variables: bool = False,
        allow_control_parameters: bool = False,
        allow_data_clump: bool = False,
        allow_duplicate_method: bool = False,
        feature_envy: bool = True,
        missing_module_description: bool = True,
        long_param_list: bool = True,
        long_yield_list: bool = True,
        module_initialize: bool = True,
        nested_iterators: bool = True,
        nil_check: bool = True,
        prima_donna_method: bool = True,
        repeated_conditional: bool = True,
        too_many_instance_variables: bool = True,
        too_many_methods: bool = True,
        too_long_method: bool = True,
        bad_method_name: bool = True,
        bad_module_name: bool = True,
        bad_param_name: bool = True,
        bad_var_name: bool = True,
        allow_unused_variables: bool = False,
        allow_unused_private_methods: bool = True,
        utility_function: bool = True,
    ):
        """
        :param allow_setter_in_classes:
            Allows setter in classes.
        :param allow_boolean_parameter_in_functions:
            Allows boolean parameter in functions (control coupling).
        :param allow_class_variables:
            Allows class variables.
        :param allow_control_parameters:
            Allows parameters that control function behaviour (control
            coupling).
        :param allow_data_clump:
            Does not warn when the same two or three items frequently appear
            together in function/class parameter list.
        :param allow_duplicate_method:
            Allows having two fragments of code that look nearly identical, or
            two fragments of code that have nearly identical effects at some
            conceptual level.
        :param feature_envy:
            Occurs when a code fragment references another object more often
            than it references itself, or when several clients do the same
            series of manipulations on a particular type of object.
        :param missing_module_description:
            Warns if a module description is missing.
        :param long_param_list:
            Warns about too many parameters of functions.
        :param long_yield_list:
            Warns when a method yields a lot of arguments to the block it gets
            passed.
        :param module_initialize:
            Warns about ``#initialize`` methods in modules.
        :param nested_iterators:
            Warns when a block contains another block.
        :param nil_check:
            Warns about nil checks.
        :param prima_donna_method:
            Warns about methods whose names end with an exclamation mark.
        :param repeated_conditional:
            Warns about repeated conditionals.
        :param too_many_instance_variables:
            Warns for too many instance variables.
        :param too_many_methods:
            Warns if a class has too many methods.
        :param too_long_method:
            Warns about huge methods.
        :param bad_method_name:
            Warns about method names which are not communicating the purpose
            of the method well.
        :param bad_module_name:
            Warns about module names which are not communicating the purpose
            of the module well.
        :param bad_param_name:
            Warns about parameter names which are not communicating the purpose
            of the parameter well.
        :param bad_var_name:
            Warns about variable names which are not communicating the purpose
            of the variable well.
        :param allow_unused_variables:
            Allows unused parameters though they are dead code.
        :param check_unused_private_methods:
            Warns about unused private methods, as they are dead code.
        :param utility_function:
            Allows any instance method that has no dependency on the state of
            the instance.
        """
        config = {
            'Attribute': not allow_setter_in_classes,
            'BooleanParameter': not allow_boolean_parameter_in_functions,
            'ClassVariable': not allow_class_variables,
            'ControlParameter': not allow_control_parameters,
            'DataClump': not allow_data_clump,
            'DuplicateMethodCall': not allow_duplicate_method,
            'FeatureEnvy': feature_envy,
            'IrresponsibleModule': missing_module_description,
            'LongParameterList': long_param_list,
            'LongYieldList': long_yield_list,
            'ModuleInitialize': module_initialize,
            'NestedIterators': nested_iterators,
            'NilCheck': nil_check,
            'PrimaDonnaMethod': prima_donna_method,
            'RepeatedConditional': repeated_conditional,
            'TooManyInstanceVariables': too_many_instance_variables,
            'TooManyMethods': too_many_methods,
            'TooManyStatements': too_long_method,
            'UncommunicativeMethodName': bad_method_name,
            'UncommunicativeModuleName': bad_module_name,
            'UncommunicativeParameterName': bad_param_name,
            'UncommunicativeVariableName': bad_var_name,
            'UnusedParameters': not allow_unused_variables,
            'UnusedPrivateMethod': not allow_unused_private_methods,
            'UtilityFunction': utility_function
        }

        return ('---\n' +
                '\n'.join('{}:\n  enabled: {}'.format(key,
                                                      str(value).lower())
                          for key, value in config.items()))
Esempio n. 12
0
class HAMLLintBear:
    """
    Uses ``haml-lint`` to perform HAML-specific style and lint checks to ensure
    clean and readable HAML code.
    """
    LANGUAGES = {'Haml'}
    REQUIREMENTS = {GemRequirement('haml_lint', '0.27.0')}
    AUTHORS = {'The coala developers'}
    AUTHORS_EMAILS = {'*****@*****.**'}
    LICENSE = 'AGPL-3.0'
    CAN_DETECT = {'Formatting', 'Syntax'}
    SEE_MORE = 'https://github.com/brigade/haml-lint'

    DEFAULT_IGNORED_COPS = (
        'Lint/BlockAlignment',
        'Lint/EndAlignment',
        'Lint/Void',
        'Layout/AlignParameters',
        'Layout/ElseAlignment',
        'Layout/EndOfLine',
        'Layout/IndentationWidth',
        'Layout/TrailingBlankLines',
        'Layout/TrailingWhitespace',
        'Metrics/BlockLength',
        'Metrics/BlockNesting',
        'Metrics/LineLength',
        'Naming/FileName',
        'Style/FrozenStringLiteralComment',
        'Style/IfUnlessModifier',
        'Style/Next',
        'Style/WhileUntilModifier',
    )

    @staticmethod
    def generate_config(
        filename,
        file,
        alignment_tabs: bool = True,
        alt_text: bool = True,
        class_attribute_with_static_value: bool = True,
        classes_before_ids: bool = True,
        consecutive_comments: bool = True,
        max_consecutive_comments: int = 1,
        consecutive_silent_scripts: bool = True,
        max_consecutive_silent_scripts: int = 2,
        empty_object_reference: bool = True,
        empty_script: bool = True,
        final_newline: bool = True,
        final_newline_present: bool = True,
        html_attributes: bool = True,
        id_names: bool = True,
        id_names_style: str = 'lisp_case',
        implicit_div: bool = True,
        indentation: bool = True,
        indentation_character: str = 'space',
        indentation_width: int = 2,
        inline_styles: bool = True,
        instance_variables: bool = True,
        instance_variables_file_types: str = 'partials',
        instance_variables_matchers_all: str = r'.*',
        instance_variables_matchers_partials: str = r'\A_.*\.haml\z',
        leading_comment_space: bool = True,
        line_length: bool = True,
        max_line_length: int = 80,
        multiline_pipe: bool = True,
        multiline_script: bool = True,
        object_reference_attributes: bool = True,
        repeat_id: bool = True,
        repeat_id_severity: str = 'error',
        rubo_cop: bool = True,
        rubo_cop_ignored_cops: typed_list(str) = DEFAULT_IGNORED_COPS,
        ruby_comments: bool = True,
        space_before_script: bool = True,
        space_inside_hash_attributes: bool = True,
        space_inside_hash_attributes_style: str = 'space',
        tag_name: bool = True,
        trailing_whitespace: bool = True,
        unnecessary_interpolation: bool = True,
        unnecessary_string_output: bool = True,
        view_length: bool = True,
        max_view_length: int = 100,
        hamllint_config: str = '',
    ):
        """
        :param alignment_tabs:
            Check if tabs are used within a tag for alignment or not.
        :param alt_text:
            Check if alternate text is specified within img tags or not. Using
            alt attributes is important to make the site more accessible.
        :param class_attribute_with_static_value:
            Check if static class attributes are preferred over hash
            attributes with static values or not. Unless a dynamic value is
            being assigned to the class attribute, it is terser to use the
            inline tag to specify the class or classes to which an element
            should be assigned.
        :param classes_before_ids:
            Check whether classes or ID attributes should be listed first in
            the tags. Attributes should be listed in the order of specificity.
            Thus, the order should be classes followed by IDs.
        :param consecutive_comments:
            Check if consective comments are allowed or not. Consecutive
            comments should be condensed into a single multiline comment.
        :param max_consecutive_comments:
            Set the maximum number of consecutive comments allowed before
            warning.
        :param consecutive_silent_scripts:
            Check if there are multiple lines of Ruby using silent script
            markers (-). Large blocks of Ruby code in HAML templates are
            generally a smell and this rule can be used to warn against that.
        :param max_consecutive_silent_scripts:
            Set the maximum number of consective scripts before yielding a
            warning.
        :param empty_object_reference:
            Check if empty object references should be removed or not. These
            are no-ops and are usually left behind by mistake and can be
            removed safely.
        :param empty_script:
            Check if empty scripts should be removed or not. Empty scripts
            serve no purpose and are usually left behind by mistake.
        :param final_newline:
            Check if the file should have a final newline or not. Files should
            always have a final newline to ensure better diffs when adding
            lines to it.
        :param final_newline_present:
            Customize whether or not a final newline exists, with this
            parameter. Final newline should be present by default.
        :param html_attributes:
            Check if HTML-style attributes syntax is being used to define the
            attributes for an element or not. HTML-style attributes syntax can
            be terser, but it also introduces additional complexity to the
            templates, since there are now two different ways to define
            attributes. Using one style makes it easier to add greater
            cognitive load to writing templates. By default, HTML-style
            attributes syntax is not used.
        :param id_names:
            Check if the naming convention of the id attributes are conforming
            to one of the possible preferred styles.
        :param id_names_style:
            Specify the style with which the id attributes must conform.
            The preferred styles are:
            lisp-case,
            camelCase,
            PascalCase,
            snake_case.
            The default style is lisp-case.
        :param implicit_div:
            Check if %div can be converted into an implicit div. Implicit divs
            make HAML templates more concise.
        :param indentation:
            Check if spaces are used for indentation instead of hard tabs.
        :param indentation_character:
            Set the character used for indentation, spaces or tabs.
        :param indentation_width:
            Set the number of spaces for space indentation. This is ignored
            when indentation_character is set to tab.
        :param inline_styles:
            Check if the tags contain inline styles or not. In general, tags
            should not contain inline styles. Dynamic content and email
            templates are possible exceptions.
        :param instance_variables:
            Check if instance variables are not used in the specified type of
            files.
        :param instance_variables_file_types:
            Specify the class of files to lint. By default, this linter only
            runs on Rails-style partial views.
        :param instance_variables_matchers_all:
            Check all file names against.
        :param instance_variables_matchers_partials:
            Specify the regular expression to check file names against.
        :param leading_comment_space:
            Check if comments are separated from the leading # by a space or
            not. The comments should be space separated for more readability.
        :param line_length:
            Check whether maximum line length linter is enabled or not.
        :param max_line_length:
            Specify the maximum number of characters for a line, the newline
            character being excluded.
        :param multiline_pipe:
            Check if multiple lines are spanned using multiline pipe (|)
            syntax or not.
        :param multiline_script:
            Check if Ruby scripts are spanned over multiple lines using
            operators or not.
        :param object_reference_attributes:
            Check if object reference syntax is used to set the class/id of an
            element or not. This syntax should not be used since it makes it
            difficult to find where a particular class attribute is defined in
            the code. It also creates an unnecessary coupling by directly
            associating class names to the objects passed to it, making
            refactoring models affect the views.
        :param repeat_id:
            Check whether IDs are unique or not. Repeating an ID is an error
            in the HTML specification.
        :param repeat_id_severity:
            Set the severity level of the linter in checking whether the IDs
            are unique or not.
        :param rubo_cop:
            Use this rule to enable the linter to run RuboCop over the Ruby
            code in the templates.
        :param rubo_cop_ignored_cops:
            Specify cops which are to be ignored while running RuboCop over
            the Ruby code in the templates.
        :param ruby_comments:
            Check if HAML's built-in comments are preferred over ad hoc Ruby
            comments.
        :param space_before_script:
            Check if Ruby script indicators are separated from code with a
            single space or not.
        :param space_inside_hash_attributes:
            Check if the style of hash attributes is one of the two possible
            preferred styles or not.
        :param space_inside_hash_attributes_style:
            Set the preferred style of hash attributes.
        :param tag_name:
            Check if the tag names contain uppercase letters or not. Tag names
            should not contain uppercase letters.
        :param trailing_whitespace:
            Check whether trailing whitespace linter is enabled or not.
        :param unnecessary_interpolation:
            Check if there is unnecessary interpolation for inline tag content
            or not. Unnecessary interpolation must be avoided.
        :param unnecessary_string_output:
            Check if string expressions are being outputted in Ruby, when
            static text will suffice. HAML gracefully handles string
            interpolation in static text, so Ruby strings are not required in
            order to use interpolation.
        :param view_length:
            Check if large views are split into separate partials.
        :param max_view_length:
            Set maximum length of template views.
        """
        if hamllint_config:
            return None
        else:
            hamllint_config = {
                'linters': {
                    'AlignmentTabs': {
                        'enabled': alignment_tabs,
                    },
                    'AltText': {
                        'enabled': alt_text,
                    },
                    'ClassAttributeWithStaticValue': {
                        'enabled': class_attribute_with_static_value,
                    },
                    'ClassesBeforeIds': {
                        'enabled': classes_before_ids,
                    },
                    'ConsecutiveComments': {
                        'enabled': consecutive_comments,
                        'max_consecutive': max_consecutive_comments,
                    },
                    'ConsecutiveSilentScripts': {
                        'enabled': consecutive_silent_scripts,
                        'max_consecutive': max_consecutive_silent_scripts,
                    },
                    'EmptyObjectReference': {
                        'enabled': empty_object_reference,
                    },
                    'EmptyScript': {
                        'enabled': empty_script,
                    },
                    'FinalNewline': {
                        'enabled': final_newline,
                        'present': final_newline_present,
                    },
                    'HtmlAttributes': {
                        'enabled': html_attributes,
                    },
                    'IdNames': {
                        'enabled': id_names,
                        'style': id_names_style,
                    },
                    'ImplicitDiv': {
                        'enabled': implicit_div,
                    },
                    'Indentation': {
                        'enabled': indentation,
                        'character': indentation_character,
                        'width': indentation_width,
                    },
                    'InlineStyles': {
                        'enabled': inline_styles,
                    },
                    'InstanceVariables': {
                        'enabled': instance_variables,
                        'file_types': instance_variables_file_types,
                        'matchers': {
                            'all': instance_variables_matchers_all,
                            'partials': instance_variables_matchers_partials,
                        },
                    },
                    'LeadingCommentSpace': {
                        'enabled': leading_comment_space,
                    },
                    'LineLength': {
                        'enabled': line_length,
                        'max': max_line_length,
                    },
                    'MultilinePipe': {
                        'enabled': multiline_pipe,
                    },
                    'MultilineScript': {
                        'enabled': multiline_script,
                    },
                    'ObjectReferenceAttributes': {
                        'enabled': object_reference_attributes,
                    },
                    'RepeatedId': {
                        'enabled': repeat_id,
                        'severity': repeat_id_severity,
                    },
                    'RuboCop': {
                        'enabled': rubo_cop,
                        'ignored_cops': rubo_cop_ignored_cops,
                    },
                    'RubyComments': {
                        'enabled': ruby_comments,
                    },
                    'SpaceBeforeScript': {
                        'enabled': space_before_script,
                    },
                    'SpaceInsideHashAttributes': {
                        'enabled': space_inside_hash_attributes,
                        'style': space_inside_hash_attributes_style,
                    },
                    'TagName': {
                        'enabled': tag_name,
                    },
                    'TrailingWhitespace': {
                        'enabled': trailing_whitespace,
                    },
                    'UnnecessaryInterpolation': {
                        'enabled': unnecessary_interpolation,
                    },
                    'UnnecessaryStringOutput': {
                        'enabled': unnecessary_string_output,
                    },
                    'ViewLength': {
                        'enabled': view_length,
                        'max': max_view_length,
                    },
                },
            }

            return yaml.dump(hamllint_config, default_flow_style=False)

    @staticmethod
    def create_arguments(
        filename,
        file,
        config_file,
        hamllint_config: str = '',
    ):
        """
        :param hamllint_config:
            Path to a custom configuration file.
        """
        return ('--no-summary', filename, '--config',
                hamllint_config if hamllint_config else config_file)