lizard 1.17.14__tar.gz → 1.17.16__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. {lizard-1.17.14 → lizard-1.17.16}/PKG-INFO +9 -1
  2. {lizard-1.17.14 → lizard-1.17.16}/README.rst +8 -0
  3. {lizard-1.17.14 → lizard-1.17.16}/lizard.egg-info/PKG-INFO +9 -1
  4. {lizard-1.17.14 → lizard-1.17.16}/lizard.egg-info/SOURCES.txt +1 -0
  5. {lizard-1.17.14 → lizard-1.17.16}/lizard.egg-info/requires.txt +1 -0
  6. {lizard-1.17.14 → lizard-1.17.16}/lizard.py +37 -12
  7. {lizard-1.17.14 → lizard-1.17.16}/lizard_ext/csvoutput.py +11 -25
  8. {lizard-1.17.14 → lizard-1.17.16}/lizard_ext/version.py +1 -1
  9. {lizard-1.17.14 → lizard-1.17.16}/lizard_languages/__init__.py +2 -0
  10. {lizard-1.17.14 → lizard-1.17.16}/lizard_languages/code_reader.py +2 -1
  11. lizard-1.17.16/lizard_languages/csharp.py +62 -0
  12. lizard-1.17.16/lizard_languages/java.py +89 -0
  13. lizard-1.17.16/lizard_languages/javascript.py +19 -0
  14. {lizard-1.17.14 → lizard-1.17.16}/lizard_languages/js_style_language_states.py +20 -21
  15. lizard-1.17.16/lizard_languages/js_style_regex_expression.py +53 -0
  16. lizard-1.17.14/lizard_languages/javascript.py → lizard-1.17.16/lizard_languages/jsx.py +21 -47
  17. {lizard-1.17.14 → lizard-1.17.16}/lizard_languages/script_language.py +1 -1
  18. lizard-1.17.16/lizard_languages/tsx.py +24 -0
  19. lizard-1.17.16/lizard_languages/typescript.py +124 -0
  20. lizard-1.17.16/lizard_languages/vue.py +34 -0
  21. {lizard-1.17.14 → lizard-1.17.16}/setup.py +1 -1
  22. {lizard-1.17.14 → lizard-1.17.16}/test/testFilesFilter.py +31 -0
  23. {lizard-1.17.14 → lizard-1.17.16}/test/testOutput.py +1 -1
  24. lizard-1.17.16/test/testOutputFile.py +117 -0
  25. lizard-1.17.14/lizard_languages/csharp.py +0 -20
  26. lizard-1.17.14/lizard_languages/java.py +0 -44
  27. lizard-1.17.14/lizard_languages/js_style_regex_expression.py +0 -23
  28. lizard-1.17.14/lizard_languages/jsx.py +0 -27
  29. lizard-1.17.14/lizard_languages/tsx.py +0 -44
  30. lizard-1.17.14/lizard_languages/typescript.py +0 -75
  31. lizard-1.17.14/test/testOutputFile.py +0 -58
  32. {lizard-1.17.14 → lizard-1.17.16}/LICENSE.txt +0 -0
  33. {lizard-1.17.14 → lizard-1.17.16}/lizard.egg-info/dependency_links.txt +0 -0
  34. {lizard-1.17.14 → lizard-1.17.16}/lizard.egg-info/entry_points.txt +0 -0
  35. {lizard-1.17.14 → lizard-1.17.16}/lizard.egg-info/top_level.txt +0 -0
  36. {lizard-1.17.14 → lizard-1.17.16}/lizard_ext/__init__.py +0 -0
  37. {lizard-1.17.14 → lizard-1.17.16}/lizard_ext/auto_open.py +0 -0
  38. {lizard-1.17.14 → lizard-1.17.16}/lizard_ext/default_ordered_dict.py +0 -0
  39. {lizard-1.17.14 → lizard-1.17.16}/lizard_ext/extension_base.py +0 -0
  40. {lizard-1.17.14 → lizard-1.17.16}/lizard_ext/htmloutput.py +0 -0
  41. {lizard-1.17.14 → lizard-1.17.16}/lizard_ext/keywords.py +0 -0
  42. {lizard-1.17.14 → lizard-1.17.16}/lizard_ext/lizardboolcount.py +0 -0
  43. {lizard-1.17.14 → lizard-1.17.16}/lizard_ext/lizardcomplextags.py +0 -0
  44. {lizard-1.17.14 → lizard-1.17.16}/lizard_ext/lizardcpre.py +0 -0
  45. {lizard-1.17.14 → lizard-1.17.16}/lizard_ext/lizarddependencycount.py +0 -0
  46. {lizard-1.17.14 → lizard-1.17.16}/lizard_ext/lizarddumpcomments.py +0 -0
  47. {lizard-1.17.14 → lizard-1.17.16}/lizard_ext/lizardduplicate.py +0 -0
  48. {lizard-1.17.14 → lizard-1.17.16}/lizard_ext/lizardduplicated_param_list.py +0 -0
  49. {lizard-1.17.14 → lizard-1.17.16}/lizard_ext/lizardexitcount.py +0 -0
  50. {lizard-1.17.14 → lizard-1.17.16}/lizard_ext/lizardgotocount.py +0 -0
  51. {lizard-1.17.14 → lizard-1.17.16}/lizard_ext/lizardignoreassert.py +0 -0
  52. {lizard-1.17.14 → lizard-1.17.16}/lizard_ext/lizardio.py +0 -0
  53. {lizard-1.17.14 → lizard-1.17.16}/lizard_ext/lizardmccabe.py +0 -0
  54. {lizard-1.17.14 → lizard-1.17.16}/lizard_ext/lizardmodified.py +0 -0
  55. {lizard-1.17.14 → lizard-1.17.16}/lizard_ext/lizardnd.py +0 -0
  56. {lizard-1.17.14 → lizard-1.17.16}/lizard_ext/lizardnonstrict.py +0 -0
  57. {lizard-1.17.14 → lizard-1.17.16}/lizard_ext/lizardns.py +0 -0
  58. {lizard-1.17.14 → lizard-1.17.16}/lizard_ext/lizardoutside.py +0 -0
  59. {lizard-1.17.14 → lizard-1.17.16}/lizard_ext/lizardstatementcount.py +0 -0
  60. {lizard-1.17.14 → lizard-1.17.16}/lizard_ext/lizardwordcount.py +0 -0
  61. {lizard-1.17.14 → lizard-1.17.16}/lizard_ext/xmloutput.py +0 -0
  62. {lizard-1.17.14 → lizard-1.17.16}/lizard_languages/clike.py +0 -0
  63. {lizard-1.17.14 → lizard-1.17.16}/lizard_languages/erlang.py +0 -0
  64. {lizard-1.17.14 → lizard-1.17.16}/lizard_languages/fortran.py +0 -0
  65. {lizard-1.17.14 → lizard-1.17.16}/lizard_languages/gdscript.py +0 -0
  66. {lizard-1.17.14 → lizard-1.17.16}/lizard_languages/go.py +0 -0
  67. {lizard-1.17.14 → lizard-1.17.16}/lizard_languages/golike.py +0 -0
  68. {lizard-1.17.14 → lizard-1.17.16}/lizard_languages/kotlin.py +0 -0
  69. {lizard-1.17.14 → lizard-1.17.16}/lizard_languages/lua.py +0 -0
  70. {lizard-1.17.14 → lizard-1.17.16}/lizard_languages/objc.py +0 -0
  71. {lizard-1.17.14 → lizard-1.17.16}/lizard_languages/php.py +0 -0
  72. {lizard-1.17.14 → lizard-1.17.16}/lizard_languages/python.py +0 -0
  73. {lizard-1.17.14 → lizard-1.17.16}/lizard_languages/ruby.py +0 -0
  74. {lizard-1.17.14 → lizard-1.17.16}/lizard_languages/rubylike.py +0 -0
  75. {lizard-1.17.14 → lizard-1.17.16}/lizard_languages/rust.py +0 -0
  76. {lizard-1.17.14 → lizard-1.17.16}/lizard_languages/scala.py +0 -0
  77. {lizard-1.17.14 → lizard-1.17.16}/lizard_languages/solidity.py +0 -0
  78. {lizard-1.17.14 → lizard-1.17.16}/lizard_languages/swift.py +0 -0
  79. {lizard-1.17.14 → lizard-1.17.16}/lizard_languages/tnsdl.py +0 -0
  80. {lizard-1.17.14 → lizard-1.17.16}/lizard_languages/ttcn.py +0 -0
  81. {lizard-1.17.14 → lizard-1.17.16}/lizard_languages/zig.py +0 -0
  82. {lizard-1.17.14 → lizard-1.17.16}/setup.cfg +0 -0
  83. {lizard-1.17.14 → lizard-1.17.16}/test/testApplication.py +0 -0
  84. {lizard-1.17.14 → lizard-1.17.16}/test/testAssertionExtension.py +0 -0
  85. {lizard-1.17.14 → lizard-1.17.16}/test/testBasicFunctionInfo.py +0 -0
  86. {lizard-1.17.14 → lizard-1.17.16}/test/testCOutsideComplexity.py +0 -0
  87. {lizard-1.17.14 → lizard-1.17.16}/test/testCPreprocessorExtension.py +0 -0
  88. {lizard-1.17.14 → lizard-1.17.16}/test/testCommentOptions.py +0 -0
  89. {lizard-1.17.14 → lizard-1.17.16}/test/testCyclomaticComplexity.py +0 -0
  90. {lizard-1.17.14 → lizard-1.17.16}/test/testExtension.py +0 -0
  91. {lizard-1.17.14 → lizard-1.17.16}/test/testFunctionDependencyCount.py +0 -0
  92. {lizard-1.17.14 → lizard-1.17.16}/test/testFunctionExitCount.py +0 -0
  93. {lizard-1.17.14 → lizard-1.17.16}/test/testFunctionGotoCount.py +0 -0
  94. {lizard-1.17.14 → lizard-1.17.16}/test/testFunctionStatementCount.py +0 -0
  95. {lizard-1.17.14 → lizard-1.17.16}/test/testHelpers.py +0 -0
  96. {lizard-1.17.14 → lizard-1.17.16}/test/testLanguages.py +0 -0
  97. {lizard-1.17.14 → lizard-1.17.16}/test/testMcCabe.py +0 -0
  98. {lizard-1.17.14 → lizard-1.17.16}/test/testNestedStructures.py +0 -0
  99. {lizard-1.17.14 → lizard-1.17.16}/test/testNestingDepth.py +0 -0
  100. {lizard-1.17.14 → lizard-1.17.16}/test/testOutputCSV.py +0 -0
  101. {lizard-1.17.14 → lizard-1.17.16}/test/testOutputHTML.py +0 -0
  102. {lizard-1.17.14 → lizard-1.17.16}/test/testTokenizer.py +0 -0
  103. {lizard-1.17.14 → lizard-1.17.16}/test/test_analyzer.py +0 -0
  104. {lizard-1.17.14 → lizard-1.17.16}/test/test_auto_open.py +0 -0
  105. {lizard-1.17.14 → lizard-1.17.16}/test/test_options.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lizard
