Moose-Rule-Engine is a multi-language, rule-based engine designed for code analysis, automated remediation, and large-scale refactoring.
- Multi-language support: Analyze and refactor code across multiple programming languages.
- Rule-based engine: Define custom rules for code analysis and remediation.
- Reusable presets: Group rule classes into composable presets.
- Automated fixes: Automatically apply fixes to detected violations.
- Extensible helpers: Integrate with external systems like SonarQube or LLMs.
To load Moose-Rule-Engine runtime from a Playground:
Metacello new
githubUser: 'Evref-BL' project: 'Moose-Rule-Engine' commitish: 'main' path: 'src';
baseline: 'MooseRuleEngine';
loads: #( 'default' );
onConflict: [ :ex | ex useIncoming ];
load.To load everything for development, including tests:
Metacello new
githubUser: 'Evref-BL' project: 'Moose-Rule-Engine' commitish: 'main' path: 'src';
baseline: 'MooseRuleEngine';
loads: #( 'dev' );
onConflict: [ :ex | ex useIncoming ];
load.To use Moose-Rule-Engine as a dependency:
spec baseline: 'MooseRuleEngine' with: [
spec repository: 'github://Evref-BL/Moose-Rule-Engine:main'.
].By default this loads only the runtime package. Tests and dev dependencies are opt-in through the tests or dev groups.
MooseRuleEngine takes files and rule classes and returns a collection of fixes. Here is a step-by-step guide to using it.
Start by creating an instance of the MooseRuleEngine:
ruleEngine := MooseRuleEngine new.You need to provide the files you want to analyze. Create a file object and add it to the engine:
file := File new path: '<path/to/your/file>'; content: '<file content>'; model: '<model moose of your file>'.
ruleEngine setFiles: { file }.You can optionally define a model that represents your project, such as a Famix model. This model will be injected into all your rules, providing additional context for analysis and fixes:
ruleEngine setModel: model.Define the rules you want to apply. Rules are objects that analyze files and suggest fixes. Add your rules to the engine:
ruleEngine setRules: { MyCustomRule }.Presets are reusable groups of rule classes. Pass preset classes to the engine:
ruleEngine setPresets: { MyProjectPreset }.You can also add presets individually and combine them with explicitly selected rule classes:
ruleEngine
addPreset: MyProjectPreset;
setRules: { MyAdditionalRule }.Helpers can be used to enhance the functionality of your rules. For example, you can add a SonarQube helper:
sonarqubeApi := SonarQubeApi new host: '<your_sonarqube_host>'; privateToken: '<your_private_token>'.
sonarHelper := MRESonarqubeHelper new
sonarqubeApi: sonarqubeApi;
projectKey: 'your_project_key';
type: 'all'.
ruleEngine addHelper: sonarHelper.Run the engine to detect and fix issues in the provided files:
fixes := ruleEngine detectAndFix.The engine returns a collection of fixes. Each fix contains the following attributes:
- startPos: Start position of the fix.
- endPos: End position of the fix.
- content: New content between start and end position
- file: File where the fix is applied.
Rules are the core of the Moose-Rule-Engine. A rule has:
- Name: A unique identifier.
- Description: A brief explanation of the rule.
initialize
super initialize.
name := 'name'.
description := 'description'.analyse: Takes anMREFileand returns a collection ofMREViolation.fix: Takes anMREViolationand returns a collection ofMREFix.
A rule must also specify the file extensions it supports. To help with common languages, MooseRuleEngine provides traits such as TJavaRule for Java files and TTypescriptRule for TypeScript files.
A preset is an MRERulePreset subclass that defines a named, reusable group of rule classes. A preset may inherit rules from other presets through parentPresets.
Class {
#name : 'MyProjectPreset',
#superclass : 'MRERulePreset',
#category : 'MyProject-Rules',
#package : 'MyProject-Rules'
}
MyProjectPreset class >> presetName
^ 'my-project'
MyProjectPreset class >> parentPresets
^ { MyBasePreset }
MyProjectPreset class >> rules
^ {
MyCustomRule.
MyAdditionalRule }Helpers are classes injected into rules to assist in writing them. They are useful for interacting with external systems like SonarQube or LLMs.
To create a helper, extend MREHelper and define a name.
rule getHelper: 'helperName'.The SonarQube helper allows you to use SonarQube analysis in your rules.
sonarHelper violationsOf: rule inFile: file usingRuleId: sonarRuleId.sonarqubeApi := SonarQubeApi new host: '<your_sonarqube_host>'; privateToken: '<your_private_token>'.
sonarHelper := MRESonarqubeHelper new
sonarqubeApi: sonarqubeApi;
projectKey: 'your_project_key';
type: 'all'.The LLM helper can fix violations using a language model.
llmHelper fix: code withMessage: message.llmApi := LLMAPI chat.
llmApi host: '<llm_host>'.
llmApi apiKey: '<llm_api_key>'.
llmHelper := MRELLMHelper new llmApi: llmApi.