diff --git a/tests/samples/codefiles/kotlin.kt b/tests/samples/codefiles/kotlin.kt new file mode 100644 index 0000000..0200188 --- /dev/null +++ b/tests/samples/codefiles/kotlin.kt @@ -0,0 +1,22 @@ +package com.wakatime + +import java.io.* +import alpha.time.Some +import bravo.charlie.something.Other + +<#assign licenseFirst = "/*"> +<#assign licensePrefix = " * "> +<#assign licenseLast = " */"> +<#include "${project.licensePath}"> +<#if package?? && package != ""> +package ${package} + + +import delta.io.* + +class MainActivity : AppCompatActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + } +} diff --git a/tests/test_dependencies.py b/tests/test_dependencies.py index 54686f8..67041fa 100644 --- a/tests/test_dependencies.py +++ b/tests/test_dependencies.py @@ -448,3 +448,15 @@ class DependenciesTestCase(TestCase): expected_lines=21, entity='rust.rs', ) + + def test_kotlin_dependencies_detected(self): + self.shared( + expected_dependencies=[ + 'alpha.time', + 'bravo.charlie', + 'delta.io', + ], + expected_language='Kotlin', + expected_lines=22, + entity='kotlin.kt', + ) diff --git a/wakatime/dependencies/jvm.py b/wakatime/dependencies/jvm.py index e48c024..38fa408 100644 --- a/wakatime/dependencies/jvm.py +++ b/wakatime/dependencies/jvm.py @@ -96,6 +96,65 @@ class JavaParser(TokenParser): pass +class KotlinParser(TokenParser): + state = None + exclude = [ + r'^java\.', + ] + + def parse(self): + for index, token, content in self.tokens: + self._process_token(token, content) + return self.dependencies + + def _process_token(self, token, content): + if self.partial(token) == 'Keyword': + self._process_keyword(token, content) + elif self.partial(token) == 'Text': + self._process_text(token, content) + elif self.partial(token) == 'Namespace': + self._process_namespace(token, content) + else: + self._process_other(token, content) + + def _process_keyword(self, token, content): + self.state = content + + def _process_text(self, token, content): + pass + + def _process_namespace(self, token, content): + if self.state == 'import': + self.append(self._format(content)) + self.state = None + + def _process_other(self, token, content): + self.state = None + + def _format(self, content): + content = content.split(u('.')) + + if len(content) == 0: + return None + + if len(content) == 1: + return content[0] + + if len(content[0]) == 3: + content = content[1:] + if content[-1] == u('*'): + content = content[:len(content) - 1] + + if len(content) == 0: + return None + elif len(content) == 1: + content = content[0] + elif len(content) > 1: + content = u('.').join(content[:2]) + + return content + + class ScalaParser(TokenParser): state = None