3
- Version: 1.17.14
3
+ Version: 1.17.16
4
4
  Summary: A code analyzer without caring the C/C++ header files. It works with Java, C/C++, JavaScript, Python, Ruby, Swift, Objective C. Metrics includes cyclomatic complexity number etc.
5
5
  Home-page: http://www.lizard.ws
6
6
  Download-URL: https://pypi.python.org/lizard/
@@ -53,6 +53,7 @@ A list of supported languages:
53
53
  - C# (C Sharp)
54
54
  - JavaScript (With ES6 and JSX)
55
55
  - TypeScript (With TSX)
56
+ - VueJS
56
57
  - Objective-C
57
58
  - Swift
58
59
  - Python
@@ -136,6 +137,13 @@ Exclude anything in the tests folder:
136
137
 
137
138
  lizard mySource/ -x"./tests/*"
138
139
 
140
+ Use .gitignore file:
141
+
142
+ ::
143
+
144
+ lizard mySource/
145
+
146
+ If there is a .gitignore file in the given path, lizard will automatically use it as an additional filter to exclude files that match the gitignore patterns. This is useful when you want to analyze only the tracked files in your git repository.
139
147
 
140
148
  Options
141
149
  ~~~~~~~
@@ -22,6 +22,7 @@ A list of supported languages:
22
22
  - C# (C Sharp)
