In this document you will find a detailed description of how to add new functionality to Hyperstyle.
If you want to add a new inspector for an existing language, you need to:
- Inherit from the
BaseInspector
class. - Define the
inspector_type
property. To do this, you need to update theInspectorType
class by adding there a name of the inspector. - Implement the
inspect
function, which should run an analysis of the language and return a list of found issues;
Usually the inspector runs a third-party linter through a command line and parses its result. In this case it will be useful to implement several auxiliary functions:
create_command
– creates a command to run the linter via subprocess.parse
– parses the linter's result and returns the list of found issues. For more details about the implementation of this function, see this section.choose_issue_type
– selects an issue type by its origin class. This function usually uses theORIGIN_CLASS_TO_ISSUE_TYPE
dictionary, stored next to the inspector, to select the issue type. Also theORIGIN_CLASS_PREFIX_TO_ISSUE_TYPE
dictionary can sometimes be useful to determine the type of groups of issues.
Usually the third-party linter needs a configuration file to run. This file should be stored next to the inspector.
An example of inspectors that are implemented in such a way: PMDInpsector
, GolangLintInspector
, Flake8Inspector
.
If the inspector does not need the third-party linter (for example, if the inspector works with a code directly), then the above functions are not necessary. In this case, each such inspector is implemented uniquely. Currently, only one inspector of this kind is implemented in Hyperstyle: PythonAstInspector
.
After implementing all the necessary functions, you need to add the inspector instance to the LANGUAGE_TO_INSPECTORS
dictionary, and update the main README file with a mention of the new inspector there.
If you are implementing the inspector that uses the third-party linter, you must also update the Dockerfile with necessary environment variables and commands to install the linter, and update the README file and the setup_environment.sh
script in the same way.
Usually, the parse
function parses the result of the third-party linter line-by-line, then creates a base issue using the BaseIssue
dataclass, which is later converted to either CodeIssue
or one of the measurable issues using the convert_base_issue
function and an instance of the IssueConigsHandler
class. The resulting issue is added to the general list of found issues and this list is returned from the function after the parsing is finished.
The IssueConfigHandler
class handles custom issue descriptions and also parses metrics from their descriptions (examples of metrics are: line or function length, cyclomatic complexity, maintainability index). It receives instances of IssueConfig
or MeasurableIssueConfig
classes as input, which should be stored in the ISSUE_CONFIGS
list next to the inspector.
Also, if the third-party linter supports output in "Checkstyle" format, you can use the parse_xml_file_result
function to parse the output file.
A sample checklist for adding a new inspector looks like this:
- I've inherited from the
BaseInspector
class. - I've implemented the
inspect
function and if needed I've added a check for the existence of third-party linter environment variables using thecheck_set_up_env_variable
function. - I've added a new inspector type to the
InspectorType
class, updated theavailable_values
function and defined the inspector type. - If needed. I've added a config to run the third-party linter.
- If needed. I've implemented the
create_command
function. - if needed. I've implemented the
parse
function and defined theISSUES_CONFIGS
list in a separate file. - If needed. I've implemented the
choose_issue_type
function and defined theORIGIN_CLASS_TO_ISSUE_TYPE
dictionary in a separate file. - I've added an instance of the new inspector to the
LANGUAGE_TO_INSPECTORS
dictionary. - I've updated the main README file:
- I've added an information about the new inspector.
- I've updated a description of the
--disable
flag. - If needed. I've added an information about the new linter environment variables.
- If needed. I've added a command to manually install the third-party linter.
- If needed. I've updated the Dockerfile with the new linter environment variables and commands to install the third-party linter.
- I've added tests to check the inspector:
- If needed. The linter's output parsing is working correctly.
- If needed. The issue categorization is working correctly.
- The total number of issues from a source code is collected correctly.
- The number of issues of each type from a source code is collected correctly.
- If needed. Metric issues are parsed correctly.
- If needed. Custom issues descriptions are added correctly.
Before you can add a new inspector, you must add support for a new language to Hyperstyle. To do this, you must do the following:
- Add a new language in the
Language
class. - Add a version of the new language in the
LanguageVersion
class. - Add file extensions of the new language in the
Extension
class. - Define configurations for the new language in the
rules
module. - Add an entry for the new language in the
language_to_reviewer
dictionary. - Install all necessary files for the new language in the base.Dockerfile.
Next, use the "Adding a new inspector for an existing language" guideline.
A sample checklist for adding a new linter looks like this:
- I've added a new language to the
Language
class, updated thefrom_language_version
function and theEXTENSION_TO_LANGUAGE
dictionary. - I've added a version of the new language to
LanguageVersion
. - I've added new language file extensions to the
Extensions
class and updated thelanguage_to_extension_dict
dictionary. - I've defined rule configs for the new language.
- I've added functional tests for the new language.
- I've installed all necessary files for the new language in the base.Dockerfile.
And all the items from the "Adding a new inspector for an existing language" checklist.