lizard 1.18.0__tar.gz → 1.20.0__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 (102) hide show
  1. {lizard-1.18.0 → lizard-1.20.0}/PKG-INFO +30 -20
  2. {lizard-1.18.0 → lizard-1.20.0}/README.rst +28 -18
  3. {lizard-1.18.0 → lizard-1.20.0}/lizard.egg-info/PKG-INFO +30 -20
  4. {lizard-1.18.0 → lizard-1.20.0}/lizard.egg-info/SOURCES.txt +1 -0
  5. {lizard-1.18.0 → lizard-1.20.0}/lizard_ext/__init__.py +0 -1
  6. {lizard-1.18.0 → lizard-1.20.0}/lizard_ext/htmloutput.py +86 -17
  7. {lizard-1.18.0 → lizard-1.20.0}/lizard_ext/lizardcomplextags.py +6 -0
  8. {lizard-1.18.0 → lizard-1.20.0}/lizard_ext/lizardmccabe.py +6 -1
  9. {lizard-1.18.0 → lizard-1.20.0}/lizard_ext/lizardmodified.py +7 -2
  10. {lizard-1.18.0 → lizard-1.20.0}/lizard_ext/lizardnd.py +64 -1
  11. {lizard-1.18.0 → lizard-1.20.0}/lizard_ext/lizardnonstrict.py +2 -1
  12. {lizard-1.18.0 → lizard-1.20.0}/lizard_ext/lizardns.py +31 -8
  13. {lizard-1.18.0 → lizard-1.20.0}/lizard_ext/version.py +1 -1
  14. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/__init__.py +2 -0
  15. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/clike.py +6 -3
  16. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/code_reader.py +27 -3
  17. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/csharp.py +21 -2
  18. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/erlang.py +9 -1
  19. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/fortran.py +5 -6
  20. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/gdscript.py +6 -2
  21. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/kotlin.py +6 -3
  22. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/perl.py +8 -4
  23. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/php.py +6 -2
  24. lizard-1.20.0/lizard_languages/plsql.py +422 -0
  25. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/python.py +6 -4
  26. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/r.py +9 -6
  27. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/rubylike.py +6 -3
  28. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/rust.py +7 -2
  29. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/scala.py +6 -2
  30. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/solidity.py +6 -1
  31. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/st.py +9 -5
  32. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/swift.py +6 -2
  33. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/tnsdl.py +6 -1
  34. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/tsx.py +2 -2
  35. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/ttcn.py +5 -3
  36. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/typescript.py +58 -4
  37. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/zig.py +7 -1
  38. {lizard-1.18.0 → lizard-1.20.0}/test/testNestedStructures.py +55 -0
  39. {lizard-1.18.0 → lizard-1.20.0}/test/testNestingDepth.py +48 -0
  40. lizard-1.20.0/test/testOutputHTML.py +42 -0
  41. lizard-1.18.0/test/testOutputHTML.py +0 -21
  42. {lizard-1.18.0 → lizard-1.20.0}/LICENSE.txt +0 -0
  43. {lizard-1.18.0 → lizard-1.20.0}/lizard.egg-info/dependency_links.txt +0 -0
  44. {lizard-1.18.0 → lizard-1.20.0}/lizard.egg-info/entry_points.txt +0 -0
  45. {lizard-1.18.0 → lizard-1.20.0}/lizard.egg-info/requires.txt +0 -0
  46. {lizard-1.18.0 → lizard-1.20.0}/lizard.egg-info/top_level.txt +0 -0
  47. {lizard-1.18.0 → lizard-1.20.0}/lizard.py +0 -0
  48. {lizard-1.18.0 → lizard-1.20.0}/lizard_ext/auto_open.py +0 -0
  49. {lizard-1.18.0 → lizard-1.20.0}/lizard_ext/checkstyleoutput.py +0 -0
  50. {lizard-1.18.0 → lizard-1.20.0}/lizard_ext/csvoutput.py +0 -0
  51. {lizard-1.18.0 → lizard-1.20.0}/lizard_ext/default_ordered_dict.py +0 -0
  52. {lizard-1.18.0 → lizard-1.20.0}/lizard_ext/extension_base.py +0 -0
  53. {lizard-1.18.0 → lizard-1.20.0}/lizard_ext/keywords.py +0 -0
  54. {lizard-1.18.0 → lizard-1.20.0}/lizard_ext/lizardboolcount.py +0 -0
  55. {lizard-1.18.0 → lizard-1.20.0}/lizard_ext/lizardcpre.py +0 -0
  56. {lizard-1.18.0 → lizard-1.20.0}/lizard_ext/lizarddependencycount.py +0 -0
  57. {lizard-1.18.0 → lizard-1.20.0}/lizard_ext/lizarddumpcomments.py +0 -0
  58. {lizard-1.18.0 → lizard-1.20.0}/lizard_ext/lizardduplicate.py +0 -0
  59. {lizard-1.18.0 → lizard-1.20.0}/lizard_ext/lizardduplicated_param_list.py +0 -0
  60. {lizard-1.18.0 → lizard-1.20.0}/lizard_ext/lizardexitcount.py +0 -0
  61. {lizard-1.18.0 → lizard-1.20.0}/lizard_ext/lizardgotocount.py +0 -0
  62. {lizard-1.18.0 → lizard-1.20.0}/lizard_ext/lizardignoreassert.py +0 -0
  63. {lizard-1.18.0 → lizard-1.20.0}/lizard_ext/lizardio.py +0 -0
  64. {lizard-1.18.0 → lizard-1.20.0}/lizard_ext/lizardoutside.py +0 -0
  65. {lizard-1.18.0 → lizard-1.20.0}/lizard_ext/lizardstatementcount.py +0 -0
  66. {lizard-1.18.0 → lizard-1.20.0}/lizard_ext/lizardwordcount.py +0 -0
  67. {lizard-1.18.0 → lizard-1.20.0}/lizard_ext/xmloutput.py +0 -0
  68. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/go.py +0 -0
  69. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/golike.py +0 -0
  70. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/java.py +0 -0
  71. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/javascript.py +0 -0
  72. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/js_style_regex_expression.py +0 -0
  73. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/lua.py +0 -0
  74. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/objc.py +0 -0
  75. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/ruby.py +0 -0
  76. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/script_language.py +0 -0
  77. {lizard-1.18.0 → lizard-1.20.0}/lizard_languages/vue.py +0 -0
  78. {lizard-1.18.0 → lizard-1.20.0}/setup.cfg +0 -0
  79. {lizard-1.18.0 → lizard-1.20.0}/setup.py +0 -0
  80. {lizard-1.18.0 → lizard-1.20.0}/test/testApplication.py +0 -0
  81. {lizard-1.18.0 → lizard-1.20.0}/test/testAssertionExtension.py +0 -0
  82. {lizard-1.18.0 → lizard-1.20.0}/test/testBasicFunctionInfo.py +0 -0
  83. {lizard-1.18.0 → lizard-1.20.0}/test/testCOutsideComplexity.py +0 -0
  84. {lizard-1.18.0 → lizard-1.20.0}/test/testCPreprocessorExtension.py +0 -0
  85. {lizard-1.18.0 → lizard-1.20.0}/test/testCommentOptions.py +0 -0
  86. {lizard-1.18.0 → lizard-1.20.0}/test/testCyclomaticComplexity.py +0 -0
  87. {lizard-1.18.0 → lizard-1.20.0}/test/testExtension.py +0 -0
  88. {lizard-1.18.0 → lizard-1.20.0}/test/testFilesFilter.py +0 -0
  89. {lizard-1.18.0 → lizard-1.20.0}/test/testFunctionDependencyCount.py +0 -0
  90. {lizard-1.18.0 → lizard-1.20.0}/test/testFunctionExitCount.py +0 -0
  91. {lizard-1.18.0 → lizard-1.20.0}/test/testFunctionGotoCount.py +0 -0
  92. {lizard-1.18.0 → lizard-1.20.0}/test/testFunctionStatementCount.py +0 -0
  93. {lizard-1.18.0 → lizard-1.20.0}/test/testHelpers.py +0 -0
  94. {lizard-1.18.0 → lizard-1.20.0}/test/testLanguages.py +0 -0
  95. {lizard-1.18.0 → lizard-1.20.0}/test/testMcCabe.py +0 -0
  96. {lizard-1.18.0 → lizard-1.20.0}/test/testOutput.py +0 -0
  97. {lizard-1.18.0 → lizard-1.20.0}/test/testOutputCSV.py +0 -0
  98. {lizard-1.18.0 → lizard-1.20.0}/test/testOutputFile.py +0 -0
  99. {lizard-1.18.0 → lizard-1.20.0}/test/testTokenizer.py +0 -0
  100. {lizard-1.18.0 → lizard-1.20.0}/test/test_analyzer.py +0 -0
  101. {lizard-1.18.0 → lizard-1.20.0}/test/test_auto_open.py +0 -0
  102. {lizard-1.18.0 → lizard-1.20.0}/test/test_options.py +0 -0
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lizard
3
- Version: 1.18.0
3
+ Version: 1.20.0
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
- Download-URL: https://pypi.python.org/lizard/
7
6
  Author: Terry Yin