23
23
  - JavaScript (With ES6 and JSX)
24
24
  - TypeScript (With TSX)
25
+ - VueJS
25
26
  - Objective-C
26
27
  - Swift
27
28
  - Python
@@ -105,6 +106,13 @@ Exclude anything in the tests folder:
105
106
 
106
107
  lizard mySource/ -x"./tests/*"
107
108
 
109
+ Use .gitignore file:
110
+
111
+ ::
112
+
113
+ lizard mySource/
114
+
115
+ If there is a .gitignore file in the given path, lizard will automatically use it as an additional filter to exclude files that match the gitignore patterns. This is useful when you want to analyze only the tracked files in your git repository.
108
116
 
109
117
  Options
110
118
  ~~~~~~~
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lizard
3
- Version: 1.17.14
3
+ Version: 1.17.16
4
4
  Summary: A code analyzer without caring the C/C++ header files. It works with Java, C/C++, JavaScript, Python, Ruby, Swift, Objective C. Metrics includes cyclomatic complexity number etc.
5
5
  Home-page: http://www.lizard.ws
6
6
  Download-URL: https://pypi.python.org/lizard/
@@ -53,6 +53,7 @@ A list of supported languages:
53
53
  - C# (C Sharp)
54
54
  - JavaScript (With ES6 and JSX)
