code-gauge 4.3.1 → 4.5.0
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.
- package/README.md +9 -4
- package/dist/crossFileDuplication.cjs +1 -1
- package/dist/crossFileDuplication.cjs.map +1 -1
- package/dist/crossFileDuplication.d.ts +11 -4
- package/dist/crossFileDuplication.js +1 -1
- package/dist/crossFileDuplication.js.map +1 -1
- package/dist/crossFileNearMiss.cjs +2 -0
- package/dist/crossFileNearMiss.cjs.map +1 -0
- package/dist/crossFileNearMiss.d.ts +27 -0
- package/dist/crossFileNearMiss.js +2 -0
- package/dist/crossFileNearMiss.js.map +1 -0
- package/dist/diffCommand.cjs +1 -1
- package/dist/diffCommand.cjs.map +1 -1
- package/dist/diffCommand.js +3 -3
- package/dist/diffCommand.js.map +1 -1
- package/dist/duplication.cjs +1 -1
- package/dist/duplication.cjs.map +1 -1
- package/dist/duplication.d.ts +11 -0
- package/dist/duplication.js +1 -1
- package/dist/duplication.js.map +1 -1
- package/dist/metrics.cjs +1 -1
- package/dist/metrics.cjs.map +1 -1
- package/dist/metrics.d.ts +10 -0
- package/dist/metrics.js +1 -1
- package/dist/metrics.js.map +1 -1
- package/dist/nativeMetrics.cjs +2 -2
- package/dist/nativeMetrics.cjs.map +1 -1
- package/dist/nativeMetrics.d.ts +7 -2
- package/dist/nativeMetrics.js +2 -2
- package/dist/nativeMetrics.js.map +1 -1
- package/dist/scan.cjs +1 -1
- package/dist/scan.cjs.map +1 -1
- package/dist/scan.d.ts +12 -1
- package/dist/scan.js +1 -1
- package/dist/scan.js.map +1 -1
- package/dist/types.d.ts +11 -1
- package/native/src/complexity.rs +23 -7
- package/native/src/dep_degree.rs +2 -3
- package/native/src/duplication.rs +170 -115
- package/native/src/functions.rs +1 -1
- package/native/src/languages.rs +17 -0
- package/native/src/lib.rs +6 -2
- package/native/src/measure.rs +118 -13
- package/native/src/types.rs +6 -0
- package/package.json +8 -8
package/native/src/languages.rs
CHANGED
|
@@ -7,6 +7,10 @@ pub struct LanguageDefinition {
|
|
|
7
7
|
grammar_id: GrammarId,
|
|
8
8
|
pub function_node_types: &'static [&'static str],
|
|
9
9
|
pub decision_node_types: &'static [&'static str],
|
|
10
|
+
/// Whether every file's top-level code runs as a module body (a component of its own in the
|
|
11
|
+
/// file's cyclomatic complexity); C# and Kotlin decide per file by the presence of top-level
|
|
12
|
+
/// statements (never for a Kotlin file with parse errors).
|
|
13
|
+
pub executes_top_level: bool,
|
|
10
14
|
pub nesting_node_types: &'static [&'static str],
|
|
11
15
|
pub ncss_node_types: &'static [&'static str],
|
|
12
16
|
pub ncss_container_node_types: &'static [&'static str],
|
|
@@ -656,6 +660,7 @@ pub const LANGUAGES: &[LanguageDefinition] = &[
|
|
|
656
660
|
grammar_id: GrammarId::JavaScript,
|
|
657
661
|
function_node_types: COMMON_FUNCTION_NODES,
|
|
658
662
|
decision_node_types: COMMON_DECISION_NODES,
|
|
663
|
+
executes_top_level: true,
|
|
659
664
|
nesting_node_types: COMMON_NESTING_NODES,
|
|
660
665
|
ncss_node_types: JS_NCSS_NODES,
|
|
661
666
|
ncss_container_node_types: &[],
|
|
@@ -666,6 +671,7 @@ pub const LANGUAGES: &[LanguageDefinition] = &[
|
|
|
666
671
|
grammar_id: GrammarId::JavaScript,
|
|
667
672
|
function_node_types: COMMON_FUNCTION_NODES,
|
|
668
673
|
decision_node_types: COMMON_DECISION_NODES,
|
|
674
|
+
executes_top_level: true,
|
|
669
675
|
nesting_node_types: COMMON_NESTING_NODES,
|
|
670
676
|
ncss_node_types: JS_NCSS_NODES,
|
|
671
677
|
ncss_container_node_types: &[],
|
|
@@ -676,6 +682,7 @@ pub const LANGUAGES: &[LanguageDefinition] = &[
|
|
|
676
682
|
grammar_id: GrammarId::TypeScript,
|
|
677
683
|
function_node_types: COMMON_FUNCTION_NODES,
|
|
678
684
|
decision_node_types: COMMON_DECISION_NODES,
|
|
685
|
+
executes_top_level: true,
|
|
679
686
|
nesting_node_types: COMMON_NESTING_NODES,
|
|
680
687
|
ncss_node_types: JS_NCSS_NODES,
|
|
681
688
|
ncss_container_node_types: &[],
|
|
@@ -686,6 +693,7 @@ pub const LANGUAGES: &[LanguageDefinition] = &[
|
|
|
686
693
|
grammar_id: GrammarId::Tsx,
|
|
687
694
|
function_node_types: COMMON_FUNCTION_NODES,
|
|
688
695
|
decision_node_types: COMMON_DECISION_NODES,
|
|
696
|
+
executes_top_level: true,
|
|
689
697
|
nesting_node_types: COMMON_NESTING_NODES,
|
|
690
698
|
ncss_node_types: JS_NCSS_NODES,
|
|
691
699
|
ncss_container_node_types: &[],
|
|
@@ -696,6 +704,7 @@ pub const LANGUAGES: &[LanguageDefinition] = &[
|
|
|
696
704
|
grammar_id: GrammarId::Python,
|
|
697
705
|
function_node_types: COMMON_FUNCTION_NODES,
|
|
698
706
|
decision_node_types: COMMON_DECISION_NODES,
|
|
707
|
+
executes_top_level: true,
|
|
699
708
|
nesting_node_types: COMMON_NESTING_NODES,
|
|
700
709
|
ncss_node_types: PYTHON_NCSS_NODES,
|
|
701
710
|
ncss_container_node_types: &[],
|
|
@@ -706,6 +715,7 @@ pub const LANGUAGES: &[LanguageDefinition] = &[
|
|
|
706
715
|
grammar_id: GrammarId::Go,
|
|
707
716
|
function_node_types: COMMON_FUNCTION_NODES,
|
|
708
717
|
decision_node_types: GO_DECISION_NODES,
|
|
718
|
+
executes_top_level: false,
|
|
709
719
|
nesting_node_types: GO_NESTING_NODES,
|
|
710
720
|
ncss_node_types: GO_NCSS_NODES,
|
|
711
721
|
ncss_container_node_types: &[],
|
|
@@ -716,6 +726,7 @@ pub const LANGUAGES: &[LanguageDefinition] = &[
|
|
|
716
726
|
grammar_id: GrammarId::Rust,
|
|
717
727
|
function_node_types: COMMON_FUNCTION_NODES,
|
|
718
728
|
decision_node_types: COMMON_DECISION_NODES,
|
|
729
|
+
executes_top_level: false,
|
|
719
730
|
nesting_node_types: COMMON_NESTING_NODES,
|
|
720
731
|
ncss_node_types: RUST_NCSS_NODES,
|
|
721
732
|
ncss_container_node_types: RUST_NCSS_CONTAINERS,
|
|
@@ -726,6 +737,7 @@ pub const LANGUAGES: &[LanguageDefinition] = &[
|
|
|
726
737
|
grammar_id: GrammarId::Java,
|
|
727
738
|
function_node_types: JAVA_FUNCTION_NODES,
|
|
728
739
|
decision_node_types: JAVA_DECISION_NODES,
|
|
740
|
+
executes_top_level: false,
|
|
729
741
|
nesting_node_types: JAVA_DECISION_NODES,
|
|
730
742
|
ncss_node_types: JAVA_NCSS_NODES,
|
|
731
743
|
ncss_container_node_types: &[],
|
|
@@ -736,6 +748,7 @@ pub const LANGUAGES: &[LanguageDefinition] = &[
|
|
|
736
748
|
grammar_id: GrammarId::Ruby,
|
|
737
749
|
function_node_types: RUBY_FUNCTION_NODES,
|
|
738
750
|
decision_node_types: RUBY_DECISION_NODES,
|
|
751
|
+
executes_top_level: true,
|
|
739
752
|
nesting_node_types: RUBY_DECISION_NODES,
|
|
740
753
|
ncss_node_types: RUBY_NCSS_NODES,
|
|
741
754
|
ncss_container_node_types: RUBY_NCSS_CONTAINERS,
|
|
@@ -746,6 +759,7 @@ pub const LANGUAGES: &[LanguageDefinition] = &[
|
|
|
746
759
|
grammar_id: GrammarId::C,
|
|
747
760
|
function_node_types: C_FUNCTION_NODES,
|
|
748
761
|
decision_node_types: C_DECISION_NODES,
|
|
762
|
+
executes_top_level: false,
|
|
749
763
|
nesting_node_types: C_DECISION_NODES,
|
|
750
764
|
ncss_node_types: C_NCSS_NODES,
|
|
751
765
|
ncss_container_node_types: &[],
|
|
@@ -756,6 +770,7 @@ pub const LANGUAGES: &[LanguageDefinition] = &[
|
|
|
756
770
|
grammar_id: GrammarId::Cpp,
|
|
757
771
|
function_node_types: C_FUNCTION_NODES,
|
|
758
772
|
decision_node_types: CPP_DECISION_NODES,
|
|
773
|
+
executes_top_level: false,
|
|
759
774
|
nesting_node_types: CPP_DECISION_NODES,
|
|
760
775
|
ncss_node_types: CPP_NCSS_NODES,
|
|
761
776
|
ncss_container_node_types: &[],
|
|
@@ -766,6 +781,7 @@ pub const LANGUAGES: &[LanguageDefinition] = &[
|
|
|
766
781
|
grammar_id: GrammarId::CSharp,
|
|
767
782
|
function_node_types: CSHARP_FUNCTION_NODES,
|
|
768
783
|
decision_node_types: CSHARP_DECISION_NODES,
|
|
784
|
+
executes_top_level: false,
|
|
769
785
|
nesting_node_types: CSHARP_DECISION_NODES,
|
|
770
786
|
ncss_node_types: CSHARP_NCSS_NODES,
|
|
771
787
|
ncss_container_node_types: &[],
|
|
@@ -776,6 +792,7 @@ pub const LANGUAGES: &[LanguageDefinition] = &[
|
|
|
776
792
|
grammar_id: GrammarId::Kotlin,
|
|
777
793
|
function_node_types: KOTLIN_FUNCTION_NODES,
|
|
778
794
|
decision_node_types: KOTLIN_DECISION_NODES,
|
|
795
|
+
executes_top_level: false,
|
|
779
796
|
nesting_node_types: KOTLIN_DECISION_NODES,
|
|
780
797
|
ncss_node_types: KOTLIN_NCSS_NODES,
|
|
781
798
|
ncss_container_node_types: KOTLIN_NCSS_CONTAINERS,
|
package/native/src/lib.rs
CHANGED
|
@@ -21,10 +21,12 @@ mod util;
|
|
|
21
21
|
/// together with `expectedPayloadVersion` in src/nativeMetrics.ts.
|
|
22
22
|
#[napi]
|
|
23
23
|
pub fn payload_version() -> u32 {
|
|
24
|
-
|
|
24
|
+
7
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
/// Measures code metrics for the given source, returning the NativeMetrics payload as JSON
|
|
27
|
+
/// Measures code metrics for the given source, returning the NativeMetrics payload as JSON; with
|
|
28
|
+
/// `include_cross_file_data`, the payload also carries the file's cross-file clone-detection
|
|
29
|
+
/// contribution from the same parse.
|
|
28
30
|
/// The TypeScript wrapper derives the remaining float metrics (Halstead volume/effort/...): they
|
|
29
31
|
/// involve transcendental functions whose last-bit results can differ between V8 and Rust's libm,
|
|
30
32
|
/// and results must not depend on which side computes them.
|
|
@@ -36,6 +38,7 @@ pub fn measure_code_native(
|
|
|
36
38
|
min_tokens: Option<u32>,
|
|
37
39
|
max_gap_tokens: Option<u32>,
|
|
38
40
|
min_similarity_percent: Option<u32>,
|
|
41
|
+
include_cross_file_data: Option<bool>,
|
|
39
42
|
) -> Result<String> {
|
|
40
43
|
let definition = find_language(&language)?;
|
|
41
44
|
let settings = to_duplication_settings(min_tokens, max_gap_tokens, min_similarity_percent);
|
|
@@ -43,6 +46,7 @@ pub fn measure_code_native(
|
|
|
43
46
|
&code,
|
|
44
47
|
definition,
|
|
45
48
|
include_syntax_tree.unwrap_or(false),
|
|
49
|
+
include_cross_file_data.unwrap_or(false),
|
|
46
50
|
&settings,
|
|
47
51
|
)
|
|
48
52
|
.map_err(Error::from_reason)?;
|
package/native/src/measure.rs
CHANGED
|
@@ -7,7 +7,8 @@ use crate::complexity::{
|
|
|
7
7
|
};
|
|
8
8
|
use crate::dep_degree::measure_dep_degree;
|
|
9
9
|
use crate::duplication::{
|
|
10
|
-
collect_cross_file_file_data, hash_text, measure_duplication, DuplicationSettings,
|
|
10
|
+
collect_cross_file_file_data, hash_text, measure_duplication, tokenize, DuplicationSettings,
|
|
11
|
+
TokenizedSource,
|
|
11
12
|
};
|
|
12
13
|
use crate::functions::{
|
|
13
14
|
collect_nodes, count_parameters, find_function_name, is_implemented_function,
|
|
@@ -25,6 +26,7 @@ pub fn measure(
|
|
|
25
26
|
code: &str,
|
|
26
27
|
language: &LanguageDefinition,
|
|
27
28
|
include_syntax_tree: bool,
|
|
29
|
+
include_cross_file_data: bool,
|
|
28
30
|
duplication_settings: &DuplicationSettings,
|
|
29
31
|
) -> Result<NativeMetrics, String> {
|
|
30
32
|
let source = Source::new(code);
|
|
@@ -38,11 +40,12 @@ pub fn measure(
|
|
|
38
40
|
.filter(|node| !is_lambda_body_block(*node) && is_implemented_function(*node))
|
|
39
41
|
.collect();
|
|
40
42
|
|
|
41
|
-
let
|
|
43
|
+
let body_metrics = measure_function_body_metrics(root, &sets, code);
|
|
42
44
|
let function_metrics: Vec<FunctionMetrics> = functions
|
|
43
45
|
.iter()
|
|
44
46
|
.map(|node| {
|
|
45
|
-
let body_metrics =
|
|
47
|
+
let body_metrics = body_metrics
|
|
48
|
+
.by_function
|
|
46
49
|
.get(&node.id())
|
|
47
50
|
.expect("every collected function node opens a frame in the body-metrics pass");
|
|
48
51
|
FunctionMetrics {
|
|
@@ -71,11 +74,22 @@ pub fn measure(
|
|
|
71
74
|
let global_complexity = measure_complexity(root, &sets, code);
|
|
72
75
|
let (lines, code_line_numbers) = classify_lines(code, root);
|
|
73
76
|
let halstead_counts = measure_halstead(root, code);
|
|
77
|
+
let tokenized = tokenize(root, code);
|
|
74
78
|
|
|
75
79
|
Ok(NativeMetrics {
|
|
76
80
|
language: language.name.to_string(),
|
|
77
81
|
bytes: code.code.len(),
|
|
78
82
|
lines,
|
|
83
|
+
// McCabe's v = e - n + 2p over the file's components: every function, every initializer
|
|
84
|
+
// block, and the module body when the file runs top-level code; decisions outside functions
|
|
85
|
+
// belong to the file.
|
|
86
|
+
cyclomatic_complexity: function_metrics
|
|
87
|
+
.iter()
|
|
88
|
+
.map(|function| function.cyclomatic_complexity)
|
|
89
|
+
.sum::<u64>()
|
|
90
|
+
+ body_metrics.top_level_decisions
|
|
91
|
+
+ u64::from(language.executes_top_level || has_top_level_statements(root, language))
|
|
92
|
+
+ count_initializer_blocks(root),
|
|
79
93
|
cognitive_complexity: global_complexity.cognitive_complexity,
|
|
80
94
|
max_cognitive_complexity: function_metrics
|
|
81
95
|
.iter()
|
|
@@ -84,7 +98,14 @@ pub fn measure(
|
|
|
84
98
|
.unwrap_or(0),
|
|
85
99
|
nesting_depth: global_complexity.nesting_depth,
|
|
86
100
|
ncss_count: crate::ncss::count_ncss(root, &sets.ncss_nodes, &sets.ncss_containers),
|
|
87
|
-
duplication: measure_duplication(
|
|
101
|
+
duplication: measure_duplication(&tokenized, &code_line_numbers, duplication_settings),
|
|
102
|
+
cross_file_data: include_cross_file_data.then(|| {
|
|
103
|
+
to_cross_file_data(
|
|
104
|
+
&tokenized,
|
|
105
|
+
&code_line_numbers,
|
|
106
|
+
duplication_settings.min_tokens,
|
|
107
|
+
)
|
|
108
|
+
}),
|
|
88
109
|
halstead_counts,
|
|
89
110
|
functions: function_metrics,
|
|
90
111
|
syntax_tree: if include_syntax_tree {
|
|
@@ -95,6 +116,76 @@ pub fn measure(
|
|
|
95
116
|
})
|
|
96
117
|
}
|
|
97
118
|
|
|
119
|
+
/// Initializer blocks run code of their own, so each is a component like a function: Java static
|
|
120
|
+
/// and instance initializers, Kotlin `init` blocks, and JavaScript/TypeScript class `static`
|
|
121
|
+
/// blocks. Their decisions already count as decisions outside functions.
|
|
122
|
+
fn count_initializer_blocks(root: Node<'_>) -> u64 {
|
|
123
|
+
let initializer_types: HashSet<&'static str> = [
|
|
124
|
+
"static_initializer",
|
|
125
|
+
"anonymous_initializer",
|
|
126
|
+
"class_static_block",
|
|
127
|
+
"block",
|
|
128
|
+
]
|
|
129
|
+
.into_iter()
|
|
130
|
+
.collect();
|
|
131
|
+
collect_nodes(root, &initializer_types)
|
|
132
|
+
.into_iter()
|
|
133
|
+
.filter(|node| {
|
|
134
|
+
// A bare block is an initializer only as a direct member of a Java class or enum body.
|
|
135
|
+
node.kind() != "block"
|
|
136
|
+
|| node.parent().is_some_and(|parent| {
|
|
137
|
+
matches!(parent.kind(), "class_body" | "enum_body_declarations")
|
|
138
|
+
})
|
|
139
|
+
})
|
|
140
|
+
.count() as u64
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/// A C# top-level statement: a `global_statement`, or a statement inside a top-level `#if` block,
|
|
144
|
+
/// which the grammar does not wrap in `global_statement`; preprocessor blocks are transparent.
|
|
145
|
+
fn is_csharp_top_level_statement(node: Node<'_>) -> bool {
|
|
146
|
+
if node.kind().starts_with("preproc_") {
|
|
147
|
+
return named_children(node)
|
|
148
|
+
.into_iter()
|
|
149
|
+
.any(is_csharp_top_level_statement);
|
|
150
|
+
}
|
|
151
|
+
node.kind() == "global_statement"
|
|
152
|
+
|| node.kind() == "block"
|
|
153
|
+
|| node.kind().ends_with("_statement")
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/// Whether a C# or Kotlin file runs top-level code: C# top-level statements, or a Kotlin script's
|
|
157
|
+
/// statements beside its declarations.
|
|
158
|
+
fn has_top_level_statements(root: Node<'_>, language: &LanguageDefinition) -> bool {
|
|
159
|
+
const KOTLIN_DECLARATIONS: &[&str] = &[
|
|
160
|
+
"package_header",
|
|
161
|
+
"import_list",
|
|
162
|
+
"class_declaration",
|
|
163
|
+
"object_declaration",
|
|
164
|
+
"function_declaration",
|
|
165
|
+
"property_declaration",
|
|
166
|
+
"type_alias",
|
|
167
|
+
"shebang_line",
|
|
168
|
+
"file_annotation",
|
|
169
|
+
"getter",
|
|
170
|
+
"setter",
|
|
171
|
+
];
|
|
172
|
+
let children = named_children(root);
|
|
173
|
+
match language.name {
|
|
174
|
+
"csharp" => children.into_iter().any(is_csharp_top_level_statement),
|
|
175
|
+
// The grammar mis-parses some valid declarations (non-empty companion objects, `fun
|
|
176
|
+
// interface`) and leaves recovery residue at the top level, so a file with parse errors is
|
|
177
|
+
// never taken for a script.
|
|
178
|
+
"kotlin" => {
|
|
179
|
+
!root.has_error()
|
|
180
|
+
&& children.iter().any(|child| {
|
|
181
|
+
!KOTLIN_DECLARATIONS.contains(&child.kind())
|
|
182
|
+
&& !crate::ncss::COMMENT_NODE_TYPES.contains(&child.kind())
|
|
183
|
+
})
|
|
184
|
+
}
|
|
185
|
+
_ => false,
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
98
189
|
/// Collects one file's cross-file clone-detection contribution; see CrossFileFileData.
|
|
99
190
|
pub fn collect_cross_file_data(
|
|
100
191
|
code: &str,
|
|
@@ -104,17 +195,30 @@ pub fn collect_cross_file_data(
|
|
|
104
195
|
let source = Source::new(code);
|
|
105
196
|
let tree = parse_source(&source, language)?;
|
|
106
197
|
let root = tree.root_node();
|
|
107
|
-
let (candidates, tokens, container_statements) =
|
|
108
|
-
collect_cross_file_file_data(root, &source, min_tokens);
|
|
109
198
|
let (_, code_line_numbers) = classify_lines(&source, root);
|
|
110
|
-
|
|
199
|
+
Ok(to_cross_file_data(
|
|
200
|
+
&tokenize(root, &source),
|
|
201
|
+
&code_line_numbers,
|
|
202
|
+
min_tokens,
|
|
203
|
+
))
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
fn to_cross_file_data(
|
|
207
|
+
tokenized: &TokenizedSource<'_>,
|
|
208
|
+
code_line_numbers: &HashSet<usize>,
|
|
209
|
+
min_tokens: usize,
|
|
210
|
+
) -> CrossFileFileData {
|
|
211
|
+
let (candidates, tokens, container_statements, near_miss_blocks) =
|
|
212
|
+
collect_cross_file_file_data(tokenized, min_tokens);
|
|
213
|
+
let mut code_line_numbers: Vec<usize> = code_line_numbers.iter().copied().collect();
|
|
111
214
|
code_line_numbers.sort_unstable();
|
|
112
|
-
|
|
215
|
+
CrossFileFileData {
|
|
113
216
|
candidates,
|
|
114
217
|
tokens,
|
|
115
218
|
container_statements,
|
|
219
|
+
near_miss_blocks,
|
|
116
220
|
code_line_numbers,
|
|
117
|
-
}
|
|
221
|
+
}
|
|
118
222
|
}
|
|
119
223
|
|
|
120
224
|
/// Name-carrying leaf types anonymized by tokenize_function so consistent renames still match.
|
|
@@ -133,7 +237,7 @@ const IDENTIFIER_LEAF_NODE_TYPES: &[&str] = &[
|
|
|
133
237
|
];
|
|
134
238
|
|
|
135
239
|
/// Normalized token hash sequences of every function, index-parallel to the functions array of
|
|
136
|
-
/// measure()
|
|
240
|
+
/// measure().
|
|
137
241
|
pub fn collect_function_token_sequences(
|
|
138
242
|
code: &str,
|
|
139
243
|
language: &LanguageDefinition,
|
|
@@ -245,8 +349,9 @@ struct CommentSpan {
|
|
|
245
349
|
end_column: usize,
|
|
246
350
|
}
|
|
247
351
|
|
|
248
|
-
/// 1-based numbers of lines that are neither blank nor comment-only,
|
|
249
|
-
///
|
|
352
|
+
/// Line metrics plus the 1-based numbers of lines that are neither blank nor comment-only, shared
|
|
353
|
+
/// by the line counts and duplication line coverage so the coverage and its code-line denominator
|
|
354
|
+
/// agree.
|
|
250
355
|
fn classify_lines(code: &Source<'_>, root: Node<'_>) -> (LineMetrics, HashSet<usize>) {
|
|
251
356
|
let source_lines = split_lines(code.code);
|
|
252
357
|
// Spans are bucketed by line so classification stays linear.
|
|
@@ -525,7 +630,7 @@ const OPERAND_NODE_TYPES: &[&str] = &[
|
|
|
525
630
|
"none",
|
|
526
631
|
];
|
|
527
632
|
|
|
528
|
-
/// Non-leaf literals counted as one Halstead operand without descending
|
|
633
|
+
/// Non-leaf literals counted as one Halstead operand without descending.
|
|
529
634
|
/// `character_literal` is a leaf in Java and Kotlin but wraps a content node in C#; Kotlin's
|
|
530
635
|
/// suffixed numbers (`1L`, `1u`) wrap the bare literal, so `1` and `1L` stay distinct.
|
|
531
636
|
const ATOMIC_OPERAND_NODE_TYPES: &[&str] = &[
|
package/native/src/types.rs
CHANGED
|
@@ -11,11 +11,15 @@ pub struct NativeMetrics {
|
|
|
11
11
|
pub bytes: usize,
|
|
12
12
|
pub lines: LineMetrics,
|
|
13
13
|
pub functions: Vec<FunctionMetrics>,
|
|
14
|
+
pub cyclomatic_complexity: u64,
|
|
14
15
|
pub cognitive_complexity: u64,
|
|
15
16
|
pub max_cognitive_complexity: u64,
|
|
16
17
|
pub nesting_depth: u64,
|
|
17
18
|
pub ncss_count: u64,
|
|
18
19
|
pub duplication: DuplicationMetrics,
|
|
20
|
+
/// Collected from the same parse on request, so a directory scan tokenizes each file once.
|
|
21
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
22
|
+
pub cross_file_data: Option<CrossFileFileData>,
|
|
19
23
|
pub halstead_counts: HalsteadCounts,
|
|
20
24
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
21
25
|
pub syntax_tree: Option<String>,
|
|
@@ -79,6 +83,8 @@ pub struct CrossFileFileData {
|
|
|
79
83
|
pub candidates: Vec<CrossFileCandidate>,
|
|
80
84
|
pub tokens: Vec<CrossFileToken>,
|
|
81
85
|
pub container_statements: Vec<Vec<CrossFileTokenRange>>,
|
|
86
|
+
/// The mutually disjoint blocks cross-file near-miss (Type-3) comparison considers.
|
|
87
|
+
pub near_miss_blocks: Vec<CrossFileTokenRange>,
|
|
82
88
|
/// 1-based lines that are neither blank nor comment-only, sorted ascending.
|
|
83
89
|
pub code_line_numbers: Vec<usize>,
|
|
84
90
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "code-gauge",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.5.0",
|
|
4
4
|
"description": "Measure code metrics with tree-sitter.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -89,12 +89,12 @@
|
|
|
89
89
|
"registry": "https://registry.npmjs.org/"
|
|
90
90
|
},
|
|
91
91
|
"optionalDependencies": {
|
|
92
|
-
"code-gauge-linux-x64-gnu": "4.
|
|
93
|
-
"code-gauge-linux-arm64-gnu": "4.
|
|
94
|
-
"code-gauge-linux-x64-musl": "4.
|
|
95
|
-
"code-gauge-linux-arm64-musl": "4.
|
|
96
|
-
"code-gauge-darwin-x64": "4.
|
|
97
|
-
"code-gauge-darwin-arm64": "4.
|
|
98
|
-
"code-gauge-win32-x64-msvc": "4.
|
|
92
|
+
"code-gauge-linux-x64-gnu": "4.5.0",
|
|
93
|
+
"code-gauge-linux-arm64-gnu": "4.5.0",
|
|
94
|
+
"code-gauge-linux-x64-musl": "4.5.0",
|
|
95
|
+
"code-gauge-linux-arm64-musl": "4.5.0",
|
|
96
|
+
"code-gauge-darwin-x64": "4.5.0",
|
|
97
|
+
"code-gauge-darwin-arm64": "4.5.0",
|
|
98
|
+
"code-gauge-win32-x64-msvc": "4.5.0"
|
|
99
99
|
}
|
|
100
100
|
}
|