8
7
  Author-email: terry@odd-e.com
9
8
  License: MIT
9
+ Download-URL: https://pypi.python.org/lizard/
10
10
  Project-URL: Source, https://github.com/terryyin/lizard
11
11
  Platform: any
12
12
  Classifier: Development Status :: 5 - Production/Stable
@@ -48,31 +48,32 @@ code analysis.
48
48
 
49
49
  A list of supported languages:
50
50
 
51
+ - C# (C Sharp)
51
52
  - C/C++ (works with C++14)
53
+ - Erlang
54
+ - Fortran
55
+ - GDScript
56
+ - Golang
52
57
  - Java
53
- - C# (C Sharp)
54
58
  - JavaScript (With ES6 and JSX)
55
- - TypeScript (With TSX)
56
- - VueJS
59
+ - Kotlin
60
+ - Lua
57
61
  - Objective-C
58
- - Swift
62
+ - Perl
63
+ - PHP
64
+ - PL/SQL
59
65
  - Python
66
+ - R
60
67
  - Ruby
61
- - TTCN-3
62
- - PHP
63
- - Scala
64
- - GDScript
65
- - Golang
66
- - Lua
67
68
  - Rust
68
- - Fortran
69
- - Kotlin
69
+ - Scala
70
70
  - Solidity