55
55
  - TypeScript (With TSX)
56
+ - VueJS
56
57
  - Objective-C
57
58
  - Swift
58
59
  - Python
@@ -136,6 +137,13 @@ Exclude anything in the tests folder:
136
137
 
137
138
  lizard mySource/ -x"./tests/*"
138
139
 
140
+ Use .gitignore file:
141
+
142
+ ::
143
+
144
+ lizard mySource/
145
+
146
+ If there is a .gitignore file in the given path, lizard will automatically use it as an additional filter to exclude files that match the gitignore patterns. This is useful when you want to analyze only the tracked files in your git repository.
139
147
 
140
148
  Options
141
149
  ~~~~~~~
@@ -67,6 +67,7 @@ lizard_languages/tnsdl.py
67
67
  lizard_languages/tsx.py
68
68
  lizard_languages/ttcn.py
69
69
  lizard_languages/typescript.py
70
+ lizard_languages/vue.py
70
71
  lizard_languages/zig.py
71
72
  test/testApplication.py
72
73
  test/testAssertionExtension.py
@@ -1 +1,2 @@
1
1
  pygments
2
+ pathspec
@@ -298,8 +298,7 @@ class FunctionInfo(Nesting): # pylint: disable=R0902
298
298
  return self.name.split('::')[-1]
299
299
 
300
300
  location = property(lambda self:
301
- " %(name)s@%(start_line)s-%(end_line)s@%(filename)s"
302
- % self.__dict__)
301
+ f" {self.name}@{self.start_line}-{self.end_line}@{self.filename}")
303
302
 
304
303
  parameter_count = property(lambda self: len(self.parameters))
305
304
 
@@ -723,17 +722,13 @@ class OutputScheme(object):
723
722
  if e.get("avg_caption", None)])
724
723
 
725
724
  def clang_warning_format(self):
726
- return (
727
- "{f.filename}:{f.start_line}: warning: {f.name} has " +
728
- ", ".join([
729
- "{{f.{ext[value]}}} {caption}"
730
- .format(ext=e, caption=e['caption'].strip())
731
- for e in self.items[:-1]
732
- ]))
725
+ return ("{f.filename}:{f.start_line}: warning: {f.name} has {f.nloc} NLOC, "
726
+ "{f.cyclomatic_complexity} CCN, {f.token_count} token, {f.parameter_count} PARAM, "
727
+ "{f.length} length, {f.max_nesting_depth} ND")
733
728
 
734
729
  def msvs_warning_format(self):
