Linter.java
package org.thewonderlemming.c4plantuml.linter;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.thewonderlemming.c4plantuml.commons.Reporter;
import org.thewonderlemming.c4plantuml.grammars.SourceType;
import org.thewonderlemming.c4plantuml.linter.rules.AbstractLintingRule;
/**
* A linting engine that parses C4 files and passes the result {@link ParseTree} to a set of
* {@link AbstractLintingRule}.
*
* @author thewonderlemming
*
*/
public class Linter {
private final Set<AbstractLintingRule> activeRules = new HashSet<>();
private final Reporter reporter;
/**
* returns a new instance of {@link LinterBuilder} since the default constructor is protected.
*
* @return a new builder instance.
*/
public static LinterBuilder builder() {
return new LinterBuilder();
}
/**
* Default constructor.
*
* @param reporter the reporter to report linting errors to.
* @param activeRules the set of {@link AbstractLintingRule} to use.
*/
protected Linter(final Reporter reporter, final Set<AbstractLintingRule> activeRules) {
this.reporter = reporter;
this.activeRules.addAll(activeRules);
}
/**
* Returns the set of active {@link AbstractLintingRule} to be used on parsed files.
*
* @return the set of active {@link AbstractLintingRule} to use.
*/
public Set<AbstractLintingRule> getActiveRules() {
return Collections.unmodifiableSet(this.activeRules);
}
/**
* Same as {@link Linter#lint(Path, Charset)} but with UTF-8 as default {@link Charset}.
*
* @see Linter#lint(Path, Charset)
*
* @param c4SourceFile the C4 file to process.
*/
public void lint(final Path c4SourceFile) {
lint(c4SourceFile, StandardCharsets.UTF_8);
}
/**
* Parses a C4 file and if no error occurs, passes the resulting {@link ParseTree} through every active
* {@link AbstractLintingRule}.
* <p>
* Any syntax error in the file will be reported to a {@link LinterSyntaxErrorListener}.
* <p>
* Linting errors will be reported to the instance {@link Reporter}.
*
* @param c4SourceFile the C4 source file to process.
* @param charset the {@link Charset} of the file.
*/
public void lint(final Path c4SourceFile, final Charset charset) {
SourceType
.getSourceTypeFromFilename(c4SourceFile)
.ifPresent(sourceType -> {
final LinterSyntaxErrorListener errorListener = new LinterSyntaxErrorListener();
sourceType
.createParser(c4SourceFile, charset, errorListener)
.ifPresent(parser -> this.activeRules
.stream()
.filter(rule -> rule.acceptableParsersTypes().contains(parser.getClass()))
.forEach(rule -> {
errorListener.registerRule(rule);
rule
.selectParseTree(parser)
.ifPresent(tree -> {
rule
.createParseTreeListener(this.reporter, parser.getClass())
.ifPresent(
listener -> new ParseTreeWalker().walk(listener, tree));
rule.wrapUp();
});
errorListener.unregisterRule(rule);
}));
});
}
}