71
- - Erlang
72
- - Zig
73
- - Perl
74
71
  - Structured Text (St)
75
- - R
72
+ - Swift
73
+ - TTCN-3
74
+ - TypeScript (With TSX)
75
+ - VueJS
76
+ - Zig
76
77
 
77
78
  By default lizard will search for any source code that it knows and mix
78
79
  all the results together. This might not be what you want. You can use
@@ -160,7 +161,7 @@ Options
160
161
  search for all languages it knows. `lizard -l cpp -l java`searches for
161
162
  C++ and Java code. The available languages are: cpp, java, csharp,
162
163
  javascript, python, objectivec, ttcn, ruby, php, swift, scala, GDScript,
163
- go, lua, rust, typescript
164
+ go, lua, rust, typescript, plsql
164
165
  -V, --verbose Output in verbose mode (long function name)
165
166
  -C CCN, --CCN CCN Threshold for cyclomatic complexity number warning. The default value is
166
167
  15. Functions with CCN bigger than it will generate warning
@@ -195,7 +196,7 @@ Options
195
196
  -X, --xml Generate XML in cppncss style instead of the tabular output. Useful to
196
197
  generate report in Jenkins server
197
198
  --csv Generate CSV output as a transform of the default output
198
- -H, --html Output HTML report
199
+ -H, --html Output HTML report with interactive DataTables (sortable, searchable, filterable)
199
200
  --checkstyle Generate Checkstyle XML output for integration with Jenkins and other tools
200
201
  -m, --modified Calculate modified cyclomatic complexity number , which count a
201
202
  switch/case with multiple cases as one CCN.
@@ -413,5 +414,14 @@ Lizard is also used as a plugin for fastlane to help check code complexity and s
413
414
  - `European research project FASTEN (Fine-grained Analysis of SofTware Ecosystems as Networks, <http://fasten-project.eu/)>`_
414
415
  - `for a quality analyzer <https://github.com/fasten-project/quality-analyzer>`_
415
416
 
417
+ How To Contribute
418
+ -----------------
419
+
420
+ Contributions are welcome. Please refer to the rules and development workflow in:
421
+
422
+ - https://github.com/terryyin/lizard/tree/master/.cursor/rules
423
+
424
+ These guidelines are usable by both AI assistants and human contributors — what works for AI works for "I" as well — to keep changes cohesive, simple, and well-tested.
425
+
416
426
 
417
427
 
@@ -17,31 +17,32 @@ code analysis.
17
17
 
18
18
  A list of supported languages:
19
19
 
20
+ - C# (C Sharp)
20
21
  - C/C++ (works with C++14)
22
+ - Erlang
23
+ - Fortran
24
+ - GDScript
25
+ - Golang
21
26
  - Java
22
- - C# (C Sharp)
23
27
  - JavaScript (With ES6 and JSX)
24
- - TypeScript (With TSX)
25
- - VueJS
28
+ - Kotlin
29
+ - Lua
26
30
  - Objective-C
27
- - Swift
31
+ - Perl
32
+ - PHP
33
+ - PL/SQL
28
34
  - Python
35
+ - R
29
36
  - Ruby
30
- - TTCN-3
31
- - PHP
32
- - Scala
33
- - GDScript
34
- - Golang
35
- - Lua
36
37
  - Rust
37
- - Fortran
38
- - Kotlin
38
+ - Scala
39
39
  - Solidity