735
730
  return (
736
- "{f.filename}({f.start_line}): warning: {f.name} has " +
731
+ "{f.filename}({f.start_line}): warning: {f.name} ({f.long_name}) has " +
737
732
  ", ".join([
738
733
  "{{f.{ext[value]}}} {caption}"
739
734
  .format(ext=e, caption=e['caption'].strip())
@@ -901,14 +896,43 @@ def md5_hash_file(full_path_name):
901
896
  def get_all_source_files(paths, exclude_patterns, lans):
902
897
  '''
903
898
  Function counts md5 hash for the given file and checks if it isn't a
904
- duplicate using set of hashes for previous files '''
899
+ duplicate using set of hashes for previous files.
900
+
901
+ If a .gitignore file is found in any of the given paths, it will be used
902
+ to filter out files that match the gitignore patterns.
903
+ '''
905
904
  hash_set = set()
905
+ gitignore_spec = None
906
+ base_path = None
907
+
908
+ def _load_gitignore():
909
+ nonlocal gitignore_spec, base_path
910
+ try:
911
+ import pathspec
912
+ for path in paths:
913
+ gitignore_path = os.path.join(path, '.gitignore')
914
+ if os.path.exists(gitignore_path):
915
+ with open(gitignore_path, 'r') as gitignore_file:
916
+ # Read lines and strip whitespace and empty lines
917
+ patterns = [line.strip() for line in gitignore_file.readlines()]
918
+ patterns = [p for p in patterns if p and not p.startswith('#')]
919
+ gitignore_spec = pathspec.PathSpec.from_lines('gitwildmatch', patterns)
920
+ base_path = path
921
+ break
922
+ except ImportError:
923
+ pass
906
924
 
907
925
  def _support(reader):
908
926
  return not lans or set(lans).intersection(
909
927
  reader.language_names)
910
928
 
911
929
  def _validate_file(pathname):
930
+ if gitignore_spec is not None and base_path is not None:
931
+ rel_path = os.path.relpath(pathname, base_path)
932
+ # Normalize path separators for consistent matching
933
+ rel_path = rel_path.replace(os.sep, '/')
934
+ if gitignore_spec.match_file(rel_path):
935
+ return False
912
936
  return (
913
937
  pathname in paths or (
914
938
  get_reader_for(pathname) and
@@ -931,6 +955,7 @@ def get_all_source_files(paths, exclude_patterns, lans):
931
955
  for filename in files:
932
956
  yield os.path.join(root, filename)
933
957
 
958
+ _load_gitignore()
934
959
  return filter(_validate_file, all_listed_files(paths))
935
960
 
936
961
 
@@ -972,7 +997,7 @@ def parse_args(argv):
972
997
  if inferred_printer:
973
998
  if not opt.printer:
974
999
  opt.printer = inferred_printer
975
- else:
1000
+ elif opt.printer != inferred_printer:
976
1001
  msg = "Warning: overriding output file extension.\n"
977
1002
  sys.stderr.write(msg)
978
1003
  return opt
@@ -36,9 +36,9 @@ def csv_output(result, options):
36
36
  if options.verbose:
37
37
  extension_caption = ""
38
38
  for caption in extension_captions:
39
- extension_caption = "{},{}".format(extension_caption, caption)
40
- print("NLOC,CCN,token,PARAM,length,location,file,function," +
41
- "long_name,start,end{}".format(extension_caption))
39
+ extension_caption = f"{extension_caption},{caption}"
40
+ print(f"NLOC,CCN,token,PARAM,length,location,file,function," +
41
+ f"long_name,start,end{extension_caption}")
42
42
 
43
43
  for source_file in result:
44
44
  if source_file:
@@ -46,25 +46,11 @@ def csv_output(result, options):
46
46
  if source_function:
47
47
  extension_string = ''
48
48
  for variable in extension_variables:
49
- extension_string = '{},{}'.\
50
- format(extension_string,
51
- source_function.__getattribute__(variable))
52
- print('{},{},{},{},{},"{}","{}","{}","{}",{},{}{}'.format(
53
- source_function.nloc,
54
- source_function.cyclomatic_complexity,
55
- source_function.token_count,
56
- len(source_function.parameters),
57
- source_function.length,
58
- "{}@{}-{}@{}".format(
59
- source_function.name.replace("\"", "'"),
60
- source_function.start_line,
61
- source_function.end_line,
62
- source_file.filename
63
- ),
64
- source_file.filename,
65
- source_function.name.replace("\"", "'"),
66
- source_function.long_name.replace("\"", "'"),
67
- source_function.start_line,
68
- source_function.end_line,
69
- extension_string
70
- ))
49
+ extension_string = f"{extension_string},{source_function.__getattribute__(variable)}"
50
+ print(f"{source_function.nloc},{source_function.cyclomatic_complexity},"
51
+ f"{source_function.token_count},{len(source_function.parameters)},"
52
+ f'{source_function.length},"{source_function.name.replace(chr(34), chr(39))}@'
53
+ f'{source_function.start_line}-{source_function.end_line}@{source_file.filename}",'
54
+ f'"{source_file.filename}","{source_function.name.replace(chr(34), chr(39))}",'
55
+ f'"{source_function.long_name.replace(chr(34), chr(39))}",'
56
+ f"{source_function.start_line},{source_function.end_line}{extension_string}")
@@ -3,4 +3,4 @@
3
3
  #
4
4
  # pylint: disable=missing-docstring,invalid-name
5
5
 
6
- version = "1.17.14"
6
+ version = "1.17.16"
@@ -23,6 +23,7 @@ from .fortran import FortranReader
23
23
  from .solidity import SolidityReader
24
24
  from .jsx import JSXReader
25
25
  from .tsx import TSXReader
26
+ from .vue import VueReader
26
27
 
27
28
 
28
29
  def languages():
@@ -50,6 +51,7 @@ def languages():
50
51
  ZigReader,
51
52
  JSXReader,
52
53
  TSXReader,
54
+ VueReader,
53
55
  ]
54
56
 
55
57
 
@@ -8,7 +8,7 @@ from functools import reduce
8
8
  from operator import or_
9
9
 
10
10
 
11
- class CodeStateMachine(object):
11
+ class CodeStateMachine:
12
12
  """ the state machine """
13
13
  # pylint: disable=R0903
14
14
  # pylint: disable=R0902
@@ -50,6 +50,7 @@ class CodeStateMachine(object):
50
50
  self.next(self.saved_state)
51
51
  if self.callback:
52
52
  self.callback()
53
+ self.callback = None
53
54
  self.last_token = token
54
55
  if self.to_exit:
55
56
  return True
@@ -0,0 +1,62 @@
1
+ '''
2
+ Language parser for C Sharp
3
+ '''
4
+
5
+ from .clike import CLikeReader, CLikeStates, CLikeNestingStackStates
6
+
7
+
8
+ class CSharpReader(CLikeReader):
9
+ # pylint: disable=R0903
10
+
11
+ ext = ['cs']
12
+ language_names = ['csharp']
13
+
14
+ _conditions = set(['if', 'for', 'while', '&&', '||', '?', 'catch',
15
+ 'case', '??'])
16
+
17
+ def __init__(self, context):
18
+ super(CSharpReader, self).__init__(context)
19
+ self.parallel_states = [
20
+ CSharpStates(context),
21
+ CLikeNestingStackStates(context)
22
+ ]
23
+
24
+ @staticmethod
25
+ def generate_tokens(source_code, addition='', token_class=None):
26
+ return CLikeReader.generate_tokens(
27
+ source_code, r"|(?:\?\?)", token_class)
28
+
29
+
30
+ class CSharpStates(CLikeStates):
31
+ def __init__(self, context):
32
+ super(CSharpStates, self).__init__(context)
33
+ self.in_primary_constructor = False
34
+ self.class_name = None
35
+
36
+ def try_new_function(self, name):
37
+ if not self.in_primary_constructor:
38
+ super(CSharpStates, self).try_new_function(name)
39
+ if self.class_name and self.context.current_function:
40
+ self.context.current_function.name = f"{self.class_name}::{name}"
41
+
42
+ def _state_global(self, token):
43
+ if token in ("class", "struct", "record"):
44
+ self.class_name = None
45
+ self._state = self._state_class_declaration
46
+ else:
47
+ super(CSharpStates, self)._state_global(token)
48
+
49
+ def _state_class_declaration(self, token):
50
+ if token == '(': # Primary constructor
51
+ self.in_primary_constructor = True
52
+ self._state = self._state_primary_constructor
53
+ elif token == '{':
54
+ self._state = self._state_global
55
+ elif token[0].isalpha():
56
+ if not self.class_name: # Only set class name if not already set
57
+ self.class_name = token
58
+
59
+ @CLikeStates.read_inside_brackets_then("()", "_state_class_declaration")
60
+ def _state_primary_constructor(self, _):
61
+ """Skip primary constructor parameters without counting them as a function"""
62
+ self.in_primary_constructor = False
@@ -0,0 +1,89 @@
1
+ '''
2
+ Language parser for Java
3
+ '''
4
+
5
+ from .clike import CLikeReader, CLikeStates, CLikeNestingStackStates
6
+
7
+
8
+ class JavaReader(CLikeReader):
9
+ # pylint: disable=R0903
10
+
11
+ ext = ['java']
12
+ language_names = ['java']
13
+
14
+ def __init__(self, context):
15
+ super(JavaReader, self).__init__(context)
16
+ self.parallel_states = [
17
+ JavaStates(context),
18
+ CLikeNestingStackStates(context)]
19
+
20
+
21
+ class JavaStates(CLikeStates): # pylint: disable=R0903
22
+ def __init__(self, context):
23
+ super(JavaStates, self).__init__(context)
24
+ self.class_name = None
25
+ self.is_record = False
26
+ self.in_record_constructor = False
27
+
28
+ def _state_old_c_params(self, token):
29
+ if token == '{':
30
+ self._state_dec_to_imp(token)
31
+
32
+ def try_new_function(self, name):
33
+ # Don't create a function for record compact constructor
34
+ if self.is_record and name == self.class_name:
35
+ self.in_record_constructor = True
36
+ self._state = self._state_record_compact_constructor
37
+ return
38
+ self.context.try_new_function(name)
39
+ self._state = self._state_function
40
+ if self.class_name and self.context.current_function:
41
+ self.context.current_function.name = f"{self.class_name}::{name}"
42
+
43
+ def _state_global(self, token):
44
+ if token == '@':
45
+ self._state = self._state_decorator
46
+ return
47
+ if token in ("class", "record", "enum"):
48
+ self.class_name = None
49
+ self.is_record = token == "record"
50
+ self.in_record_constructor = False
51
+ self._state = self._state_class_declaration
52
+ return
53
+ if not self.in_record_constructor: # Only process as potential function if not in record constructor
54
+ super(JavaStates, self)._state_global(token)
55
+
56
+ def _state_decorator(self, _):
57
+ self._state = self._state_post_decorator
58
+
59
+ def _state_post_decorator(self, token):
60
+ if token == '.':
61
+ self._state = self._state_decorator
62
+ else:
63
+ self._state = self._state_global
64
+ self._state(token)
65
+
66
+ def _state_class_declaration(self, token):
67
+ if token == '{':
68
+ self._state = self._state_global
69
+ elif token == '(': # Record parameters
70
+ self._state = self._state_record_parameters
71
+ elif token[0].isalpha():
72
+ if not self.class_name: # Only set class name if not already set
73
+ self.class_name = token
74
+
75
+ def _state_record_parameters(self, token):
76
+ if token == ')':
77
+ self._state = self._state_class_declaration
78
+
79
+ def _state_record_compact_constructor(self, token):
80
+ if token == '{':
81
+ self._state = self._state_record_constructor_body
82
+ return
83
+ self._state = self._state_global
84
+ self._state(token)
85
+
86
+ def _state_record_constructor_body(self, token):
87
+ if token == '}':
88
+ self.in_record_constructor = False
89
+ self._state = self._state_global
@@ -0,0 +1,19 @@
1
+ '''
2
+ Language parser for JavaScript
3
+ '''
4
+
5
+ from .code_reader import CodeReader
6
+ from .clike import CCppCommentsMixin
7
+ from .js_style_regex_expression import js_style_regex_expression
8
+ from .js_style_language_states import JavaScriptStyleLanguageStates
9
+ from .typescript import TypeScriptReader, JSTokenizer
10
+
11
+
12
+ class JavaScriptReader(TypeScriptReader):
13
+ # pylint: disable=R0903
14
+
15
+ ext = ['js']
16
+ language_names = ['javascript', 'js']
17
+
18
+ def __init__(self, context):
19
+ super(JavaScriptReader, self).__init__(context)
@@ -11,8 +11,18 @@ class JavaScriptStyleLanguageStates(CodeStateMachine): # pylint: disable=R0903
11
11
  self.last_tokens = ''
12
12
  self.function_name = ''
13
13
  self.started_function = None
14
+ self.as_object = False
14
15
 
15
16
  def _state_global(self, token):
17
+ if self.as_object:
18
+ if token == ':':
19
+ self.function_name = self.last_tokens
20
+ return
21
+ elif token == '(':
22
+ self._function(self.last_tokens)
23
+ self.next(self._function, token)
24
+ return
25
+
16
26
  if token in '.':
17
27
  self._state = self._field
18
28
  self.last_tokens += token
@@ -29,11 +39,11 @@ class JavaScriptStyleLanguageStates(CodeStateMachine): # pylint: disable=R0903
29
39
  self.function_name = self.last_tokens
30
40
  elif token == "(":
31
41
  self.sub_state(
32
- JavaScriptStyleLanguageStates(self.context))
42
+ self.__class__(self.context))
33
43
  elif token in '{':
34
44
  if self.started_function:
35
45
  self.sub_state(
36
- JavaScriptStyleLanguageStates(self.context),
46
+ self.__class__(self.context),
37
47
  self._pop_function_from_stack)
38
48
  else:
39
49
  self.read_object()
@@ -46,7 +56,12 @@ class JavaScriptStyleLanguageStates(CodeStateMachine): # pylint: disable=R0903
46
56
  self.last_tokens = token
47
57
 
48
58
  def read_object(self):
49
- self.sub_state(ES6ObjectStates(self.context))
59
+ def callback():
60
+ self.next(self._state_global)
61
+
62
+ object_reader = self.__class__(self.context)
63
+ object_reader.as_object = True
64
+ self.sub_state(object_reader, callback)
50
65
 
51
66
  def statemachine_before_return(self):
52
67
  self._pop_function_from_stack()
@@ -63,16 +78,14 @@ class JavaScriptStyleLanguageStates(CodeStateMachine): # pylint: disable=R0903
63
78
  return
64
79
 
65
80
  self.sub_state(
66
- JavaScriptStyleLanguageStates(self.context),
67
- callback)
81
+ self.__class__(self.context), callback)
68
82
 
69
83
  def _expecting_statement_or_block(self, token):
70
84
  def callback():
71
85
  self.next(self._state_global)
72
86
  if token == "{":
73
87
  self.sub_state(
74
- JavaScriptStyleLanguageStates(self.context),
75
- callback)
88
+ self.__class__(self.context), callback)
76
89
  else:
77
90
  self.next(self._state_global, token)
78
91
 
@@ -116,17 +129,3 @@ class JavaScriptStyleLanguageStates(CodeStateMachine): # pylint: disable=R0903
116
129
  if token != '{':
117
130
  self.started_function = None
118
131
  self.next(self._state_global, token)
119
-
120
-
121
- class ES6ObjectStates(JavaScriptStyleLanguageStates): # pylint: disable=R0903
122
- def __init__(self, context):
123
- super(ES6ObjectStates, self).__init__(context)
124
-
125
- def _state_global(self, token):
126
- if token == ':':
127
- self.function_name = self.last_tokens
128
- elif token == '(':
129
- self._function(self.last_tokens)
130
- self.next(self._function, token)
131
- else:
132
- super(ES6ObjectStates, self)._state_global(token)
@@ -0,0 +1,53 @@
1
+ '''
2
+ generate token with javascript style regular expression.
3
+ '''
4
+
5
+ import re
6
+
7
+
8
+ def js_style_regex_expression(func):
9
+ def generate_tokens_with_regex(source_code, addition='', token_class=None):
10
+ regx_regx = r"\/(\S*?[^\s\\]\/)+?(igm)*"
11
+ regx_pattern = re.compile(regx_regx)
12
+ tokens = list(func(source_code, addition, token_class))
13
+ result = []
14
+ i = 0
15
+ while i < len(tokens):
16
+ token = tokens[i]
17
+ if token == '/':
18
+ # Check if this could be a regex pattern
19
+ is_regex = False
20
+ if i == 0:
21
+ is_regex = True
22
+ elif i > 0:
23
+ prev_token = tokens[i-1].strip()
24
+ if prev_token and prev_token[-1] in '=,({[?:!&|;':
25
+ is_regex = True
26
+
27
+ if is_regex:
28
+ # This is likely a regex pattern start
29
+ regex_tokens = [token]
30
+ i += 1
31
+ while i < len(tokens) and not tokens[i].endswith('/'):
32
+ regex_tokens.append(tokens[i])
33
+ i += 1
34
+ if i < len(tokens):
35
+ regex_tokens.append(tokens[i])
36
+ i += 1
37
+ # Check for regex flags
38
+ if i < len(tokens) and re.match(r'^[igm]+$', tokens[i]):
39
+ regex_tokens.append(tokens[i])
40
+ i += 1
41
+ combined = ''.join(regex_tokens)
42
+ if regx_pattern.match(combined):
43
+ result.append(combined)
44
+ else:
45
+ result.extend(regex_tokens)
46
+ else:
47
+ # This is a division operator
48
+ result.append(token)
49
+ else:
50
+ result.append(token)
51
+ i += 1
52
+ return result
53
+ return generate_tokens_with_regex