lizard 1.17.31__py2.py3-none-any.whl → 1.19.0__py2.py3-none-any.whl
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.
- {lizard-1.17.31.dist-info → lizard-1.19.0.dist-info}/METADATA +31 -17
- {lizard-1.17.31.dist-info → lizard-1.19.0.dist-info}/RECORD +21 -20
- {lizard-1.17.31.dist-info → lizard-1.19.0.dist-info}/entry_points.txt +1 -0
- lizard.py +7 -7
- lizard_ext/checkstyleoutput.py +4 -2
- lizard_ext/htmloutput.py +86 -17
- lizard_ext/lizardnd.py +64 -1
- lizard_ext/version.py +1 -1
- lizard_languages/__init__.py +6 -2
- lizard_languages/clike.py +61 -2
- lizard_languages/code_reader.py +1 -1
- lizard_languages/plsql.py +419 -0
- lizard_languages/python.py +36 -0
- lizard_languages/r.py +290 -0
- lizard_languages/rust.py +5 -0
- lizard_languages/st.py +139 -0
- lizard_languages/tsx.py +445 -11
- lizard_languages/typescript.py +264 -14
- lizard_languages/js_style_language_states.py +0 -185
- lizard_languages/jsx.py +0 -337
- {lizard-1.17.31.dist-info → lizard-1.19.0.dist-info}/LICENSE.txt +0 -0
- {lizard-1.17.31.dist-info → lizard-1.19.0.dist-info}/WHEEL +0 -0
- {lizard-1.17.31.dist-info → lizard-1.19.0.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: lizard
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.19.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
6
|
Download-URL: https://pypi.python.org/lizard/
|
|
@@ -50,29 +50,32 @@ code analysis.
|
|
|
50
50
|
|
|
51
51
|
A list of supported languages:
|
|
52
52
|
|
|
53
|
+
- C# (C Sharp)
|
|
53
54
|
- C/C++ (works with C++14)
|
|
55
|
+
- Erlang
|
|
56
|
+
- Fortran
|
|
57
|
+
- GDScript
|
|
58
|
+
- Golang
|
|
54
59
|
- Java
|
|
55
|
-
- C# (C Sharp)
|
|
56
60
|
- JavaScript (With ES6 and JSX)
|
|
57
|
-
-
|
|
58
|
-
-
|
|
61
|
+
- Kotlin
|
|
62
|
+
- Lua
|
|
59
63
|
- Objective-C
|
|
60
|
-
-
|
|
64
|
+
- Perl
|
|
65
|
+
- PHP
|
|
66
|
+
- PL/SQL
|
|
61
67
|
- Python
|
|
68
|
+
- R
|
|
62
69
|
- Ruby
|
|
63
|
-
- TTCN-3
|
|
64
|
-
- PHP
|
|
65
|
-
- Scala
|
|
66
|
-
- GDScript
|
|
67
|
-
- Golang
|
|
68
|
-
- Lua
|
|
69
70
|
- Rust
|
|
70
|
-
-
|
|
71
|
-
- Kotlin
|
|
71
|
+
- Scala
|
|
72
72
|
- Solidity
|
|
73
|
-
-
|
|
73
|
+
- Structured Text (St)
|
|
74
|
+
- Swift
|
|
75
|
+
- TTCN-3
|
|
76
|
+
- TypeScript (With TSX)
|
|
77
|
+
- VueJS
|
|
74
78
|
- Zig
|
|
75
|
-
- Perl
|
|
76
79
|
|
|
77
80
|
By default lizard will search for any source code that it knows and mix
|
|
78
81
|
all the results together. This might not be what you want. You can use
|
|
@@ -160,7 +163,7 @@ Options
|
|
|
160
163
|
search for all languages it knows. `lizard -l cpp -l java`searches for
|
|
161
164
|
C++ and Java code. The available languages are: cpp, java, csharp,
|
|
162
165
|
javascript, python, objectivec, ttcn, ruby, php, swift, scala, GDScript,
|
|
163
|
-
go, lua, rust, typescript
|
|
166
|
+
go, lua, rust, typescript, plsql
|
|
164
167
|
-V, --verbose Output in verbose mode (long function name)
|
|
165
168
|
-C CCN, --CCN CCN Threshold for cyclomatic complexity number warning. The default value is
|
|
166
169
|
15. Functions with CCN bigger than it will generate warning
|
|
@@ -195,7 +198,7 @@ Options
|
|
|
195
198
|
-X, --xml Generate XML in cppncss style instead of the tabular output. Useful to
|
|
196
199
|
generate report in Jenkins server
|
|
197
200
|
--csv Generate CSV output as a transform of the default output
|
|
198
|
-
-H, --html Output HTML report
|
|
201
|
+
-H, --html Output HTML report with interactive DataTables (sortable, searchable, filterable)
|
|
199
202
|
--checkstyle Generate Checkstyle XML output for integration with Jenkins and other tools
|
|
200
203
|
-m, --modified Calculate modified cyclomatic complexity number , which count a
|
|
201
204
|
switch/case with multiple cases as one CCN.
|
|
@@ -413,3 +416,14 @@ Lizard is also used as a plugin for fastlane to help check code complexity and s
|
|
|
413
416
|
- `European research project FASTEN (Fine-grained Analysis of SofTware Ecosystems as Networks, <http://fasten-project.eu/)>`_
|
|
414
417
|
- `for a quality analyzer <https://github.com/fasten-project/quality-analyzer>`_
|
|
415
418
|
|
|
419
|
+
How To Contribute
|
|
420
|
+
-----------------
|
|
421
|
+
|
|
422
|
+
Contributions are welcome. Please refer to the rules and development workflow in:
|
|
423
|
+
|
|
424
|
+
- https://github.com/terryyin/lizard/tree/master/.cursor/rules
|
|
425
|
+
|
|
426
|
+
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.
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
lizard.py,sha256=
|
|
1
|
+
lizard.py,sha256=B0g5lEp5me31bQpjfMKVayF0iUfH0PalVecOKeUX3-A,41365
|
|
2
2
|
lizard_ext/__init__.py,sha256=AkZYVqCgd7XX1hMwLMyh_ABm9geIHmobEch-thYXZz8,932
|
|
3
3
|
lizard_ext/auto_open.py,sha256=byD_RbeVhvSUhR2bJMRitvA3zcKEapFwv0-XaDJ6GFo,1096
|
|
4
|
-
lizard_ext/checkstyleoutput.py,sha256=
|
|
4
|
+
lizard_ext/checkstyleoutput.py,sha256=UzDHg837ErEZepXkR8I8YCoz2r1lkmzGctMA7dpyB-M,1245
|
|
5
5
|
lizard_ext/csvoutput.py,sha256=43fhmo8kB85qcdujCwySGNuTC4FkKUPLqIApPeljPnA,2663
|
|
6
6
|
lizard_ext/default_ordered_dict.py,sha256=YbVz6nPlQ6DjWc_EOFBz6AJN2XLo9dpnUdeyejQvUDE,831
|
|
7
7
|
lizard_ext/extension_base.py,sha256=rnjUL2mqSGToUVYydju7fa8ZwynLPY8S1F17gIJP55I,346
|
|
8
|
-
lizard_ext/htmloutput.py,sha256=
|
|
8
|
+
lizard_ext/htmloutput.py,sha256=G7MdLD7AwuR0LLCAkEpyHx4N_ssCcFQdXd7Xg5jZWX0,6537
|
|
9
9
|
lizard_ext/keywords.py,sha256=VxsxoATtKV-8egMKd7I8sd2qbZMtEFEpsszk__6rmjQ,893
|
|
10
10
|
lizard_ext/lizardboolcount.py,sha256=abmMA9X3VFRO5mziicUxWKmHldHNC0jBEe7NKAKA5fs,1062
|
|
11
11
|
lizard_ext/lizardcomplextags.py,sha256=flrwYg24P5DoDsBO3gdcK9SxkugX_brhfjuu8zgPnOc,681
|
|
@@ -20,17 +20,17 @@ lizard_ext/lizardignoreassert.py,sha256=sqLwcnJQ06SYqIk901ib4NQ8ECwjIe_qL4T6z1wL
|
|
|
20
20
|
lizard_ext/lizardio.py,sha256=xQN-AgLGLKJarJkgfaqX_TKyupbb7GTcwPxrL2B1J1w,3357
|
|
21
21
|
lizard_ext/lizardmccabe.py,sha256=RiO8ASmQUah4udOH8SbE2OOMxwShIPByW93TlFxXlQU,1274
|
|
22
22
|
lizard_ext/lizardmodified.py,sha256=4Ld7yy1D2m2biMtx-g0DtjXwLa-9mG2togS2IRDAF3k,705
|
|
23
|
-
lizard_ext/lizardnd.py,sha256=
|
|
23
|
+
lizard_ext/lizardnd.py,sha256=h4MaSsFAY5rK8kOSr61LkWntwJWV1KnhaEOWZgp3-c0,7496
|
|
24
24
|
lizard_ext/lizardnonstrict.py,sha256=pPG22up2uh9rEkdRFtTWdiuOaiBNe0ZUjaZQpSTX5LE,394
|
|
25
25
|
lizard_ext/lizardns.py,sha256=8pztUoRS_UWN24MawwxeHEJgYh49id5PWODUBb6O72U,4184
|
|
26
26
|
lizard_ext/lizardoutside.py,sha256=FGm2tbBZ17-2OCgmQlD-vobUCfQKb0FAygf86eM3xuM,336
|
|
27
27
|
lizard_ext/lizardstatementcount.py,sha256=xYk6ixSIItSE1BWQXzrWmduFgGhA3VR817SNKLffyVQ,1182
|
|
28
28
|
lizard_ext/lizardwordcount.py,sha256=2QYXD7-AtkkgAbi9VSidunMbSsGQ7MKYb6IT-bS-cok,7575
|
|
29
|
-
lizard_ext/version.py,sha256=
|
|
29
|
+
lizard_ext/version.py,sha256=gScBFBQFiyhdj77Gb-x1hY6wABdKwZlb_aaNdiiADQ0,181
|
|
30
30
|
lizard_ext/xmloutput.py,sha256=-cbh0he4O_X-wX56gkv9AnSPNN0qvR7FACqlBeezUS4,5609
|
|
31
|
-
lizard_languages/__init__.py,sha256=
|
|
32
|
-
lizard_languages/clike.py,sha256=
|
|
33
|
-
lizard_languages/code_reader.py,sha256=
|
|
31
|
+
lizard_languages/__init__.py,sha256=DniggHM3SOFlwkP8Tm4csEcisbf7_i1EvfoAkG9Atg0,1611
|
|
32
|
+
lizard_languages/clike.py,sha256=_oDUbA1hEIPujKw3wyAtC1uFPvjmg4TBgKbHLa-S1wg,13597
|
|
33
|
+
lizard_languages/code_reader.py,sha256=O0nZkI4xEHIWGgFBDwczj8-ay7aKllPnzRsblQtL3Gc,6874
|
|
34
34
|
lizard_languages/csharp.py,sha256=EfFAIOIcJXUUhXTlZApXGSlzG34NZvHM9OSe6m7hpv0,2141
|
|
35
35
|
lizard_languages/erlang.py,sha256=7YJS2cMyXDKEV_kpH8DzBARxFCFcjKuTOPSQ3K52auU,3860
|
|
36
36
|
lizard_languages/fortran.py,sha256=KATDsnfjob5W3579A_VxbwrbTkK7Rx3p0eXdBgjx25I,8973
|
|
@@ -39,31 +39,32 @@ lizard_languages/go.py,sha256=sntz0jOEuj4klPipoTFd16UDK1fAUQfwK7YX_cLMZAc,1346
|
|
|
39
39
|
lizard_languages/golike.py,sha256=vRIfjTVvc0VmJf27lTOLht55ZF1AQ9wn0Fvu-9WabWk,2858
|
|
40
40
|
lizard_languages/java.py,sha256=HQBTZjUKbUJwgmtLYIzJrWtPpFP3ZdBP_NJK7YOXZC0,6424
|
|
41
41
|
lizard_languages/javascript.py,sha256=vniCNMW-ea9Jpv6c8qCcjLVDYjT8VztjXigp5XRWt0E,317
|
|
42
|
-
lizard_languages/js_style_language_states.py,sha256=6mLrHfvDC4oHttKsSRGkE-ayG8uKSEm4E4rlhaUN5lA,6396
|
|
43
42
|
lizard_languages/js_style_regex_expression.py,sha256=Xgyogch4xElYtCG4EnBKvalHTl3tjRPcIIcIQRRd61I,1970
|
|
44
|
-
lizard_languages/jsx.py,sha256=TLH93qrZO2r_tiiv1XBIbw2_mbUMjwCZAuBz5vG5oBw,11696
|
|
45
43
|
lizard_languages/kotlin.py,sha256=v_o2orEzA5gB9vM_0h-E4QXjrc5Yum-0K6W6_laOThc,2844
|
|
46
44
|
lizard_languages/lua.py,sha256=3nqBcunBzJrhv4Iqaf8xvbyqxZy3aSxJ-IiHimHFlac,1573
|
|
47
45
|
lizard_languages/objc.py,sha256=2a1teLdaXZBtCeFiIZer1j_sVx9LZ1CbF2XfnqlvLmk,2319
|
|
48
46
|
lizard_languages/perl.py,sha256=136w620eECe_t-kmlRUGrsZSxQNo2JQ_PZTSQfCSmHY,11987
|
|
49
47
|
lizard_languages/php.py,sha256=UV40p8WzNC64NQ5qElPKzcFTjVt5kenLMz-eKYlcnMY,9940
|
|
50
|
-
lizard_languages/
|
|
48
|
+
lizard_languages/plsql.py,sha256=17zf0AkDLFW7mA3ngUNrU7z6U6DkmA96CKOcEhYNC5Q,17137
|
|
49
|
+
lizard_languages/python.py,sha256=AsL0SmQ73zhNS1iGi4Z8VtuUE0VjqBzo9W8W0mjqL0E,5790
|
|
50
|
+
lizard_languages/r.py,sha256=IoyMhmFtUmTji6rm6-fqss_j_kvIHu3JjABRh6RNys0,12583
|
|
51
51
|
lizard_languages/ruby.py,sha256=HL1ZckeuUUJU3QSVAOPsG_Zsl0C6X2PX5_VaWqclzkM,2277
|
|
52
52
|
lizard_languages/rubylike.py,sha256=dAGZ2wqW8nqaESMU8HkeR9gwQ-q9fmZqE6AANvVZD1Q,3426
|
|
53
|
-
lizard_languages/rust.py,sha256=
|
|
53
|
+
lizard_languages/rust.py,sha256=WarDHnFZv99Yu3_C5DpZfLS8dVWz6AcOzo2dzLW94rA,817
|
|
54
54
|
lizard_languages/scala.py,sha256=6Jr_TG945VYqB3o5weD7jN7S4beHt4aVj3r-fmKeMAM,1316
|
|
55
55
|
lizard_languages/script_language.py,sha256=SKe45AbO6Z-axbN8KW_g7jf9g7YTXZ6dWzJj4ubDsM8,1172
|
|
56
56
|
lizard_languages/solidity.py,sha256=Z0GD7U5bI5eUikdy7m_iKWeFD5yXRYq4r3zycscOhJQ,553
|
|
57
|
+
lizard_languages/st.py,sha256=7fpOfNAoUjNY8RCHSYLufnOzZTUkKwjVvcyRyM1xP2Y,4160
|
|
57
58
|
lizard_languages/swift.py,sha256=p8S2OAkQOx9YQ02yhoVXFkr7pMqUH1Nb3RVXPHRU_9M,2450
|
|
58
59
|
lizard_languages/tnsdl.py,sha256=pGcalA_lHY362v2wwPS86seYBOOBBjvmU6vd4Yy3A9g,2803
|
|
59
|
-
lizard_languages/tsx.py,sha256=
|
|
60
|
+
lizard_languages/tsx.py,sha256=1oOVCcz5yHkmYLYGhSarCMSXfGVasweklAqqapkuNR4,17160
|
|
60
61
|
lizard_languages/ttcn.py,sha256=ygjw_raBmPF-4mgoM8m6CAdyEMpTI-n1kZJK1RL4Vxo,2131
|
|
61
|
-
lizard_languages/typescript.py,sha256=
|
|
62
|
+
lizard_languages/typescript.py,sha256=unCDj040dY9fTOw9iIykqjt2j5tZWJ2Bm9fHYjOWY5I,14706
|
|
62
63
|
lizard_languages/vue.py,sha256=KXUBUo2R1zNF8Pffrz_KsQEN44m5XFRMoGXylxKUeT0,1038
|
|
63
64
|
lizard_languages/zig.py,sha256=NX1iyBstBuJFeAGBOAIaRfrmeBREne2HX6Pt4fXZZTQ,586
|
|
64
|
-
lizard-1.
|
|
65
|
-
lizard-1.
|
|
66
|
-
lizard-1.
|
|
67
|
-
lizard-1.
|
|
68
|
-
lizard-1.
|
|
69
|
-
lizard-1.
|
|
65
|
+
lizard-1.19.0.dist-info/LICENSE.txt,sha256=05ZjgQ8Cl1dD9p0BhW-Txzkc5rhCogGJVEuf1GT2Y_M,1303
|
|
66
|
+
lizard-1.19.0.dist-info/METADATA,sha256=DNAVbhrtdVrI5tn2rWZoSBwCfZ5ArhMQ0XNmHvOqbh4,16697
|
|
67
|
+
lizard-1.19.0.dist-info/WHEEL,sha256=Kh9pAotZVRFj97E15yTA4iADqXdQfIVTHcNaZTjxeGM,110
|
|
68
|
+
lizard-1.19.0.dist-info/entry_points.txt,sha256=pPMMwoHAltzGHqR2WeJQItLeeyR7pbX5R2S_POC-xoo,40
|
|
69
|
+
lizard-1.19.0.dist-info/top_level.txt,sha256=5NTrTaOLhHuTzXaGcZPKfuaOgUv7WafNGe0Zl5aycpg,35
|
|
70
|
+
lizard-1.19.0.dist-info/RECORD,,
|
lizard.py
CHANGED
|
@@ -623,7 +623,7 @@ def whitelist_filter(warnings, script=None, whitelist=None):
|
|
|
623
623
|
|
|
624
624
|
def get_whitelist(whitelist):
|
|
625
625
|
if os.path.isfile(whitelist):
|
|
626
|
-
return
|
|
626
|
+
return auto_read(whitelist)
|
|
627
627
|
if whitelist != DEFAULT_WHITELIST:
|
|
628
628
|
print("WARNING: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
|
|
629
629
|
print("WARNING: the whitelist \""+whitelist+"\" doesn't exist.")
|
|
@@ -923,12 +923,12 @@ def get_all_source_files(paths, exclude_patterns, lans):
|
|
|
923
923
|
for path in paths:
|
|
924
924
|
gitignore_path = os.path.join(path, '.gitignore')
|
|
925
925
|
if os.path.exists(gitignore_path):
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
926
|
+
gitignore_file = auto_read(gitignore_path)
|
|
927
|
+
# Read lines and strip whitespace and empty lines
|
|
928
|
+
patterns = [line.strip() for line in gitignore_file.splitlines()]
|
|
929
|
+
patterns = [p for p in patterns if p and not p.startswith('#')]
|
|
930
|
+
gitignore_spec = pathspec.PathSpec.from_lines('gitwildmatch', patterns)
|
|
931
|
+
base_path = path
|
|
932
932
|
break
|
|
933
933
|
except ImportError:
|
|
934
934
|
pass
|
lizard_ext/checkstyleoutput.py
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Checkstyle XML output for Lizard
|
|
3
3
|
'''
|
|
4
4
|
|
|
5
|
+
|
|
5
6
|
def checkstyle_output(all_result, verbose):
|
|
6
7
|
result = all_result.result
|
|
7
8
|
import xml.etree.ElementTree as ET
|
|
@@ -20,7 +21,8 @@ def checkstyle_output(all_result, verbose):
|
|
|
20
21
|
line=str(func.start_line),
|
|
21
22
|
column="0",
|
|
22
23
|
severity="info",
|
|
23
|
-
message=f"{func.name} has {func.nloc} NLOC, {func.cyclomatic_complexity} CCN,
|
|
24
|
+
message=f"{func.name} has {func.nloc} NLOC, {func.cyclomatic_complexity} CCN, "
|
|
25
|
+
f"{func.token_count} token, {len(func.parameters)} PARAM, {func.length} length",
|
|
24
26
|
source="lizard"
|
|
25
27
|
)
|
|
26
28
|
|
|
@@ -28,4 +30,4 @@ def checkstyle_output(all_result, verbose):
|
|
|
28
30
|
import xml.dom.minidom
|
|
29
31
|
rough_string = ET.tostring(checkstyle, 'utf-8')
|
|
30
32
|
reparsed = xml.dom.minidom.parseString(rough_string)
|
|
31
|
-
return reparsed.toprettyxml(indent=" ")
|
|
33
|
+
return reparsed.toprettyxml(indent=" ")
|
lizard_ext/htmloutput.py
CHANGED
|
@@ -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
|
|
117
|
-
<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
|
|
lizard_ext/lizardnd.py
CHANGED
|
@@ -45,11 +45,43 @@ class LizardExtension(object): # pylint: disable=R0903
|
|
|
45
45
|
else:
|
|
46
46
|
indent_indicator = ';'
|
|
47
47
|
for token in tokens:
|
|
48
|
-
|
|
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)
|
lizard_ext/version.py
CHANGED
lizard_languages/__init__.py
CHANGED
|
@@ -21,10 +21,12 @@ from .rust import RustReader
|
|
|
21
21
|
from .typescript import TypeScriptReader
|
|
22
22
|
from .fortran import FortranReader
|
|
23
23
|
from .solidity import SolidityReader
|
|
24
|
-
from .jsx import JSXReader
|
|
25
24
|
from .tsx import TSXReader
|
|
26
25
|
from .vue import VueReader
|
|
27
26
|
from .perl import PerlReader
|
|
27
|
+
from .st import StReader
|
|
28
|
+
from .r import RReader
|
|
29
|
+
from .plsql import PLSQLReader
|
|
28
30
|
|
|
29
31
|
|
|
30
32
|
def languages():
|
|
@@ -50,10 +52,12 @@ def languages():
|
|
|
50
52
|
SolidityReader,
|
|
51
53
|
ErlangReader,
|
|
52
54
|
ZigReader,
|
|
53
|
-
JSXReader,
|
|
54
55
|
TSXReader,
|
|
55
56
|
VueReader,
|
|
56
57
|
PerlReader,
|
|
58
|
+
StReader,
|
|
59
|
+
RReader,
|
|
60
|
+
PLSQLReader,
|
|
57
61
|
]
|
|
58
62
|
|
|
59
63
|
|
lizard_languages/clike.py
CHANGED
|
@@ -19,7 +19,7 @@ class CCppCommentsMixin(object): # pylint: disable=R0903
|
|
|
19
19
|
class CLikeReader(CodeReader, CCppCommentsMixin):
|
|
20
20
|
''' This is the reader for C, C++ and Java. '''
|
|
21
21
|
|
|
22
|
-
ext = ["c", "cpp", "cc", "
|
|
22
|
+
ext = ["c", "cpp", "cc", "cxx", "h", "hpp"]
|
|
23
23
|
language_names = ['cpp', 'c']
|
|
24
24
|
macro_pattern = re.compile(r"#\s*(\w+)\s*(.*)", re.M | re.S)
|
|
25
25
|
|
|
@@ -54,7 +54,7 @@ class CLikeReader(CodeReader, CCppCommentsMixin):
|
|
|
54
54
|
elif macro.group(1) == 'include':
|
|
55
55
|
yield "#include"
|
|
56
56
|
yield macro.group(2) or "\"\""
|
|
57
|
-
for _ in macro.group(2).
|
|
57
|
+
for _ in macro.group(2).split('\n')[1:]:
|
|
58
58
|
yield '\n'
|
|
59
59
|
else:
|
|
60
60
|
yield token
|
|
@@ -162,6 +162,11 @@ class CLikeStates(CodeStateMachine):
|
|
|
162
162
|
def _state_global(self, token):
|
|
163
163
|
if token[0].isalpha() or token[0] in '_~':
|
|
164
164
|
self.try_new_function(token)
|
|
165
|
+
elif token == '[':
|
|
166
|
+
# Check if this might be a lambda expression (C++ only)
|
|
167
|
+
# Java doesn't have lambda expressions, so skip lambda detection for Java
|
|
168
|
+
if not hasattr(self, 'class_name'): # JavaStates has class_name attribute
|
|
169
|
+
self._state = self._state_lambda_check
|
|
165
170
|
|
|
166
171
|
def _state_function(self, token):
|
|
167
172
|
if token == '(':
|
|
@@ -310,3 +315,57 @@ class CLikeStates(CodeStateMachine):
|
|
|
310
315
|
def _state_attribute(self, _):
|
|
311
316
|
"Ignores function attributes with C++11 syntax, i.e., [[ attribute ]]."
|
|
312
317
|
pass
|
|
318
|
+
|
|
319
|
+
def _state_lambda_check(self, token):
|
|
320
|
+
"""Check if this is a lambda expression or a function attribute."""
|
|
321
|
+
if token == ']':
|
|
322
|
+
# This is a lambda expression [](params) or [capture](params)
|
|
323
|
+
# Skip the lambda and continue parsing normally
|
|
324
|
+
self._state = self._state_lambda_params
|
|
325
|
+
elif token == '[':
|
|
326
|
+
# This is a function attribute [[attribute]]
|
|
327
|
+
self._state = self._state_attribute
|
|
328
|
+
else:
|
|
329
|
+
# This is a lambda with capture list [capture](params)
|
|
330
|
+
# Skip until we find the closing bracket
|
|
331
|
+
self._state = self._state_lambda_capture
|
|
332
|
+
|
|
333
|
+
def _state_lambda_params(self, token):
|
|
334
|
+
"""Handle lambda parameters and body."""
|
|
335
|
+
if token == '(':
|
|
336
|
+
# Start of parameter list, skip until closing parenthesis
|
|
337
|
+
self._state = self._state_lambda_param_list
|
|
338
|
+
else:
|
|
339
|
+
# No parameters, check for body
|
|
340
|
+
self._state = self._state_lambda_body
|
|
341
|
+
|
|
342
|
+
def _state_lambda_param_list(self, token):
|
|
343
|
+
"""Handle lambda parameter list."""
|
|
344
|
+
if token == ')':
|
|
345
|
+
# End of parameter list, check for body
|
|
346
|
+
self._state = self._state_lambda_body
|
|
347
|
+
# Otherwise, continue in parameter list
|
|
348
|
+
|
|
349
|
+
def _state_lambda_body(self, token):
|
|
350
|
+
"""Handle lambda body."""
|
|
351
|
+
if token == '{':
|
|
352
|
+
# Start of lambda body, skip until closing brace
|
|
353
|
+
self._state = self._state_lambda_body_skip
|
|
354
|
+
elif token == ';':
|
|
355
|
+
# Lambda without body, just a semicolon
|
|
356
|
+
self._state = self._state_global
|
|
357
|
+
# Otherwise, continue
|
|
358
|
+
|
|
359
|
+
def _state_lambda_body_skip(self, token):
|
|
360
|
+
"""Skip lambda body until closing brace."""
|
|
361
|
+
if token == '}':
|
|
362
|
+
# End of lambda body, continue parsing normally
|
|
363
|
+
self._state = self._state_global
|
|
364
|
+
# Otherwise, continue skipping
|
|
365
|
+
|
|
366
|
+
def _state_lambda_capture(self, token):
|
|
367
|
+
"""Handle lambda capture list."""
|
|
368
|
+
if token == ']':
|
|
369
|
+
# End of capture list, continue parsing normally
|
|
370
|
+
self._state = self._state_global
|
|
371
|
+
# Otherwise, continue in capture list
|
lizard_languages/code_reader.py
CHANGED
|
@@ -138,7 +138,7 @@ class CodeReader:
|
|
|
138
138
|
r"|\/\/" + _until_end +
|
|
139
139
|
r"|\#" +
|
|
140
140
|
r"|:=|::|\*\*" +
|
|
141
|
-
r"
|
|
141
|
+
r"|\<(?=(?:[^<>]*\?)+[^<>]*\>)(?:[\w\s,.?]|(?:extends))+\>" +
|
|
142
142
|
r"|" + r"|".join(re.escape(s) for s in combined_symbols) +
|
|
143
143
|
r"|\\\n" +
|
|
144
144
|
r"|\n" +
|