40
- - Erlang
41
- - Zig
42
- - Perl
43
40
  - Structured Text (St)
44
- - R
41
+ - Swift
42
+ - TTCN-3
43
+ - TypeScript (With TSX)
44
+ - VueJS
45
+ - Zig
45
46
 
46
47
  By default lizard will search for any source code that it knows and mix
47
48
  all the results together. This might not be what you want. You can use
@@ -129,7 +130,7 @@ Options
129
130
  search for all languages it knows. `lizard -l cpp -l java`searches for
130
131
  C++ and Java code. The available languages are: cpp, java, csharp,
131
132
  javascript, python, objectivec, ttcn, ruby, php, swift, scala, GDScript,
132
- go, lua, rust, typescript
133
+ go, lua, rust, typescript, plsql
133
134
  -V, --verbose Output in verbose mode (long function name)
134
135
  -C CCN, --CCN CCN Threshold for cyclomatic complexity number warning. The default value is
135
136
  15. Functions with CCN bigger than it will generate warning
@@ -164,7 +165,7 @@ Options
164
165
  -X, --xml Generate XML in cppncss style instead of the tabular output. Useful to
165
166
  generate report in Jenkins server
166
167
  --csv Generate CSV output as a transform of the default output
167
- -H, --html Output HTML report
168
+ -H, --html Output HTML report with interactive DataTables (sortable, searchable, filterable)
168
169
  --checkstyle Generate Checkstyle XML output for integration with Jenkins and other tools
169
170
  -m, --modified Calculate modified cyclomatic complexity number , which count a
170
171
  switch/case with multiple cases as one CCN.
@@ -382,3 +383,12 @@ Lizard is also used as a plugin for fastlane to help check code complexity and s
382
383
  - `European research project FASTEN (Fine-grained Analysis of SofTware Ecosystems as Networks, <http://fasten-project.eu/)>`_
383
384
  - `for a quality analyzer <https://github.com/fasten-project/quality-analyzer>`_
384
385
 
386
+ How To Contribute
387
+ -----------------
388
+
389
+ Contributions are welcome. Please refer to the rules and development workflow in:
390
+
391
+ - https://github.com/terryyin/lizard/tree/master/.cursor/rules
392
+
393
+ These guidelines are usable by both AI assistants and human contributors — what works for AI works for "I" as well — to keep changes cohesive, simple, and well-tested.
394
+
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lizard
3
- Version: 1.18.0
3
+ Version: 1.20.0
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
- Download-URL: https://pypi.python.org/lizard/
7
6
  Author: Terry Yin
8
7
  Author-email: terry@odd-e.com
9
8
  License: MIT
9
+ Download-URL: https://pypi.python.org/lizard/
10
10
  Project-URL: Source, https://github.com/terryyin/lizard
11
11
  Platform: any
12
12
  Classifier: Development Status :: 5 - Production/Stable
@@ -48,31 +48,32 @@ code analysis.
48
48
 
49
49
  A list of supported languages:
50
50
 
51
+ - C# (C Sharp)
51
52
  - C/C++ (works with C++14)
53
+ - Erlang
54
+ - Fortran
55
+ - GDScript
56
+ - Golang
52
57
  - Java
53
- - C# (C Sharp)
54
58
  - JavaScript (With ES6 and JSX)
55
- - TypeScript (With TSX)
56
- - VueJS
59
+ - Kotlin
60
+ - Lua
57
61
  - Objective-C
58
- - Swift
62
+ - Perl
63
+ - PHP
64
+ - PL/SQL
59
65
  - Python
66
+ - R
60
67
  - Ruby
61
- - TTCN-3
62
- - PHP
63
- - Scala
64
- - GDScript
65
- - Golang
66
- - Lua
67
68
  - Rust
68
- - Fortran
69
- - Kotlin
69
+ - Scala
70
70
  - Solidity
71
- - Erlang
72
- - Zig
73
- - Perl
74
71
  - Structured Text (St)
75
- - R
72
+ - Swift
73
+ - TTCN-3
74
+ - TypeScript (With TSX)
75
+ - VueJS
76
+ - Zig
76
77
 
77
78
  By default lizard will search for any source code that it knows and mix
78
79
  all the results together. This might not be what you want. You can use
@@ -160,7 +161,7 @@ Options
160
161
  search for all languages it knows. `lizard -l cpp -l java`searches for
161
162
  C++ and Java code. The available languages are: cpp, java, csharp,
162
163
  javascript, python, objectivec, ttcn, ruby, php, swift, scala, GDScript,
163
- go, lua, rust, typescript
164
+ go, lua, rust, typescript, plsql
164
165
  -V, --verbose Output in verbose mode (long function name)
