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
BaseInspectorclass. - Define the
inspector_typeproperty. To do this, you need to update theInspectorTypeclass by adding there a name of the inspector. - Implement the
inspectfunction, 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_TYPEdictionary, stored next to the inspector, to select the issue type. Also theORIGIN_CLASS_PREFIX_TO_ISSUE_TYPEdictionary 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
BaseInspectorclass. - I've implemented the
inspectfunction and if needed I've added a check for the existence of third-party linter environment variables using thecheck_set_up_env_variablefunction. - I've added a new inspector type to the
InspectorTypeclass, updated theavailable_valuesfunction 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_commandfunction. - if needed. I've implemented the
parsefunction and defined theISSUES_CONFIGSlist in a separate file. - If needed. I've implemented the
choose_issue_typefunction and defined theORIGIN_CLASS_TO_ISSUE_TYPEdictionary in a separate file. - I've added an instance of the new inspector to the
LANGUAGE_TO_INSPECTORSdictionary. - I've updated the main README file:
- I've added an information about the new inspector.
- I've updated a description of the
--disableflag. - 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
Languageclass. - Add a version of the new language in the
LanguageVersionclass. - Add file extensions of the new language in the
Extensionclass. - Define configurations for the new language in the
rulesmodule. - Add an entry for the new language in the
language_to_reviewerdictionary. - 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
Languageclass, updated thefrom_language_versionfunction and theEXTENSION_TO_LANGUAGEdictionary. - I've added a version of the new language to
LanguageVersion. - I've added new language file extensions to the
Extensionsclass and updated thelanguage_to_extension_dictdictionary. - 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.