diff --git a/tests/samples/codefiles/empty.ts b/tests/samples/codefiles/empty.ts new file mode 100644 index 0000000..e69de29 diff --git a/tests/samples/codefiles/es6.js b/tests/samples/codefiles/es6.js new file mode 100644 index 0000000..1b92b22 --- /dev/null +++ b/tests/samples/codefiles/es6.js @@ -0,0 +1,37 @@ +import Alpha from './bravo'; +import { charlie, delta } from '../../echo/foxtrot'; +import golf from './hotel/india.js'; +import juliett from 'kilo'; +import { + lima, + mike, +} from './november'; +import * from '/modules/oscar'; +import * as papa from 'quebec'; +import {romeo as sierra} from from 'tango.jsx'; +import 'uniform.js'; +import victorDefault, * as victorModule from '/modules/victor.js'; +import whiskeyDefault, {whiskeyOne, whiskeyTwo} from 'whiskey'; + +const propTypes = {}; + +const defaultProps = {}; + +class Link extends Alpha.Component { + static method() { + return true; + } + + render() { + return ( + + {this.props.text} + + ); + } +} + +Link.propTypes = propTypes; +Link.defaultProps = defaultProps; + +export default Link; diff --git a/tests/samples/codefiles/typescript.ts b/tests/samples/codefiles/typescript.ts index 157017f..e69de29 100644 --- a/tests/samples/codefiles/typescript.ts +++ b/tests/samples/codefiles/typescript.ts @@ -1,3 +0,0 @@ -/** - * A Comment - */ diff --git a/tests/test_dependencies.py b/tests/test_dependencies.py index 6f2d406..751935b 100644 --- a/tests/test_dependencies.py +++ b/tests/test_dependencies.py @@ -188,6 +188,28 @@ class DependenciesTestCase(TestCase): entity='python.py', ) + def test_dependencies_still_detected_when_alternate_language_used(self): + with mock.patch('wakatime.stats.smart_guess_lexer') as mock_guess_lexer: + mock_guess_lexer.return_value = None + + self.shared( + expected_dependencies=[ + 'app', + 'django', + 'flask', + 'jinja', + 'mock', + 'pygments', + 'simplejson', + 'sqlalchemy', + 'unittest', + ], + expected_language='Python', + expected_lines=37, + entity='python.py', + extra_args=['--alternate-language', 'PYTHON'], + ) + def test_python_dependencies_detected(self): self.shared( expected_dependencies=[ @@ -302,7 +324,7 @@ class DependenciesTestCase(TestCase): expected_dependencies=[ '"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"', ], - expected_language='HTML+PHP', + expected_language='HTML', expected_lines=22, entity='html-with-php.html', ) @@ -312,7 +334,7 @@ class DependenciesTestCase(TestCase): expected_dependencies=[ '"libs/json2.js"', ], - expected_language='HTML+Django/Jinja', + expected_language='HTML', expected_lines=40, entity='html-django.html', ) @@ -336,24 +358,22 @@ class DependenciesTestCase(TestCase): entity='go.go', ) - def test_dependencies_still_detected_when_alternate_language_used(self): - with mock.patch('wakatime.stats.smart_guess_lexer') as mock_guess_lexer: - mock_guess_lexer.return_value = None - - self.shared( - expected_dependencies=[ - 'app', - 'django', - 'flask', - 'jinja', - 'mock', - 'pygments', - 'simplejson', - 'sqlalchemy', - 'unittest', - ], - expected_language='Python', - expected_lines=37, - entity='python.py', - extra_args=['--alternate-language', 'PYTHON'], - ) + def test_es6_dependencies_detected(self): + self.shared( + expected_dependencies=[ + 'bravo', + 'foxtrot', + 'india', + 'kilo', + 'november', + 'oscar', + 'quebec', + 'tango', + 'uniform', + 'victor', + 'whiskey', + ], + expected_language='JavaScript', + expected_lines=37, + entity='es6.js', + ) diff --git a/tests/test_languages.py b/tests/test_languages.py index 8c867d8..1df212e 100644 --- a/tests/test_languages.py +++ b/tests/test_languages.py @@ -141,7 +141,7 @@ class LanguagesTestCase(utils.TestCase): def test_typescript_detected_over_typoscript(self): self.shared( expected_language='TypeScript', - entity='typescript.ts', + entity='empty.ts', extra_args=['--language', 'foo', '--plugin', 'NeoVim/703 vim-wakatime/4.0.9'] ) diff --git a/wakatime/dependencies/__init__.py b/wakatime/dependencies/__init__.py index dccb3bf..b7653bc 100644 --- a/wakatime/dependencies/__init__.py +++ b/wakatime/dependencies/__init__.py @@ -106,8 +106,8 @@ class DependencyParser(object): self.lexer = lexer if self.lexer: - module_name = self.lexer.__module__.rsplit('.', 1)[-1] - class_name = self.lexer.__class__.__name__.replace('Lexer', 'Parser', 1) + module_name = self.root_lexer.__module__.rsplit('.', 1)[-1] + class_name = self.root_lexer.__class__.__name__.replace('Lexer', 'Parser', 1) else: module_name = 'unknown' class_name = 'UnknownParser' @@ -121,6 +121,14 @@ class DependencyParser(object): except ImportError: log.debug('Parsing dependencies not supported for {0}.{1}'.format(module_name, class_name)) + @property + def root_lexer(self): + if not self.lexer: + return None + if hasattr(self.lexer, 'root_lexer'): + return self.lexer.root_lexer + return self.lexer + def parse(self): if self.parser: plugin = self.parser(self.source_file, lexer=self.lexer) diff --git a/wakatime/dependencies/c_cpp.py b/wakatime/dependencies/c_cpp.py index 8729743..3d4eb6d 100644 --- a/wakatime/dependencies/c_cpp.py +++ b/wakatime/dependencies/c_cpp.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ - wakatime.languages.c_cpp - ~~~~~~~~~~~~~~~~~~~~~~~~ + wakatime.dependencies.c_cpp + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Parse dependencies from C++ code. diff --git a/wakatime/dependencies/data.py b/wakatime/dependencies/data.py index 389a1b6..121b70b 100644 --- a/wakatime/dependencies/data.py +++ b/wakatime/dependencies/data.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ - wakatime.languages.data - ~~~~~~~~~~~~~~~~~~~~~~~ + wakatime.dependencies.data + ~~~~~~~~~~~~~~~~~~~~~~~~~~ Parse dependencies from data files. diff --git a/wakatime/dependencies/dotnet.py b/wakatime/dependencies/dotnet.py index 7d67341..53557e9 100644 --- a/wakatime/dependencies/dotnet.py +++ b/wakatime/dependencies/dotnet.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ - wakatime.languages.dotnet - ~~~~~~~~~~~~~~~~~~~~~~~~~ + wakatime.dependencies.dotnet + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Parse dependencies from .NET code. diff --git a/wakatime/dependencies/go.py b/wakatime/dependencies/go.py index 2231e70..95bea21 100644 --- a/wakatime/dependencies/go.py +++ b/wakatime/dependencies/go.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ - wakatime.languages.go - ~~~~~~~~~~~~~~~~~~~~~ + wakatime.dependencies.go + ~~~~~~~~~~~~~~~~~~~~~~~~ Parse dependencies from Go code. diff --git a/wakatime/dependencies/templates.py b/wakatime/dependencies/html.py similarity index 81% rename from wakatime/dependencies/templates.py rename to wakatime/dependencies/html.py index 422a971..a2b34b4 100644 --- a/wakatime/dependencies/templates.py +++ b/wakatime/dependencies/html.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- """ - wakatime.languages.templates - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + wakatime.dependencies.html + ~~~~~~~~~~~~~~~~~~~~~~~~~~ - Parse dependencies from Templates. + Parse dependencies from HTML. :copyright: (c) 2014 Alan Hamlett. :license: BSD, see LICENSE for more details. @@ -69,7 +69,7 @@ KEYWORDS = [ ] -class HtmlDjangoParser(TokenParser): +class HtmlParser(TokenParser): tags = [] opening_tag = False getting_attrs = False @@ -141,63 +141,3 @@ class HtmlDjangoParser(TokenParser): elif content.startswith('"') or content.startswith("'"): if self.current_attr_value is None: self.current_attr_value = content - - -class VelocityHtmlParser(HtmlDjangoParser): - pass - - -class MyghtyHtmlParser(HtmlDjangoParser): - pass - - -class MasonParser(HtmlDjangoParser): - pass - - -class MakoHtmlParser(HtmlDjangoParser): - pass - - -class CheetahHtmlParser(HtmlDjangoParser): - pass - - -class HtmlGenshiParser(HtmlDjangoParser): - pass - - -class RhtmlParser(HtmlDjangoParser): - pass - - -class HtmlPhpParser(HtmlDjangoParser): - pass - - -class HtmlSmartyParser(HtmlDjangoParser): - pass - - -class EvoqueHtmlParser(HtmlDjangoParser): - pass - - -class ColdfusionHtmlParser(HtmlDjangoParser): - pass - - -class LassoHtmlParser(HtmlDjangoParser): - pass - - -class HandlebarsHtmlParser(HtmlDjangoParser): - pass - - -class YamlJinjaParser(HtmlDjangoParser): - pass - - -class TwigHtmlParser(HtmlDjangoParser): - pass diff --git a/wakatime/dependencies/javascript.py b/wakatime/dependencies/javascript.py new file mode 100644 index 0000000..0627788 --- /dev/null +++ b/wakatime/dependencies/javascript.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +""" + wakatime.dependencies.javascript + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Parse dependencies from JavaScript code. + + :copyright: (c) 2018 Alan Hamlett. + :license: BSD, see LICENSE for more details. +""" + +import re + +from . import TokenParser + + +class JavascriptParser(TokenParser): + state = None + extension = re.compile(r'\.\w{1,4}$') + + 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) == 'Reserved': + self._process_reserved(token, content) + elif self.partial(token) == 'Single': + self._process_string(token, content) + elif self.partial(token) == 'Punctuation': + self._process_punctuation(token, content) + else: + self._process_other(token, content) + + def _process_reserved(self, token, content): + if self.state is None: + self.state = content + + def _process_string(self, token, content): + if self.state == 'import': + self.append(self._format_module(content)) + self.state = None + + def _process_punctuation(self, token, content): + if content == ';': + self.state = None + + def _process_other(self, token, content): + pass + + def _format_module(self, content): + content = content.strip().strip('"').strip("'").strip() + content = content.split('/')[-1].split('\\')[-1] + content = self.extension.sub('', content, count=1) + return content diff --git a/wakatime/dependencies/jvm.py b/wakatime/dependencies/jvm.py index 421474d..f92471c 100644 --- a/wakatime/dependencies/jvm.py +++ b/wakatime/dependencies/jvm.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ - wakatime.languages.java - ~~~~~~~~~~~~~~~~~~~~~~~ + wakatime.dependencies.java + ~~~~~~~~~~~~~~~~~~~~~~~~~~ Parse dependencies from Java code. diff --git a/wakatime/dependencies/php.py b/wakatime/dependencies/php.py index dea7846..70798e3 100644 --- a/wakatime/dependencies/php.py +++ b/wakatime/dependencies/php.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ - wakatime.languages.php - ~~~~~~~~~~~~~~~~~~~~~~ + wakatime.dependencies.php + ~~~~~~~~~~~~~~~~~~~~~~~~~ Parse dependencies from PHP code. diff --git a/wakatime/dependencies/python.py b/wakatime/dependencies/python.py index 43b10bd..6cab7dd 100644 --- a/wakatime/dependencies/python.py +++ b/wakatime/dependencies/python.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ - wakatime.languages.python - ~~~~~~~~~~~~~~~~~~~~~~~~~ + wakatime.dependencies.python + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Parse dependencies from Python code. diff --git a/wakatime/dependencies/unknown.py b/wakatime/dependencies/unknown.py index 5d269eb..e37561f 100644 --- a/wakatime/dependencies/unknown.py +++ b/wakatime/dependencies/unknown.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ - wakatime.languages.unknown - ~~~~~~~~~~~~~~~~~~~~~~~~~~ + wakatime.dependencies.unknown + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Parse dependencies from files of unknown language. diff --git a/wakatime/stats.py b/wakatime/stats.py index 9d889d4..f58aed3 100644 --- a/wakatime/stats.py +++ b/wakatime/stats.py @@ -53,6 +53,8 @@ def get_file_stats(file_name, entity_type='file', lineno=None, cursorpos=None, if not language: language, lexer = guess_language(file_name) + language = use_root_language(language, lexer) + parser = DependencyParser(file_name, lexer) dependencies = parser.parse() @@ -236,6 +238,13 @@ def get_lexer(language): return None +def use_root_language(language, lexer): + if lexer and hasattr(lexer, 'root_lexer'): + return u(lexer.root_lexer.name) + + return language + + def get_language_from_json(language, key): """Finds the given language in a json file."""