165
166
  -C CCN, --CCN CCN Threshold for cyclomatic complexity number warning. The default value is
166
167
  15. Functions with CCN bigger than it will generate warning
@@ -195,7 +196,7 @@ Options
195
196
  -X, --xml Generate XML in cppncss style instead of the tabular output. Useful to
196
197
  generate report in Jenkins server
197
198
  --csv Generate CSV output as a transform of the default output
198
- -H, --html Output HTML report
199
+ -H, --html Output HTML report with interactive DataTables (sortable, searchable, filterable)
199
200
  --checkstyle Generate Checkstyle XML output for integration with Jenkins and other tools
200
201
  -m, --modified Calculate modified cyclomatic complexity number , which count a
201
202
  switch/case with multiple cases as one CCN.
@@ -413,5 +414,14 @@ Lizard is also used as a plugin for fastlane to help check code complexity and s
413
414
  - `European research project FASTEN (Fine-grained Analysis of SofTware Ecosystems as Networks, <http://fasten-project.eu/)>`_
414
415
  - `for a quality analyzer <https://github.com/fasten-project/quality-analyzer>`_
415
416
 
417
+ How To Contribute
418
+ -----------------
419
+
420
+ Contributions are welcome. Please refer to the rules and development workflow in:
421
+
422
+ - https://github.com/terryyin/lizard/tree/master/.cursor/rules
423
+
424
+ These guidelines are usable by both AI assistants and human contributors — what works for AI works for "I" as well — to keep changes cohesive, simple, and well-tested.
425
+
416
426
 
417
427
 
@@ -55,6 +55,7 @@ lizard_languages/lua.py
55
55
  lizard_languages/objc.py
56
56
  lizard_languages/perl.py
57
57
  lizard_languages/php.py
58
+ lizard_languages/plsql.py
58
59
  lizard_languages/python.py
59
60
  lizard_languages/r.py
60
61
  lizard_languages/ruby.py
@@ -21,7 +21,6 @@ def print_csv(results, options, _, total_factory):
21
21
 
22
22
  def print_checkstyle(results, options, _, total_factory, file=None):
23
23
  import sys
24
- print("DEBUG: print_checkstyle called", file=sys.stderr)
25
24
  output = checkstyle_output(total_factory(list(results)), options.verbose)
26
25
  if file is None:
27
26
  file = sys.stdout
@@ -48,6 +48,12 @@ TEMPLATE = '''<!DOCTYPE HTML PUBLIC
48
48
  <head>
49
49
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
50
50
  <title>Code complexity report</title>
51
+ <!-- DataTables CSS -->
52
+ <link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css">
53
+ <!-- jQuery -->
54
+ <script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
55
+ <!-- DataTables JS -->
56
+ <script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js"></script>
51
57
  <style>
52
58
  h2
53
59
  {
@@ -88,6 +94,42 @@ TEMPLATE = '''<!DOCTYPE HTML PUBLIC
88
94
  font-family: sans-serif;
89
95
  white-space: nowrap;
90
96
  }
97
+ td.file-header
98
+ {
99
+ background-color: LightBlue;
100
+ font-weight: bold;
101
+ }
102
+ td.function-name
103
+ {
104
+ background-color: LightSteelBlue;
105
+ }
106
+ /* DataTables wrapper styling */
107
+ .dataTables_wrapper {
108
+ margin: 0 auto;
109
+ width: 95%;
110
+ }
111
+ /* Fallback styling if DataTables CSS doesn't load */
112
+ table#complexityTable {
113
+ border-collapse: collapse;
114
+ width: 95%;
115
+ margin: 0 auto;
116
+ }
117
+ table#complexityTable th {
118
+ background-color: #4CAF50;
119
+ color: white;
120
+ padding: 10px;
121
+ text-align: left;
122
+ border: 1px solid #ddd;
123
+ }
124
+ table#complexityTable td {
125
+ border: 1px solid #ddd;
126
+ }
127
+ table#complexityTable tr:nth-child(even) {
128
+ background-color: #f2f2f2;
129
+ }
130
+ table#complexityTable tr:hover {
131
+ background-color: #ddd;
132
+ }
91
133
  </style>
92
134
  </head>
93
135
  <body>
