-
Notifications
You must be signed in to change notification settings - Fork 508
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Clarify how to implement an API Consumer #1881
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
# Custom integration | ||
|
||
!!! warning | ||
This page is based on Ktlint `0.49.x` which has to be released. Most concepts are also applicable for `0.48.x`. | ||
|
||
## Ktlint Rule Engine | ||
|
||
The `Ktlint Rule Engine` is the central entry point for custom integrations with the `Ktlint API`. See [basic API Consumer](https://github.com/pinterest/ktlint/blob/master/ktlint-api-consumer/src/main/kotlin/com/example/ktlint/api/consumer/KtlintApiConsumer.kt) for a basic example on how to invoke the `Ktlint Rule Engine`. This example also explains how the logging of the `Ktlint Rule Engine` can be configured to your needs. | ||
|
||
The `KtLintRuleEngine` instance only needs to be created once for the entire lifetime of your application. Reusing the same instance results in better performance due to caching. | ||
|
||
```kotlin title="Creating the KtLintRuleEngine" | ||
val ktLintRuleEngine = | ||
KtLintRuleEngine( | ||
ruleProviders = KTLINT_API_CONSUMER_RULE_PROVIDERS, | ||
) | ||
``` | ||
|
||
### Rule provider | ||
|
||
The `KtLintRuleEngine` must be configured with at least one `RuleProvider`. A `RuleProvider` is a lambda which upon request of the `KtLintRuleEngine` provides a new instance of a specific rule. You can either provide any of the standard rules provided by KtLint or with your own custom rules, or with a combination of both. | ||
```kotlin title="Creating a set of RuleProviders" | ||
val KTLINT_API_CONSUMER_RULE_PROVIDERS = | ||
setOf( | ||
// Can provide custom rules | ||
RuleProvider { NoVarRule() }, | ||
// but also reuse rules from KtLint rulesets | ||
RuleProvider { IndentationRule() }, | ||
) | ||
``` | ||
|
||
### Editor config: defaults & overrides | ||
|
||
When linting and formatting files, the `KtlintRuleEngine` takes the `.editorconfig` file(s) into account which are found on the path to the file. A property which is specified in the `editorConfigOverride` property of the `KtLintRuleEngine` takes precedence above the value of that same property in the `.editorconfig` file. The `editorConfigDefaults` property of the `KtLintRuleEngine` can be used to specify the fallback values for properties in case that property is not defined in the `.editorconfig` file (or in the `editorConfigOverride` property). | ||
|
||
```kotlin title="Specifying the editorConfigOverride" | ||
val ktLintRuleEngine = | ||
KtLintRuleEngine( | ||
ruleProviders = KTLINT_API_CONSUMER_RULE_PROVIDERS, | ||
editorConfigOverride = EditorConfigOverride.from( | ||
INDENT_STYLE_PROPERTY to IndentConfig.IndentStyle.SPACE, | ||
INDENT_SIZE_PROPERTY to 4 | ||
) | ||
) | ||
``` | ||
|
||
The `editorConfigOverride` property takes an `EditorConfigProperty` as key. KtLint defines several such properties, but they can also be defined as part of a custom rule. | ||
|
||
The `editorConfigDefaults` property is more cumbersome to define as it is based directly on the data format of the `ec4j` library which is used for parsing the `.editorconfig` file. | ||
|
||
The defaults can be loaded from a path or a directory. If a path to a file is specified, the name of the file does not necessarily have to end with `.editorconfig`. If a path to a directory is specified, the directory should contain a file with name `.editorconfig`. Note that the `propertyTypes` have to be derived from the same collection of rule providers that are specified in the `ruleProviders` property of the `KtLintRuleEngine`. | ||
|
||
```kotlin title="Specifying the editorConfigDefaults using an '.editorconfig' file" | ||
val ktLintRuleEngine = | ||
KtLintRuleEngine( | ||
ruleProviders = KTLINT_API_CONSUMER_RULE_PROVIDERS, | ||
editorConfigDefaults = EditorConfigDefaults.load( | ||
path = Paths.get("/some/path/to/editorconfig/file/or/directory"), | ||
propertyTypes = KTLINT_API_CONSUMER_RULE_PROVIDERS.propertyTypes(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just a confirmation: this is only valid for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That is correct. The function without the |
||
) | ||
) | ||
``` | ||
If you want to include all RuleProviders of the Ktlint project than you can easily retrieve the collection using `StandardRuleSetProvider().getRuleProviders()`. | ||
|
||
The `EditorConfigDefaults` property can also be specified programmatically as is shown below: | ||
|
||
```kotlin title="Specifying the editorConfigDefaults programmatically" | ||
val ktLintRuleEngine = | ||
KtLintRuleEngine( | ||
ruleProviders = KTLINT_API_CONSUMER_RULE_PROVIDERS, | ||
editorConfigDefaults = EditorConfigDefaults( | ||
org.ec4j.core.model.EditorConfig | ||
.builder() | ||
// .. add relevant properties | ||
.build() | ||
) | ||
) | ||
``` | ||
|
||
### Lint & format | ||
|
||
Once the `KtLintRuleEngine` has been defined, it is ready to be invoked for each file or code snippet that has to be linted or formatted. The the `lint` and `format` functions take a `Code` instance as parameter. Such an instance can either be created from a file | ||
```kotlin title="Code from file" | ||
val code = Code.fromFile( | ||
File("/some/path/to/file") | ||
) | ||
``` | ||
or a code snippet (set `script` to `true` to handle the snippet as Kotlin script): | ||
```kotlin title="Code from snippet" | ||
val code = Code.fromSnippet( | ||
""" | ||
val code = "some-code" | ||
""".trimIndent() | ||
) | ||
``` | ||
|
||
The `lint` function is invoked with a lambda which is called each time a `LintError` is found and does not return a result. | ||
```kotlin title="Specifying the editorConfigDefaults programmatically" | ||
ktLintRuleEngine | ||
.lint(codeFile) { lintError -> | ||
// handle | ||
} | ||
``` | ||
|
||
The `format` function is invoked with a lambda which is called each time a `LintError` is found and returns the formatted code as result. Note that the `LintError` should be inspected for errors that could not be autocorrected. | ||
```kotlin title="Specifying the editorConfigDefaults programmatically" | ||
val formattedCode = | ||
ktLintRuleEngine | ||
.format(codeFile) { lintError -> | ||
// handle | ||
} | ||
``` | ||
|
||
## Logging | ||
|
||
Ktlint uses the `io.github.microutils:kotlin-logging` which is a `slf4j` wrapper. As API consumer you can choose which logging framework you want to use and configure that framework to your exact needs. The [basic API Consumer](https://github.com/pinterest/ktlint/blob/master/ktlint-api-consumer/src/main/kotlin/com/example/ktlint/api/consumer/KtlintApiConsumer.kt) contains an example with `org.slf4j:slf4j-simple` as logging provider and a customized configuration which shows logging at `DEBUG` level for all classes except one specific class which only displays logging at `WARN` level. | ||
paul-dingemans marked this conversation as resolved.
Show resolved
Hide resolved
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Ktlint API Consumer | ||
|
||
This module contains a very basic example of how to implement an API Consumer on top of the Ktlint API. If you want to implement your own custom API Consumer than you can copy this module into a stand-alone project or as submodule into another project. |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# SLF4J's SimpleLogger configuration file | ||
|
||
# This file contains the configuration for the logging framework which is added as dependency of the module (see build.gradle.kts). When you | ||
# use another framework than "slf4j-simple", the configuration below will not work. Check out the documentation of the chosen framework how | ||
# it should be configured. Most likely, it has comparable capabilities. | ||
|
||
# Default logging detail level for all instances of SimpleLogger. | ||
# Must be one of ("trace", "debug", "info", "warn", or "error"). | ||
# If not specified, defaults to "info". | ||
#org.slf4j.simpleLogger.defaultLogLevel=warn | ||
|
||
# Logging detail level which can either be set for a specific class or all classes in a specific package. If your project already contains | ||
# a logger, you might want to set the logging for ktlint classes only. | ||
# | ||
# Must be one of ("trace", "debug", "info", "warn", or "error"). | ||
# If not specified, the default logging detail level is used. Specifying another loglevel (for example the value "off") results in | ||
# suppressing all logging for the class or package. Although this can be abused to suppress all logging from KtLint, you are advised no to | ||
# do this. It is better to set the loglevel to "debug" to reduce all logging except the error messages that you don't want to miss. | ||
org.slf4j.simpleLogger.log.com.pinterest.ktlint=debug | ||
# Additional logging detail levels can be set. Although rule above suppresses all log messages at levels warn, info, debug and trace, the | ||
# line below adds an exception for a specific class which might be relevant for you. | ||
org.slf4j.simpleLogger.log.com.pinterest.ktlint.rule.engine.internal.EditorConfigDefaultsLoader=warn | ||
|
||
# Set to true if you want the current date and time to be included in output messages. | ||
# Default is false, and will output the number of milliseconds elapsed since startup. | ||
#org.slf4j.simpleLogger.showDateTime=false | ||
|
||
# The date and time format to be used in the output messages. | ||
# The pattern describing the date and time format is the same that is used in java.text.SimpleDateFormat. | ||
# If the format is not specified or is invalid, the default format is used. | ||
# The default format is yyyy-MM-dd HH:mm:ss:SSS Z. | ||
#org.slf4j.simpleLogger.dateTimeFormat=yyyy-MM-dd HH:mm:ss:SSS Z | ||
|
||
# Set to true if you want to output the current thread name. | ||
# Defaults to true. | ||
#org.slf4j.simpleLogger.showThreadName=true | ||
|
||
# Set to true if you want the Logger instance name to be included in output messages. | ||
# Defaults to true. | ||
#org.slf4j.simpleLogger.showLogName=true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I get this right, this example shows how to define a set of rules that can have custom rules or rules from KtLint rulesets. But to me it is not clear how can I just use the use all the standard rules from KtLint rulesets.
In Slack I was recommended to do the following:
But I'm not sure what this is providing. Is this providing all the standard rules from KtLint rulesets?
What about the experimental rulesets? How can I be able to add those as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To get just the RuleProviders from Ktlint, it is more readable to use
StandardRuleSetProvider().getRuleProviders()
(see https://github.com/pinterest/ktlint/blob/0.48.2/ktlint-ruleset-standard/src/main/kotlin/com/pinterest/ktlint/ruleset/standard/StandardRuleSetProvider.kt).The code block above retrieves all rules which are defined in the project or in any of the dependencies that are included in the project. Standard rules will then only be retrieved in case the Ktlint dependency is included in which the Standard rules are defined.
In '0.48.x', experimental rules can be retrieved in a similar way as the standard rules. Note that in
0.49.x
the experimental rules will be included in the standard rules. See changelog for more information.