Giter VIP home page Giter VIP logo

mrmans0n / compose-rules Goto Github PK

View Code? Open in Web Editor NEW

This project forked from twitter/compose-rules

549.0 549.0 21.0 3.72 MB

Lint rules for ktlint/detekt aimed to contribute to a healthier usage of Compose. Actively maintained and evolved fork of the Twitter Compose rules.

Home Page: https://mrmans0n.github.io/compose-rules

License: Other

Kotlin 100.00%
detekt-plugin detekt-rules jetpack-compose ktlint-rules

compose-rules's People

Contributors

afigaliyev avatar blundell avatar chrisbanes avatar digitalbuddha avatar goooler avatar hrafnthor avatar jcraane avatar kenyee avatar knanao avatar kychirp avatar manuel-martos avatar mmartosdev avatar mrmans0n avatar nuhkoca avatar paulwoitaschek avatar renovate[bot] avatar stefma avatar t-regbs avatar vincentmasselis avatar zacsweers avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

compose-rules's Issues

Compose rules not working in ktlint-intellij-plugin (follow-up on #176)

As reported in #176 (Originally posted by @chrimaeon in #176 (comment)), the fix for running the compose rules with the ktlint-intellij-plugin only partially works. Given code sample below:

import androidx.compose.material3.Text
import androidx.compose.runtime.Composable

@Composable
fun Post() {
    Text("foo")
}

does not show violation below which is shown by Ktlint CLI"

Post.kt:11:5: This @Composable function emits content but doesn't have a modifier parameter.

See https://mrmans0n.github.io/compose-rules/rules/#when-should-i-expose-modifier-parameters for more information. (compose:modifier-missing-check)

Summary error count (descending) by rule:
  compose:modifier-missing-check: 1

Process finished with exit code 1

with ktlint-compose 0.3.9 and intellij-ktlint-plugin 0.20.0

After investigation in ktlint and ktlint-intellij-plugin, I have found the cause of the problem. Like in #176 the cause is the embedded kotlin compiler which conflicts with packages provided by Intellij IDEA itself. In the ktlint-intellij-plugin those problems are resolved with relocating packages.

I have tried to relocate the packages in ktlint to prevent that third party supplier of rules are not affected by this but it didn't work out as expected. For now, I see no other solution than that each third party supplier of rules applies relocation of packages similar as is done in ktlint-intellij-plugin. For compose rules that would mean that configuration below has to be added to build file of ktlint-rules:

shadowJar {
    // Relocate packages that may conflict with ktlint-intellij-plugin. The rule set won't work when relocations below
    // are not kept in sync with https://github.com/nbadal/ktlint-intellij-plugin/blob/main/lib/build.gradle.kts
    relocate("org.jetbrains.concurrency", "shadow.org.jetbrains.concurrency")
    relocate("org.jetbrains.kotlin.psi.KtPsiFactory", "shadow.org.jetbrains.kotlin.psi.KtPsiFactory")
    relocate("org.jetbrains.kotlin.psi.psiUtil", "shadow.org.jetbrains.kotlin.psi.psiUtil")
    relocate("org.jetbrains.org", "shadow.org.jetbrains.org")
}

On my local machine, I have build the compose rules for ktlint with changes above. Both ktlint CLI and ktlint-intelli-plugin now report the violation as requested by OP.

Screenshot 2024-01-23 at 12 00 32

Screenshot 2024-01-23 at 12 00 47

Failure whith custom detekt task

Hello
Thank you for maintaining this library !

Whenever used with the detekt extension, all works as expected. However, when using integrating detekt as gradle task here this error shows up.

detekt 'compose' property is misspelled or does not exist.

how can this be fixed ?

Screenshot 2023-02-17 at 14 18 26

Add extra checks in ParamOrder rule

Two issues observed in JakeWharton/mosaic#267

  • If a modifier param doesn't have a default, it shouldn't be treated as special in the mandatory/optional order list.
  • The trailing lambda should take into account typealiases to functions / fun interfaces that are defined in the same file (as we can't have type resolution).
  • As a stretch goal, there should be a new config parameter to allowlist specific types so they are treated as lambdas in this case too.

MutableParams rule and MutableState

This rule is reporting a violation for the following Composable's expanded parameter:

@Composable
fun ExpandableText(
    text: String,
    modifier: Modifier = Modifier,
    collapsedMaxLines: Int = 3,
    color: Color = Color.Unspecified,
    expanded: MutableState<Boolean> = rememberSaveable { mutableStateOf(false) },
    fontSize: TextUnit = TextUnit.Unspecified,
    fontStyle: FontStyle? = null,
    fontWeight: FontWeight? = null,
    fontFamily: FontFamily? = null,
    letterSpacing: TextUnit = TextUnit.Unspecified,
    textDecoration: TextDecoration? = null,
    textAlign: TextAlign? = null,
    lineHeight: TextUnit = TextUnit.Unspecified,
    overflow: TextOverflow = TextOverflow.Clip,
    softWrap: Boolean = true,
    minLines: Int = 1,
    style: TextStyle = LocalTextStyle.current,
    placeholder: Boolean = false,
) {
[...]

The parameter expanded: MutableState<Boolean> is using an androidx.compose.runtime.MutableState and I don't think should trigger the error

Using mutable objects as state in Compose will cause your users to see incorrect or stale data in your app.
Mutable objects that are not observable, such as ArrayList<T> or a mutable data class, cannot be observed by Compose to trigger recomposition when they change.

An example of the official Material3 Using MutableState as parameter: https://github.com/androidx/androidx/blob/72d507d1723a212997afe83bd7779f7524ed2bff/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/Menu.kt#L188

I can understand that this doesn't follow the principle of "Hoist all the things", but the error states that MutableState is not observable and "will cause your users to see incorrect or stale data" which, afaik, is not true:

 * A mutable value holder where reads to the [value] property during the execution of a [Composable]
 * function, the current [RecomposeScope] will be subscribed to changes of that value. When the
 * [value] property is written to and changed, a recomposition of any subscribed [RecomposeScope]s
 * will be scheduled. If [value] is written to with the same value, no recompositions will be
 * scheduled.

Can the rule be split between real unobservable objects like ArrayList<T> and ViewModel and the observable one like MutableState or have an optional configuration parameter to ignore observable objects?

Material2 rule / rememberRipple violation

io.nlopez.compose.rules:detekt:0.3.15

Fail if we use Material 3 in the project and try to make custom ripple effect

androidx.compose.material.ripple.rememberRipple

@Composable
fun TestRipple(
    selected: Boolean,
    onClick: () -> Unit,
    enabled: Boolean = true
) {
    Box(
        modifier = Modifier
            .selectable(
                selected = selected,
                onClick = onClick,
                enabled = enabled,
                interactionSource = remember { MutableInteractionSource() },
                indication = rememberRipple(bounded = false),
                role = Role.Tab,
            )
            .fillMaxHeight()
    ) {
        Text(text = "Select")
    }
}

looks like will be change in Compose 1.7.0
https://developer.android.com/develop/ui/compose/touch-input/user-interactions/migrate-indication-ripple

ComposableParamOrder shows error when trailing function is nullable without a default param

I'm seeing an issue where a trailing function that is nullable, without a default param, it does not pass the ComposableParamOrder lint check.

I get this error:

Warning  (detekt) ComposableParamOrder
    Parameters in a composable function should be ordered following this
    pattern: params without defaults, modifiers, params with defaults and
    optionally, a trailing function that might not have a default param.
...

I don't want to post my exact source code, so here's something very similar:

The following composable declaration will show the error.

@Composable
fun SomeView(
    paramWithoutDefault: Boolean,
    modifier: Modifier = Modifier,
    paramWithDefault: Int = 5,
    trailingFunction: (() -> Unit)?,
) {}

What I would expect is this to pass the lint check, since the warning states the allowed order is

  1. params without defaults
  2. modifiers
  3. params with defaults
  4. optionally, a trailing function that might not have a default param.

(4) should allow a trailing function that doesn't have a default param, regardless of its nullability.

ModifierMissing with multi-previews

Describe the bug

Looks like the ModifierMissing rule is not able to detect multipreview usage, so it flags those previews as missing modifiers. If there's a technical issue with detecting it, maybe we can at least have an exclusion by function name. Maybe by regex or even just assume that previews end with "Preview".

Action Required: Fix Renovate Configuration

There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.

Location: renovate.json
Error type: The renovate configuration file contains some invalid settings
Message: Invalid configuration option: includeForks

Ktlint compose rules not working in ktlint-intellij-plugin

In nbadal/ktlint-intellij-plugin#425 it was reported that the compose rules are not working in the new ktlint-intellij-plugin while they do work in Ktlint CLI.

Post.kt:

import androidx.compose.material3.Text
import androidx.compose.runtime.Composable

@Composable
fun Post() {
    Text("foo")
}

.editorconfig:

root = true
[*.{kt,kts}]
ij_kotlin_imports_layout = *,java.**,javax.**,kotlin.**,^
ij_kotlin_allow_trailing_comma = false
ij_kotlin_allow_trailing_comma_on_call_site = false
ktlint_function_naming_ignore_when_annotated_with=Composable

Output with ktlint CLI 1.1.0:

/opt/homebrew/bin/ktlint -F -R <path>/scripts/ktlint-compose-0.3.8-all.jar .../Post.kt
<path>/Post.kt:11:5: This @Composable function emits content but doesn't have a modifier parameter.

See https://mrmans0n.github.io/compose-rules/rules/#when-should-i-expose-modifier-parameters for more information. (compose:modifier-missing-check)

Summary error count (descending) by rule:
  compose:modifier-missing-check: 1

Process finished with exit code 1

The lint violation is however not reported by the ktlint-intellij-plugin.

After investigation, I have found that the usages of KtStubElementTypes in KtlintRule is the most likely cause of the problem.

        when (node.elementType) {
            KtStubElementTypes.FILE -> {
                psi.attach(config)
                visitFile(psi as KtFile, autoCorrect, emit.toEmitter())
            }

            KtStubElementTypes.CLASS -> visitClass(psi as KtClass, autoCorrect, emit.toEmitter())
            KtStubElementTypes.FUNCTION -> {
                val function = psi as KtFunction
                val emitter = emit.toEmitter()
                visitFunction(function, autoCorrect, emitter)
                if (function.isComposable) {
                    visitComposable(function, autoCorrect, emitter)
                }
            }
        }

Here the node.elementType is checked against KtStubElementTypes instead of using ElementType. This might also be used in other classes.

To proof that above assumption is the cause of the problem, I have build a new simple rule in a new custom ruleset in ktlint:

class NoFooFun :
    Rule(
        ruleId = RuleId("$CUSTOM_RULE_SET_ID:no-foo-fun"),
        about =
            About(
                maintainer = "Your name",
                repositoryUrl = "https://github.com/your/project/",
                issueTrackerUrl = "https://github.com/your/project/issues",
            ),
    ) {
    override fun beforeVisitChildNodes(
        node: ASTNode,
        autoCorrect: Boolean,
        emit: (offset: Int, errorMessage: String, canBeAutoCorrected: Boolean) -> Unit,
    ) {
        // Compose ruleset uses KtStubElementTypes in KtlintRule class to match element types. This works fine when rules are used with
        // ktlint CLI as the embeddable kotlin compiler is used.
        if (node.elementType == KtStubElementTypes.FUNCTION) {
            node
                .findChildByType(ElementType.IDENTIFIER)
                ?.takeIf { it.text == "foo" }
                ?.let {
                    emit(node.startOffset, "Unexpected fun foo (via KtStubElementTypes.FUNCTION)", false)
                }
        }

        // However, when the ruleset is used in combination with the ktlint-intelli-plugin, the KtStubElementTypes are no longer recognized.
        // Most likely this is caused by interoperability problems between the embedded kotlin compiler in the KtLintRuleEngine versus the
        // Kotlin compiler in IntelliJ IDEA.
        if (node.elementType == ElementType.FUN) {
            node
                .findChildByType(ElementType.IDENTIFIER)
                ?.takeIf { it.text == "foo" }
                ?.let {
                    emit(node.startOffset, "Unexpected fun foo (via elementType.FUN)", false)
                }
        }
    }
}

Given code sample below:

fun foo() {
    // do something
}

and ktlint CLI 1.1.0 this produces:

$ ktlint-1.1.0 --relative -R ~/Downloads/ktlint-custom-ruleset-example-1.1.0.jar
15:21:12.813 [main] INFO com.pinterest.ktlint.cli.internal.KtlintCommandLine -- Enable default patterns [**/*.kt, **/*.kts]
src/main/kotlin/Foo.kt:1:1: Unexpected fun foo (via KtStubElementTypes.FUNCTION) (custom-rule-set-id:no-foo-fun)
src/main/kotlin/Foo.kt:1:1: Unexpected fun foo (via elementType.FUN) (custom-rule-set-id:no-foo-fun)

Summary error count (descending) by rule:
  custom-rule-set-id:no-foo-fun: 2

The problem is reported twice, as was to be expected. The embeddable kotlin compiler in Ktlint CLI can match the element type of the node both to 'ElementType.FUNandKtStubElementTypes.FUNCTION`.

When using the same ruleset jar in ktlint-intellij-plugin, following problems are reported:
Screenshot 2023-12-29 at 15 25 06
As you can see, the problem is now only reported as it matches with ElementType.FUN. I am not 100% sure about the reason, but I believe that the KtStubElementTypes are not compatible with the IDEA kotlin compiler.

Can you provide a snapshot version of the compose ruleset that uses ElementType instead of KtStubElementTypes so that we can verify whether this resolves the problem?

Bump up spotless ktlint version

Currently ktlint is fixed to 0.50.0 in this project's config. Bumping it to the latest yields a ton of new linting errors, that will need to be fixed.

ModifierMissing's checkModifiersForVisibility does not seem to work

When specified in config.yml it seems to have no effect:

  ModifierMissing:
    active: true
    checkModifiersForVisibility: public_and_internal
@Composable
internal fun GreetingNoModifier(name: String) {
    Text(
        text = "Hello $name!",
    )
}

yields no extra tech debt ๐Ÿ˜ข

I have a working test project if you need it.

compose:vm-injection-check rule work don't properly

Let's say we have the following function:

@Composable
fun ScreenRoute(viewModel: ScreenViewModel)

although there is no default value, it is still correct. Here the rule works fine. Then we use it for example from the navigation declaration like this:

composable(destination = Destination.ScreenRoute) {
  ScreenRoute(
    viewModel = hiltViewModel()
  )
}

Here, too, everything works correctly. But then we decide to use assistedfactory to add parameters to the viewmodel and change the code like this:

composable(destination = Destination.ScreenRoute) {
  val viewModel = hiltViewModel(
       creationCallback = { factory: ScreenViewModel.Factory ->
           factory.create(
               parameter = 5,
               parameter2 = null
           )
       }
   )
   ScreenRoute(
       viewModel = viewModel
   )
}

This is where the rule sounds the alarm, although everything still remains correct. Let's go further and explicitly declare the type of the viewModel variable:

composable(destination = Destination.ScreenRoute) {
  val viewModel: ScreenViewModel = hiltViewModel(
       creationCallback = { factory: ScreenViewModel.Factory ->
           factory.create(
               parameter = 5,
               parameter2 = null
           )
       }
   )
   ScreenRoute(
       viewModel = viewModel
   )
}

Here the rule finally loses its mind and it puts the variable with the viewmodel into the parameter of the function in which all the screens are located:

Navigation(
  ...
  navController: NavHostController = rememberNavController()
  **<here>**
) {
NavHost(
    navController = navController,
    startDestination = startDestination
) {
    composable(destination = Destination.ScreenRoute) {...}
    composable(destination = Destination.Screen1Route) {...}
  }
}

kotlin = "1.9.23"
compose = "1.6.4"
ktlint = "12.1.0"
ktlintComposeRules = "0.3.12"

Using `@Composable` for Custom Modifiers is now the recommended method based on official documents

As you can see in the official document of Custom Modifiers, the lint for not using @Composable for custom modifiers is now removed:

Note: In previous versions of Compose, we recommended against this approach and suggested using composed {} instead via a lint rule. Now that composed {} is not recommended, the lint rule has been removed.

So I think it is better to also remove it from this ruleset.

Reference of the rule in the repository's website

Reference of the rule in the repository

Using compose rules with ktlint-intellij-plugin

I am working on upgrading the ktlint-intelli-plugin to Ktlint 1.x. In this issue it is mentioned that the plugin does not work with the compose ruleset. When I use the ktlint-0.3.2.jar artifact, I get error java.lang.NoClassDefFoundError: io/nlopez/rules/core/ComposeKtVisitor.

According to the documentation I should use ktlint-compose-<VERSION>-all.jar which I can not find on Maven. Is the documentation outdated or is the artifact somehow not published?

False negative for multiple-emiters-check

compose:multiple-emitters-check failed to detekt issues, in following code.

private fun Content(title: String? = null, subtitle: String? = null) {
    title?.let {
        Text(text = it)
    }

    subtitle?.let {
        Text(text = it)
    }
}

I didn't double check this, since I'm short on time. I only noticed, that our CI didn't complain.

Library version: 0.3.3

Not applying rules using IDE

Hello, I am using Detekt plugin on Android Studio. To apply this plugin, I downloaded its .jar file and attached in under Settings -> Tools -> detekt -> Plugin JAR(s), however, after applying all rules to detekt.yaml, the compiler still shows the errors. How to solve this issue? Thanks.

Preview composable naming rule

Even with PreviewPublic rule, in large codebase, it's still easy to import wrong Composable function because of unclear naming. Having such code:

@Preview
@Composable
internal fun MyText() {
    MyText("Sample text")
}

It's not immediately clear that this is just a preview composable. I think it would be good to have a rule which enforces preview composables naming with Preview as suffix, similar to PreviewNaming rule (initially I thought that was the purpose of this rule ๐Ÿ™ˆ). Wdyt? :)

Wrong parameters order

I have this composable:

@Composable
internal fun MyComposable(
    param: Param,
    modifier: Modifier = Modifier,
    onClick1: () -> Unit,
    onClick2: () -> Unit,
) {

but the ktlint rule throws this:

Parameters in a composable function should be ordered following this pattern: params without defaults, modifiers, params with defaults and optionally, a trailing function that might not have a default param.
Current params are: [param: Param, modifier: Modifier = Modifier, onClick1: () -> Unit, onClick2: () -> Unit] but should be [param: Param, onClick1: () -> Unit, modifier: Modifier = Modifier, onClick2: () -> Unit].

Not sure why it is complaining about the modifier position, I think is an error, it also happens with others @composables

Rule for suspicious modifiers order

Few things give Compose away more than this.
Pay attention to the corners when you click on the Share and Copy buttons.

doc_2023-08-27_16-42-57.mp4

In Compose, it's very easy to make clickability that doesn't match the radius of the rounding.
Just mix up the modifiers, it happens every day.

Can you, please, add a rule to prevent such ordering?

lint worker execution error

Trying to apply rule set with kotlinter (latest 3.13.0).

While running check I'm getting following errors:

lint worker execution error
java.lang.NoClassDefFoundError: Could not initialize class org.jmailen.gradle.kotlinter.support.RuleSetsKt
	at org.jmailen.gradle.kotlinter.tasks.lint.LintWorkerAction.execute(LintWorkerAction.kt:43)
...

This does not happen while using non-forked original classpath "com.twitter.compose.rules:ktlint:<version>"

Modifier rule triggers on Compose-based projects which may not have a `Modifier` concept

I added these rules to Mosaic mostly for the function naming rule, but I'm getting errors about missing Modifier parameters. Now, Mosaic does have a Modifier type now, but that wasn't always the case. And it certainly isn't the case that other Compose-based projects will have such a type. In Redwood we are actively planning on eliminating our Modifier type because the semantics are not the same as in Compose UI. Once that happens our node-emitting functions will never be able to comply with this rule.

The presence of a Modifier type is certainly common across multiple node types, but it's not fundamentally intrinsic to Compose. What should the behavior of this rule be in the larger non-Compose UI, Compose-based ecosystem?

Maybe it could hardcode a list of well-known Modifier types (Compose UI + Glance) which are detected on the classpath to enable the rule. And then perhaps a configuration option could be exposed for cases like Mosaic where we can specify the fully-qualified type name of our Modifier. Plus, in the future case of Redwood, this would allow our non-"Modifier"-named Modifier-like type to participate in this rule's validation.

Operator fun lowercase

I have the next code in my project:

fun interface MyInterface { @Composable operator fun invoke(param: MyParam) }

The compose_naming_check rule is complaining :

Composable functions that return Unit should start with an uppercase letter.
They are considered declarative entities that can be either present or absent in a composition and therefore follow the naming rules for classes.

I'm wondering if operator fun should be whitelisted from this specific rule as it doesn't make sense to make them be uppercase

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

This repository currently has no open or pending branches.

Detected dependencies

github-actions
.github/workflows/build.yaml
  • actions/checkout v4
  • actions/setup-java v4
  • gradle/actions v3
  • actions/upload-artifact v4
  • actions/checkout v4
  • actions/setup-java v4
  • gradle/actions v3
.github/workflows/create-release.yaml
  • release-drafter/release-drafter v6
.github/workflows/publish-docs.yaml
  • actions/checkout v4
  • actions/setup-python v5
  • peaceiris/actions-gh-pages v4
.github/workflows/update-release.yaml
  • actions/checkout v4
  • actions/setup-java v4
  • gradle/actions v3
  • svenstaro/upload-release-action v2
  • svenstaro/upload-release-action v2
gradle
gradle.properties
settings.gradle
  • com.gradle.develocity 3.17.2
build.gradle
core-common/gradle.properties
core-common/build.gradle
core-detekt/gradle.properties
core-detekt/build.gradle
core-ktlint/gradle.properties
core-ktlint/build.gradle
gradle/libs.versions.toml
  • com.pinterest.ktlint:ktlint-core 1.2.1
  • com.pinterest.ktlint:ktlint-rule-engine-core 1.2.1
  • com.pinterest.ktlint:ktlint-rule-engine 1.2.1
  • com.pinterest.ktlint:ktlint-cli-ruleset-core 1.2.1
  • com.pinterest.ktlint:ktlint-test 1.2.1
  • io.gitlab.arturbosch.detekt:detekt-core 1.23.6
  • io.gitlab.arturbosch.detekt:detekt-test 1.23.6
  • org.jetbrains.kotlin:kotlin-compiler-embeddable 1.9.23
  • org.junit.jupiter:junit-jupiter 5.10.2
  • org.junit.jupiter:junit-jupiter-params 5.10.2
  • org.assertj:assertj-core 3.25.3
  • org.reflections:reflections 0.10.2
  • org.jetbrains.kotlin.jvm 1.9.23
  • com.vanniktech.maven.publish 0.28.0
  • com.diffplug.spotless 6.25.0
  • com.github.johnrengelman.shadow 8.1.1
rules/common/gradle.properties
rules/common/build.gradle
rules/detekt/gradle.properties
rules/detekt/build.gradle
rules/ktlint/gradle.properties
rules/ktlint/build.gradle
gradle-wrapper
gradle/wrapper/gradle-wrapper.properties
  • gradle 8.7

  • Check this box to trigger a request for Renovate to run again on this repository

Add configurable exceptions for ViewModelForwarding rule

There might be valid patterns where you want to forward a VM-like class. Usually this could be worked around by using an optional param with viewModel() as a default value and not passing the VM from stateful-parent to stateful-child directly. However, this only works if there is a way to acquire the VMs via a factory, which might not be the case (cough cough Compose multiplatform).

We should allow the allowlisting of Composables that match some given regexes.

Typo in release 0.3.0

Morning!

There is a typo in https://github.com/mrmans0n/compose-rules/releases/tag/v0.3.0:

If you are using Detekt, you'll need to change the PreviewAnnotationNaming in your detekt.yml config to be PreviewAnnotationNaming.

Should be:

If you are using Detekt, you'll need to change the PreviewNaming in your detekt.yml config to be PreviewAnnotationNaming.

If someone can edit the release description to avoid confusing the users, that would be awesome! Thanks.

(change on our side: element-hq/element-x-android@fb87c77)

[Idea] add ComposePreviewNaming

The idea is to align naming of preview composable functions in unified format.
we already have PreviewAnnotationNaming and PreviewPublic.

Propose:
name: ComposePreviewNaming
logic: composable preview function should require Preview postfix

Didn't find any official docs, but Google follow this name convention: https://developer.android.com/develop/ui/compose/tooling/previews

valid code

@Preview
@Composable
private fun SectionCounterPreview() {
    // code
}

invalid

@Preview
@Composable
private fun SectionCounter() {
    // code
}
@Preview
@Composable
private fun PreviewSectionCounter() {
    // code
}

Dependency resolving issue with Kotlin 1.9.10 vs 1.9.0?

Execution failed for task ':app:detekt'.
> Could not resolve all files for configuration ':app:detektPlugins'.
   > Could not resolve org.jetbrains.kotlin:kotlin-compiler-embeddable:{strictly 1.9.0}.
     Required by:
         project :app > io.gitlab.arturbosch.detekt:detekt-cli:1.23.1
      > Cannot find a version of 'org.jetbrains.kotlin:kotlin-compiler-embeddable' that satisfies the version constraints:
           Dependency path 'My Application:app:unspecified' --> 'io.gitlab.arturbosch.detekt:detekt-cli:1.23.1' (runtimeElements) --> 'org.jetbrains.kotlin:kotlin-compiler-embeddable:{strictly 1.9.0}'
           Dependency path 'My Application:app:unspecified' --> 'io.gitlab.arturbosch.detekt:detekt-cli:1.23.1' (runtimeElements) --> 'io.gitlab.arturbosch.detekt:detekt-parser:1.23.1' (runtimeElements) --> 'org.jetbrains.kotlin:kotlin-compiler-embeddable:1.9.0'
           Dependency path 'My Application:app:unspecified' --> 'io.nlopez.compose.rules:detekt:0.3.0' (runtimeElements) --> 'io.nlopez.compose.rules:core-common:0.3.0' (runtimeElements) --> 'org.jetbrains.kotlin:kotlin-compiler-embeddable:1.9.10'
           Dependency path 'My Application:app:unspecified' --> 'io.gitlab.arturbosch.detekt:detekt-cli:1.23.1' (runtimeElements) --> 'io.gitlab.arturbosch.detekt:detekt-tooling:1.23.1' (runtimeElements) --> 'io.gitlab.arturbosch.detekt:detekt-api:1.23.1' (runtimeElements) --> 'org.jetbrains.kotlin:kotlin-compiler-embeddable:1.9.0'
           Dependency path 'My Application:app:unspecified' --> 'io.gitlab.arturbosch.detekt:detekt-cli:1.23.1' (runtimeElements) --> 'io.gitlab.arturbosch.detekt:detekt-parser:1.23.1' (runtimeElements) --> 'io.gitlab.arturbosch.detekt:detekt-psi-utils:1.23.1' (runtimeElements) --> 'org.jetbrains.kotlin:kotlin-compiler-embeddable:1.9.0'

   > Could not resolve org.jetbrains.kotlin:kotlin-compiler-embeddable:1.9.0.
     Required by:
         project :app > io.gitlab.arturbosch.detekt:detekt-cli:1.23.1 > io.gitlab.arturbosch.detekt:detekt-parser:1.23.1
         project :app > io.gitlab.arturbosch.detekt:detekt-cli:1.23.1 > io.gitlab.arturbosch.detekt:detekt-tooling:1.23.1 > io.gitlab.arturbosch.detekt:detekt-api:1.23.1
         project :app > io.gitlab.arturbosch.detekt:detekt-cli:1.23.1 > io.gitlab.arturbosch.detekt:detekt-parser:1.23.1 > io.gitlab.arturbosch.detekt:detekt-psi-utils:1.23.1
      > Cannot find a version of 'org.jetbrains.kotlin:kotlin-compiler-embeddable' that satisfies the version constraints:
           Dependency path 'My Application:app:unspecified' --> 'io.gitlab.arturbosch.detekt:detekt-cli:1.23.1' (runtimeElements) --> 'org.jetbrains.kotlin:kotlin-compiler-embeddable:{strictly 1.9.0}'
           Dependency path 'My Application:app:unspecified' --> 'io.gitlab.arturbosch.detekt:detekt-cli:1.23.1' (runtimeElements) --> 'io.gitlab.arturbosch.detekt:detekt-parser:1.23.1' (runtimeElements) --> 'org.jetbrains.kotlin:kotlin-compiler-embeddable:1.9.0'
           Dependency path 'My Application:app:unspecified' --> 'io.nlopez.compose.rules:detekt:0.3.0' (runtimeElements) --> 'io.nlopez.compose.rules:core-common:0.3.0' (runtimeElements) --> 'org.jetbrains.kotlin:kotlin-compiler-embeddable:1.9.10'
           Dependency path 'My Application:app:unspecified' --> 'io.gitlab.arturbosch.detekt:detekt-cli:1.23.1' (runtimeElements) --> 'io.gitlab.arturbosch.detekt:detekt-tooling:1.23.1' (runtimeElements) --> 'io.gitlab.arturbosch.detekt:detekt-api:1.23.1' (runtimeElements) --> 'org.jetbrains.kotlin:kotlin-compiler-embeddable:1.9.0'
           Dependency path 'My Application:app:unspecified' --> 'io.gitlab.arturbosch.detekt:detekt-cli:1.23.1' (runtimeElements) --> 'io.gitlab.arturbosch.detekt:detekt-parser:1.23.1' (runtimeElements) --> 'io.gitlab.arturbosch.detekt:detekt-psi-utils:1.23.1' (runtimeElements) --> 'org.jetbrains.kotlin:kotlin-compiler-embeddable:1.9.0'

   > Could not resolve org.jetbrains.kotlin:kotlin-compiler-embeddable:1.9.10.
     Required by:
         project :app > io.nlopez.compose.rules:detekt:0.3.0 > io.nlopez.compose.rules:core-common:0.3.0
      > Cannot find a version of 'org.jetbrains.kotlin:kotlin-compiler-embeddable' that satisfies the version constraints:
           Dependency path 'My Application:app:unspecified' --> 'io.gitlab.arturbosch.detekt:detekt-cli:1.23.1' (runtimeElements) --> 'org.jetbrains.kotlin:kotlin-compiler-embeddable:{strictly 1.9.0}'
           Dependency path 'My Application:app:unspecified' --> 'io.gitlab.arturbosch.detekt:detekt-cli:1.23.1' (runtimeElements) --> 'io.gitlab.arturbosch.detekt:detekt-parser:1.23.1' (runtimeElements) --> 'org.jetbrains.kotlin:kotlin-compiler-embeddable:1.9.0'
           Dependency path 'My Application:app:unspecified' --> 'io.nlopez.compose.rules:detekt:0.3.0' (runtimeElements) --> 'io.nlopez.compose.rules:core-common:0.3.0' (runtimeElements) --> 'org.jetbrains.kotlin:kotlin-compiler-embeddable:1.9.10'
           Dependency path 'My Application:app:unspecified' --> 'io.gitlab.arturbosch.detekt:detekt-cli:1.23.1' (runtimeElements) --> 'io.gitlab.arturbosch.detekt:detekt-tooling:1.23.1' (runtimeElements) --> 'io.gitlab.arturbosch.detekt:detekt-api:1.23.1' (runtimeElements) --> 'org.jetbrains.kotlin:kotlin-compiler-embeddable:1.9.0'
           Dependency path 'My Application:app:unspecified' --> 'io.gitlab.arturbosch.detekt:detekt-cli:1.23.1' (runtimeElements) --> 'io.gitlab.arturbosch.detekt:detekt-parser:1.23.1' (runtimeElements) --> 'io.gitlab.arturbosch.detekt:detekt-psi-utils:1.23.1' (runtimeElements) --> 'org.jetbrains.kotlin:kotlin-compiler-embeddable:1.9.0'

An exclusion is needed in order to avoid it:

    detektPlugins("io.gitlab.arturbosch.detekt:detekt-cli:1.23.1")
    detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.23.1")
    detektPlugins("io.nlopez.compose.rules:detekt:0.3.0") {
        exclude(group = "org.jetbrains.kotlin", module = "kotlin-compiler-embeddable")
    }

I have a test project showing this issue if you need it.

Broken PreviewPublic rule

Hi, thanks for the fork.
Everything works as expected except rule PreviewPublic.

For example this code block.
Expected behaviour: fail detekt due to this function public.

@Preview(showBackground = true)
@Composable
fun FilledIconButtonPreview() {
    FilledIconButton(
        onClick = {},
        imageVector = Icons.Default.Done
    )
}

False positive Preview naming

When using something like this as custom multi-preview definitions, probably the check should not trigger a warning.

@Preview(device = Devices.PIXEL_2, name = "PIXEL_2")
@Preview(device = Devices.NEXUS_7_2013, name = "NEXUS_7_2013")
annotation class DevicesPreview

Preview annotation naming rule does not match Googles naming scheme

In Compose UI 1.6.0 Google will introduce predefined multi-preview annotations. See commit

The annotation class names are PreviewScreenSizes, PreviewFontScale, PreviewLightDark and PreviewDynamicColors, so always having Preview as the prefix.

Currently your rule enforces Preview as the suffix in custom preview annotations we declare in our code.
So should a change in your rule be considered to be aligned with this naming scheme?

Compatibility with 0.49.0

The changelog of ktlint says:

https://github.com/pinterest/ktlint/releases/tag/0.49.0

WARNING: This version of KtLint contains a number of breaking changes in KtLint CLI and KtLint API. If you are using KtLint with custom ruleset jars or custom reporter jars, then those need to be upgraded before you can use them with this version of ktlint. Please contact the maintainers of those jars and ask them to upgrade a.s.a.p.

It would be great if you could update it :) Also I'm wondering why renovate didn't pick it up.

False positive on ModifierNotUsedAtRoot and MaterialTheme

I'm getting a false positive for ModifierNotUsedAtRoot with 0.2.0 because MaterialTheme doesn't have a Modifier parameter.

@Composable
private fun SampleCard(
  modifier: Modifier = Modifier,
  content: @Composable BoxScope.() -> Unit
) {
  MaterialTheme(
    colorScheme = darkColorScheme()
  ) {
    Box(
      modifier = modifier
        .fillMaxSize()
        .background(
          color = MaterialTheme.colorScheme.background
        )
    ) { ... }
  }
}

modifier-missing-check rule, extra ignore params

I'm wondering if there was a chance to add some config for the modifier-missing-check similarly like compose_allowed_composition_locals.

We have quite few composable functions/screens for manual UI testing, which have arg less signature

@Composable
fun TestXYZScreen() { ... }

In this case, our preferences is to follow simple arg less composable function.
Unfortunately internal modifier doesn't necessary work well in kotlin multiplatform setup.

So I was wondering for something like following to add to .editorconfig,
compose_allowed_no_modifier_functions = regex1, regex2
where I could simply pass a regexp to have easier control over the rule instead of having explicit @Suppress or passing unused Modifier for this usecase

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.