@@ -95,26 +137,29 @@ TEMPLATE = '''<!DOCTYPE HTML PUBLIC
95
137
 
96
138
  <center>
97
139
 
98
- <table>
140
+ <table id="complexityTable" class="display" style="width:100%">
141
+ <thead>
142
+ <tr>
143
+ <th>File</th>
144
+ <th>Function name</th>
145
+ <th>Cyclomatic complexity ({{ thresholds["cyclomatic_complexity"] }})</th>
146
+ <th>LOC ({{ thresholds["nloc"] }})</th>
147
+ <th>
148
+ {% if thresholds["token_count"] %}
149
+ Token count ({{ thresholds["token_count"] }})
150
+ {% else %}
151
+ Token count
152
+ {% endif %}
153
+ </th>
154
+ <th>Parameter count ({{ thresholds["parameter_count"] }})</th>
155
+ </tr>
156
+ </thead>
157
+ <tbody>
99
158
  {% for file in files %}
100
- <tr><td colspan="7" style="background-color:LightBlue;">
101
- Source file: <b>{{ file.filename }}</b></td></tr>
102
- {% if file.functions|length > 0 %}
103
- <tr><th>Function name</th><th></th><th>
104
- Cyclomatic complexity
105
- ({{ thresholds["cyclomatic_complexity"] }})
106
- </th><th>LOC ({{ thresholds["nloc"] }})</th><th>
107
- {% if thresholds["token_count"] %}
108
- Token count ({{ thresholds["token_count"] }})
109
- {% else %}
110
- Token count
111
- {% endif %}
112
- </th><th>Parameter count ({{ thresholds["parameter_count"] }})</th></tr>
113
- {% endif %}
114
159
  {% for func in file.functions %}
115
160
  <tr>
116
- <td style="background-color:LightSteelBlue">{{ func.name }}</td>
117
- <td></td>
161
+ <td>{{ file.filename }}</td>
162
+ <td class="function-name">{{ func.name }}</td>
118
163
  {% if func.cyclomatic_complexity > thresholds["cyclomatic_complexity"] %}
119
164
  <td class="greater-value">{{ func.cyclomatic_complexity }}</td>
120
165
  {% else %}
@@ -145,6 +190,7 @@ Cyclomatic complexity
145
190
  </tr>
146
191
  {% endfor %}
147
192
  {% endfor %}
193
+ </tbody>
148
194
  </table>
149
195
  <center>
150
196
 
@@ -154,6 +200,29 @@ Cyclomatic complexity
154
200
  <a href="http://www.lizard.ws/">Lizard</a> on {{ date }}
155
201
  </td></tr>
156
202
  </table>
203
+
204
+ <script>
205
+ // Gracefully degrade if CDN is unavailable
206
+ if (typeof jQuery !== 'undefined' && typeof jQuery.fn.dataTable !== 'undefined') {
207
+ $(document).ready(function() {
208
+ try {
209
+ $('#complexityTable').DataTable({
210
+ "pageLength": 25,
211
+ "order": [[2, "desc"]], // Sort by cyclomatic complexity descending by default
212
+ "columnDefs": [
213
+ { "type": "num", "targets": [2, 3, 4, 5] } // Ensure numeric sorting for metric columns
214
+ ]
215
+ });
216
+ } catch (e) {
217
+ console.warn('DataTables initialization failed. Displaying static table.', e);
218
+ }
219
+ });
220
+ } else {
221
+ // Fallback: Table will display as static HTML
222
+ console.info('DataTables not available. Displaying static HTML table.');
223
+ }
224
+ </script>
225
+
157
226
  </body>
158
227
  </html>
159
228
 
@@ -5,10 +5,16 @@ that adding the complexity and the line numbers of the keywords appear.
5
5
 
6
6
 
7
7
  class LizardExtension(object): # pylint: disable=R0903
8
+ """
9
+ Complex tags extension: records all complexity-adding keywords and their line numbers.
10
+ Uses reader.conditions (combined set of all condition types) to track all
11
+ complexity contributors: control flow, logical operators, case labels, and ternary.
12
+ """
8
13
 
9
14
  # pylint: disable=W0221
10
15
  def __call__(self, tokens, reader):
11
16
  context = reader.context
17
+ # Use combined conditions set - intentionally includes all types
12
18
  conditions = reader.conditions
13
19
  for token in tokens:
14
20
  yield token
@@ -14,9 +14,14 @@ from .extension_base import ExtensionBase
14
14
 
15
15
 
16
16
  class LizardExtension(ExtensionBase): # pylint: disable=R0903
17
+ """
18
+ McCabe extension: only counts the first 'case' in a switch statement.
19
+ Consecutive cases without code between them don't add to complexity.
20
+ Works by detecting case tokens (conceptually from reader.case_keywords).
21
+ """
17
22
 
18
23
  def _state_global(self, token):
19
- if token == "case":
24
+ if token == "case": # Detect case keywords
20
25
  self._state = self._in_case
21
26
 
22
27
  def _in_case(self, token):
@@ -6,14 +6,19 @@ where the whole switch/case will be counted as 1.
6
6
 
7
7
 
8
8
  class LizardExtension(object): # pylint: disable=R0903
9
+ """
10
+ Modified CCN extension: counts entire switch/case as 1 complexity.
11
+ Adds +1 for 'switch', subtracts -1 for each 'case'.
12
+ Works with switch/case keywords (conceptually from reader.case_keywords).
13
+ """
9
14
 
10
15
  def __call__(self, tokens, reader):
11
16
  for token in tokens:
12
- if token == 'switch':
17
+ if token == 'switch': # Add complexity for switch statement
13
18
  reader.context.add_condition()
14
19
  if hasattr(reader.context, "add_nd_condition"):
15
20
  reader.context.add_nd_condition()
16
- elif token == 'case':
21
+ elif token == 'case': # Subtract complexity for each case
17
22
  reader.context.add_condition(-1)
18
23
  if hasattr(reader.context, "add_nd_condition"):
19
24
  reader.context.add_nd_condition(-1)
@@ -45,11 +45,43 @@ class LizardExtension(object): # pylint: disable=R0903
45
45
  else:
46
46
  indent_indicator = ';'
47
47
  for token in tokens:
48
- if token in loops:
48
+ # Handle opening parenthesis - start of condition
49
+ if token == '(':
50
+ reader.context.set_in_condition(True)
51
+ reader.context.increment_condition_depth()
52
+ reader.context.set_logical_operator_added(False) # Reset for new condition
53
+ # Handle closing parenthesis - end of condition
54
+ elif token == ')':
55
+ reader.context.decrement_condition_depth()
56
+ if reader.context.get_condition_depth() == 0:
57
+ reader.context.set_in_condition(False)
58
+ reader.context.set_logical_operator_added(False)
59
+
60
+ # Handle logical operators && and || within conditions
61
+ elif token in ('&&', '||'):
62
+ if reader.context.get_in_condition():
63
+ # Only add nesting depth for the first logical operator in a condition
64
+ # Subsequent && or || operators in the same condition don't add depth
65
+ if not reader.context.get_logical_operator_added():
66
+ l_depth = reader.context.add_nd_condition()
67
+ if not reader.context.get_loop_status():
68
+ reader.context.add_hidden_bracket_condition()
69
+ reader.context.loop_bracket_status()
70
+ reader.context.set_logical_operator_added(True)
71
+ else:
72
+ # Not in a condition, treat as regular nesting
73
+ l_depth = reader.context.add_nd_condition()
74
+ if not reader.context.get_loop_status():
75
+ reader.context.add_hidden_bracket_condition()
76
+ reader.context.loop_bracket_status()
77
+
78
+ # Handle other loop keywords (if, for, while, etc.)
79
+ elif token in loops and token not in ('&&', '||'):
49
80
  l_depth = reader.context.add_nd_condition()
50
81
  if not reader.context.get_loop_status():
51
82
  reader.context.add_hidden_bracket_condition()
52
83
  reader.context.loop_bracket_status()
84
+
53
85
  if token == loop_indicator:
54
86
  reader.context.loop_bracket_status()
55
87
  if token == bracket:
@@ -82,6 +114,7 @@ class NDFileInfoAddition(FileInfoBuilder):
82
114
  self.current_function.nesting_depth = 0
83
115
  self.current_function.hidden_bracket = 0
84
116
  self.current_function.bracket_loop = False
117
+ self.reset_condition_tracking()
85
118
 
86
119
  def add_hidden_bracket_condition(self, inc=1):
87
120
  self.current_function.hidden_bracket += inc
@@ -96,6 +129,33 @@ class NDFileInfoAddition(FileInfoBuilder):
96
129
  def get_loop_status(self):
97
130
  return self.current_function.bracket_loop
98
131
 
132
+ def set_in_condition(self, in_condition):
133
+ self.current_function.in_condition = in_condition
134
+
135
+ def get_in_condition(self):
136
+ return self.current_function.in_condition
137
+
138
+ def increment_condition_depth(self):
139
+ self.current_function.condition_depth += 1
140
+
141
+ def decrement_condition_depth(self):
142
+ if self.current_function.condition_depth > 0:
143
+ self.current_function.condition_depth -= 1
144
+
145
+ def get_condition_depth(self):
146
+ return self.current_function.condition_depth
147
+
148
+ def reset_condition_tracking(self):
149
+ self.current_function.in_condition = False
150
+ self.current_function.condition_depth = 0
151
+ self.current_function.logical_operator_added = False
152
+
153
+ def set_logical_operator_added(self, added):
154
+ self.current_function.logical_operator_added = added
155
+
156
+ def get_logical_operator_added(self):
157
+ return self.current_function.logical_operator_added
158
+
99
159
 
100
160
  def get_method(cls, name):
101
161
  """ python3 doesn't need the __func__ to get the func of the
@@ -127,6 +187,9 @@ def _init_nesting_depth_data(self, *_):
127
187
  self.max_nesting_depth = 0
128
188
  self.hidden_bracket = 0
129
189
  self.bracket_loop = False
190
+ self.in_condition = False # Track if we're inside a condition
191
+ self.condition_depth = 0 # Track nesting depth within conditions
192
+ self.logical_operator_added = False # Track if we've added nesting for logical operators in current condition
130
193
 
131
194
 
132
195
  patch(NDFileInfoAddition, FileInfoBuilder)
@@ -9,5 +9,6 @@ class LizardExtension(object): # pylint: disable=R0903
9
9
 
10
10
  # pylint: disable=W0221
11
11
  def __call__(self, tokens, reader):
12
- reader.conditions -= set(['&&', '||', 'and', 'or'])
12
+ # Remove logical operators from conditions (non-strict mode)
13
+ reader.conditions -= reader.logical_operators
13
14
  return tokens
@@ -67,10 +67,35 @@ class LizardExtension(ExtensionBase): # pylint: disable=R0903
67
67
 
68
68
  def __init__(self):
69
69
  super(LizardExtension, self).__init__(None)
70
- self.structure_piles = [0]
70
+ self.structure_piles = [0] # Invariant: must always have at least one element
71
71
 
72
- def pile_up_within_block(self):
72
+ def _push_scope(self):
73
+ """Push a new scope level. Safe to call anytime."""
74
+ self.structure_piles.append(0)
75
+
76
+ def _pop_scope(self):
77
+ """Pop a scope level. Maintains invariant of at least one element."""
78
+ if len(self.structure_piles) > 1:
79
+ self.structure_piles.pop()
80
+
81
+ def _increment_current_scope(self):
82
+ """Increment structure count in current scope. Safe even if piles corrupted."""
83
+ if not self.structure_piles:
84
+ self.structure_piles = [0] # Restore invariant
73
85
  self.structure_piles[-1] += 1
86
+
87
+ def _reset_or_decrement_current_scope(self, decrement=False):
88
+ """Reset or decrement current scope counter. Safe even if piles corrupted."""
89
+ if not self.structure_piles:
90
+ self.structure_piles = [0] # Restore invariant
91
+ return
92
+ if decrement:
93
+ self.structure_piles[-1] -= 1
94
+ else:
95
+ self.structure_piles[-1] = 0
96
+
97
+ def pile_up_within_block(self):
98
+ self._increment_current_scope()
74
99
  cur_level = sum(self.structure_piles)
75
100
  # Is there a path around _state_global?
76
101
  if not hasattr(self.context.current_function, "max_nested_structures"):
@@ -83,10 +108,10 @@ class LizardExtension(ExtensionBase): # pylint: disable=R0903
83
108
  if not hasattr(self.context.current_function, "max_nested_structures"):
84
109
  self.context.current_function.max_nested_structures = 0
85
110
  if token == '{':
86
- self.structure_piles.append(0)
111
+ self._push_scope()
87
112
  elif token in ';}':
88
113
  if token == '}':
89
- self.structure_piles.pop()
114
+ self._pop_scope()
90
115
  self._state = self._block_ending
91
116
  elif token in self.structures:
92
117
  self._state = self._in_structure_head
@@ -98,10 +123,8 @@ class LizardExtension(ExtensionBase): # pylint: disable=R0903
98
123
  self._state(token)
99
124
 
100
125
  def _block_ending(self, token):
101
- if token in self.matching_structures:
102
- self.structure_piles[-1] -= 1
103
- else:
104
- self.structure_piles[-1] = 0
126
+ decrement = token in self.matching_structures
127
+ self._reset_or_decrement_current_scope(decrement=decrement)
105
128
  self._state = self._state_global
106
129
  self._state(token)
107
130
 
@@ -3,4 +3,4 @@
3
3
  #
4
4
  # pylint: disable=missing-docstring,invalid-name
5
5
 
6
- version = "1.18.0"
6
+ version = "1.20.0"
@@ -26,6 +26,7 @@ from .vue import VueReader
26
26
  from .perl import PerlReader
27
27
  from .st import StReader
28
28
  from .r import RReader
29
+ from .plsql import PLSQLReader
29
30
 
30
31
 
31
32
  def languages():
@@ -56,6 +57,7 @@ def languages():
56
57
  PerlReader,
57
58
  StReader,
58
59
  RReader,
60
+ PLSQLReader,
59
61
  ]
60
62
 
61
63