slopbrick 0.25.0 → 0.26.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/dist/engine/worker.cjs +418 -46
- package/dist/engine/worker.js +418 -46
- package/dist/index.cjs +467 -50
- package/dist/index.js +467 -50
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -19,7 +19,7 @@ var VERSION;
|
|
|
19
19
|
var init_header = __esm({
|
|
20
20
|
"src/types/_header.ts"() {
|
|
21
21
|
"use strict";
|
|
22
|
-
VERSION = "0.
|
|
22
|
+
VERSION = "0.26.0";
|
|
23
23
|
}
|
|
24
24
|
});
|
|
25
25
|
|
|
@@ -327,19 +327,24 @@ var init_defaults = __esm({
|
|
|
327
327
|
* - `tests/rules/**` — rule test files contain expected-issue
|
|
328
328
|
* assertions, also meta-code.
|
|
329
329
|
*
|
|
330
|
-
* Three patterns
|
|
331
|
-
*
|
|
332
|
-
*
|
|
333
|
-
*
|
|
330
|
+
* Three patterns (broadened in v0.25.1 from the v0.25.0 narrow
|
|
331
|
+
* set, which missed `tests/engine/**`, `tests/cli/**`, and
|
|
332
|
+
* `snippet/**`), ~80 issues removed per self-scan. Combined
|
|
333
|
+
* with the v0.25.0 graded security cap, this restores the
|
|
334
|
+
* v9 plan's "security ≥ 80" criterion (unachievable in
|
|
335
|
+
* v0.24.0 due to 90 self-scan FPs collapsing the score to 0).
|
|
334
336
|
*
|
|
335
337
|
* Set `selfScan: { excludePaths: [] }` in `slopbrick.config.mjs`
|
|
336
338
|
* to opt out and scan every file (legacy behavior).
|
|
337
339
|
*/
|
|
338
340
|
selfScan: {
|
|
339
341
|
excludePaths: [
|
|
340
|
-
"src/rules/**",
|
|
341
|
-
|
|
342
|
-
"
|
|
342
|
+
"**/src/rules/**",
|
|
343
|
+
// rule definitions are meta-code
|
|
344
|
+
"**/snippet/**",
|
|
345
|
+
// RULE_HINTS examples are intentional bad code
|
|
346
|
+
"**/tests/**"
|
|
347
|
+
// all test files (fixtures + unit + integration)
|
|
343
348
|
]
|
|
344
349
|
}
|
|
345
350
|
};
|
|
@@ -30680,6 +30685,55 @@ var init_arraylist_vs_linkedlist = __esm({
|
|
|
30680
30685
|
}
|
|
30681
30686
|
});
|
|
30682
30687
|
|
|
30688
|
+
// src/rules/java/builder-overuse.ts
|
|
30689
|
+
var BUILDER_ANNOTATION_REGEX, FIELD_DECL_REGEX, DEFAULT_FIELD_COUNT_CAP, javaBuilderOveruseRule;
|
|
30690
|
+
var init_builder_overuse = __esm({
|
|
30691
|
+
"src/rules/java/builder-overuse.ts"() {
|
|
30692
|
+
"use strict";
|
|
30693
|
+
init_rule();
|
|
30694
|
+
BUILDER_ANNOTATION_REGEX = /@Builder\b/;
|
|
30695
|
+
FIELD_DECL_REGEX = /(?:private|public|protected)\s+(?:final\s+)?[\w<>,\s]+\s+(\w+)\s*[=;]/g;
|
|
30696
|
+
DEFAULT_FIELD_COUNT_CAP = 3;
|
|
30697
|
+
javaBuilderOveruseRule = createRule({
|
|
30698
|
+
id: "java/builder-overuse",
|
|
30699
|
+
category: "typo",
|
|
30700
|
+
severity: "low",
|
|
30701
|
+
aiSpecific: true,
|
|
30702
|
+
description: "@Builder on a class with few fields \u2014 plain constructor is simpler",
|
|
30703
|
+
create(_context) {
|
|
30704
|
+
return { fieldCountCap: DEFAULT_FIELD_COUNT_CAP };
|
|
30705
|
+
},
|
|
30706
|
+
analyze(context, facts) {
|
|
30707
|
+
const issues = [];
|
|
30708
|
+
const source = facts.v2?._source;
|
|
30709
|
+
if (!source) return issues;
|
|
30710
|
+
if (!/\.java$/i.test(facts.filePath)) return issues;
|
|
30711
|
+
BUILDER_ANNOTATION_REGEX.lastIndex = 0;
|
|
30712
|
+
const builderMatch = BUILDER_ANNOTATION_REGEX.exec(source);
|
|
30713
|
+
if (!builderMatch) return issues;
|
|
30714
|
+
const firstBuilderLine = source.slice(0, builderMatch.index).split("\n").length;
|
|
30715
|
+
FIELD_DECL_REGEX.lastIndex = 0;
|
|
30716
|
+
let fieldCount = 0;
|
|
30717
|
+
while (FIELD_DECL_REGEX.exec(source) !== null) {
|
|
30718
|
+
fieldCount++;
|
|
30719
|
+
}
|
|
30720
|
+
if (fieldCount > context.fieldCountCap) return issues;
|
|
30721
|
+
issues.push({
|
|
30722
|
+
ruleId: "java/builder-overuse",
|
|
30723
|
+
category: "typo",
|
|
30724
|
+
severity: "low",
|
|
30725
|
+
aiSpecific: true,
|
|
30726
|
+
message: `@Builder on a class with ${fieldCount} field(s) \u2014 plain constructor is simpler`,
|
|
30727
|
+
line: firstBuilderLine,
|
|
30728
|
+
column: 1,
|
|
30729
|
+
advice: "Use a plain constructor for classes with \u2264 3 fields. AI agents default to @Builder because their training data emphasizes the pattern. Builder adds Lombok dependency and a Builder inner class for every annotated class. Reference: java/builder-overuse v0.26.0."
|
|
30730
|
+
});
|
|
30731
|
+
return issues;
|
|
30732
|
+
}
|
|
30733
|
+
});
|
|
30734
|
+
}
|
|
30735
|
+
});
|
|
30736
|
+
|
|
30683
30737
|
// src/rules/java/empty-catch-block.ts
|
|
30684
30738
|
var SINGLE_LINE_EMPTY_CATCH_REGEX, javaEmptyCatchBlockRule;
|
|
30685
30739
|
var init_empty_catch_block = __esm({
|
|
@@ -30722,6 +30776,65 @@ var init_empty_catch_block = __esm({
|
|
|
30722
30776
|
}
|
|
30723
30777
|
});
|
|
30724
30778
|
|
|
30779
|
+
// src/rules/java/immutable-collection-preference.ts
|
|
30780
|
+
var IMMUTABLE_REGEX, MUTABLE_REGEX, DEFAULT_IMMUTABLE_THRESHOLD, DEFAULT_MUTABLE_CAP, javaImmutableCollectionPreferenceRule;
|
|
30781
|
+
var init_immutable_collection_preference = __esm({
|
|
30782
|
+
"src/rules/java/immutable-collection-preference.ts"() {
|
|
30783
|
+
"use strict";
|
|
30784
|
+
init_rule();
|
|
30785
|
+
IMMUTABLE_REGEX = /\b(List|Map|Set)\.of\s*\(/g;
|
|
30786
|
+
MUTABLE_REGEX = /new\s+(ArrayList|HashMap|HashSet|LinkedList|TreeMap)\s*[<(]/g;
|
|
30787
|
+
DEFAULT_IMMUTABLE_THRESHOLD = 5;
|
|
30788
|
+
DEFAULT_MUTABLE_CAP = 1;
|
|
30789
|
+
javaImmutableCollectionPreferenceRule = createRule({
|
|
30790
|
+
id: "java/immutable-collection-preference",
|
|
30791
|
+
category: "typo",
|
|
30792
|
+
severity: "low",
|
|
30793
|
+
aiSpecific: true,
|
|
30794
|
+
description: "Immutable factory method over-use \u2014 prefer mutable when collection will be modified",
|
|
30795
|
+
create(_context) {
|
|
30796
|
+
return {
|
|
30797
|
+
immutableThreshold: DEFAULT_IMMUTABLE_THRESHOLD,
|
|
30798
|
+
mutableCap: DEFAULT_MUTABLE_CAP
|
|
30799
|
+
};
|
|
30800
|
+
},
|
|
30801
|
+
analyze(context, facts) {
|
|
30802
|
+
const issues = [];
|
|
30803
|
+
const source = facts.v2?._source;
|
|
30804
|
+
if (!source) return issues;
|
|
30805
|
+
if (!/\.java$/i.test(facts.filePath)) return issues;
|
|
30806
|
+
IMMUTABLE_REGEX.lastIndex = 0;
|
|
30807
|
+
let immutableCount = 0;
|
|
30808
|
+
let firstIdx = 0;
|
|
30809
|
+
let m;
|
|
30810
|
+
while ((m = IMMUTABLE_REGEX.exec(source)) !== null) {
|
|
30811
|
+
immutableCount++;
|
|
30812
|
+
if (firstIdx === 0) firstIdx = m.index;
|
|
30813
|
+
}
|
|
30814
|
+
if (immutableCount < context.immutableThreshold) return issues;
|
|
30815
|
+
MUTABLE_REGEX.lastIndex = 0;
|
|
30816
|
+
let mutableCount = 0;
|
|
30817
|
+
while ((m = MUTABLE_REGEX.exec(source)) !== null) {
|
|
30818
|
+
mutableCount++;
|
|
30819
|
+
}
|
|
30820
|
+
if (mutableCount > context.mutableCap) return issues;
|
|
30821
|
+
const line = source.slice(0, firstIdx).split("\n").length;
|
|
30822
|
+
issues.push({
|
|
30823
|
+
ruleId: "java/immutable-collection-preference",
|
|
30824
|
+
category: "typo",
|
|
30825
|
+
severity: "low",
|
|
30826
|
+
aiSpecific: true,
|
|
30827
|
+
message: `${immutableCount} immutable factory calls (List/Map/Set.of) with only ${mutableCount} mutable collection \u2014 likely over-preferring immutability`,
|
|
30828
|
+
line,
|
|
30829
|
+
column: 1,
|
|
30830
|
+
advice: "Prefer mutable collections (new ArrayList<>()) when the collection will be modified later. AI agents default to List.of/Map.of/Set.of because their training data emphasizes functional-style Java. Reference: java/immutable-collection-preference v0.26.0."
|
|
30831
|
+
});
|
|
30832
|
+
return issues;
|
|
30833
|
+
}
|
|
30834
|
+
});
|
|
30835
|
+
}
|
|
30836
|
+
});
|
|
30837
|
+
|
|
30725
30838
|
// src/rules/java/legacy-date-api.ts
|
|
30726
30839
|
var LEGACY_IMPORT_REGEX, LEGACY_USAGE_REGEX, CALENDAR_GET_INSTANCE_REGEX, javaLegacyDateApiRule;
|
|
30727
30840
|
var init_legacy_date_api = __esm({
|
|
@@ -30798,6 +30911,59 @@ var init_legacy_date_api = __esm({
|
|
|
30798
30911
|
}
|
|
30799
30912
|
});
|
|
30800
30913
|
|
|
30914
|
+
// src/rules/java/optional-overuse.ts
|
|
30915
|
+
var OR_ELSE_THROW_REGEX, NULL_CHECK_REGEX, DEFAULT_THRESHOLD, javaOptionalOveruseRule;
|
|
30916
|
+
var init_optional_overuse = __esm({
|
|
30917
|
+
"src/rules/java/optional-overuse.ts"() {
|
|
30918
|
+
"use strict";
|
|
30919
|
+
init_rule();
|
|
30920
|
+
OR_ELSE_THROW_REGEX = /\.orElseThrow\s*\(/g;
|
|
30921
|
+
NULL_CHECK_REGEX = /Objects\.requireNonNull\s*\(|if\s*\([^)]*==\s*null\)\s*(?:throw|return)/g;
|
|
30922
|
+
DEFAULT_THRESHOLD = 2;
|
|
30923
|
+
javaOptionalOveruseRule = createRule({
|
|
30924
|
+
id: "java/optional-overuse",
|
|
30925
|
+
category: "typo",
|
|
30926
|
+
severity: "low",
|
|
30927
|
+
aiSpecific: true,
|
|
30928
|
+
description: "Optional chain over-use \u2014 null check or Objects.requireNonNull is faster",
|
|
30929
|
+
create(_context) {
|
|
30930
|
+
return { threshold: DEFAULT_THRESHOLD };
|
|
30931
|
+
},
|
|
30932
|
+
analyze(context, facts) {
|
|
30933
|
+
const issues = [];
|
|
30934
|
+
const source = facts.v2?._source;
|
|
30935
|
+
if (!source) return issues;
|
|
30936
|
+
if (!/\.java$/i.test(facts.filePath)) return issues;
|
|
30937
|
+
OR_ELSE_THROW_REGEX.lastIndex = 0;
|
|
30938
|
+
let orElseThrowCount = 0;
|
|
30939
|
+
let firstIdx = 0;
|
|
30940
|
+
let m;
|
|
30941
|
+
while ((m = OR_ELSE_THROW_REGEX.exec(source)) !== null) {
|
|
30942
|
+
orElseThrowCount++;
|
|
30943
|
+
if (firstIdx === 0) firstIdx = m.index;
|
|
30944
|
+
}
|
|
30945
|
+
if (orElseThrowCount < context.threshold) return issues;
|
|
30946
|
+
NULL_CHECK_REGEX.lastIndex = 0;
|
|
30947
|
+
const nullCheckCount = (source.match(NULL_CHECK_REGEX) ?? []).length;
|
|
30948
|
+
const optionalRatio = orElseThrowCount / Math.max(orElseThrowCount + nullCheckCount, 1);
|
|
30949
|
+
if (optionalRatio < 0.6) return issues;
|
|
30950
|
+
const line = source.slice(0, firstIdx).split("\n").length;
|
|
30951
|
+
issues.push({
|
|
30952
|
+
ruleId: "java/optional-overuse",
|
|
30953
|
+
category: "typo",
|
|
30954
|
+
severity: "low",
|
|
30955
|
+
aiSpecific: true,
|
|
30956
|
+
message: `${orElseThrowCount} .orElseThrow() calls with ${nullCheckCount} null checks \u2014 Optional chain over-use`,
|
|
30957
|
+
line,
|
|
30958
|
+
column: 1,
|
|
30959
|
+
advice: 'Use Objects.requireNonNull(x, "msg") for null checks; reserve Optional for return values. AI agents default to Optional chains because their training data emphasizes null-safety. Real Java code uses null checks in hot paths. Reference: java/optional-overuse v0.26.0.'
|
|
30960
|
+
});
|
|
30961
|
+
return issues;
|
|
30962
|
+
}
|
|
30963
|
+
});
|
|
30964
|
+
}
|
|
30965
|
+
});
|
|
30966
|
+
|
|
30801
30967
|
// src/rules/java/raw-type-overuse.ts
|
|
30802
30968
|
var RAW_TYPE_REGEX, javaRawTypeOveruseRule;
|
|
30803
30969
|
var init_raw_type_overuse = __esm({
|
|
@@ -30841,6 +31007,75 @@ var init_raw_type_overuse = __esm({
|
|
|
30841
31007
|
}
|
|
30842
31008
|
});
|
|
30843
31009
|
|
|
31010
|
+
// src/rules/java/stream-overuse.ts
|
|
31011
|
+
var STREAM_OPS, DEFAULT_CHAIN_THRESHOLD, javaStreamOveruseRule;
|
|
31012
|
+
var init_stream_overuse = __esm({
|
|
31013
|
+
"src/rules/java/stream-overuse.ts"() {
|
|
31014
|
+
"use strict";
|
|
31015
|
+
init_rule();
|
|
31016
|
+
STREAM_OPS = [
|
|
31017
|
+
".map(",
|
|
31018
|
+
".filter(",
|
|
31019
|
+
".flatMap(",
|
|
31020
|
+
".collect(",
|
|
31021
|
+
".reduce(",
|
|
31022
|
+
".sorted(",
|
|
31023
|
+
".distinct(",
|
|
31024
|
+
".limit(",
|
|
31025
|
+
".skip(",
|
|
31026
|
+
".anyMatch(",
|
|
31027
|
+
".allMatch(",
|
|
31028
|
+
".noneMatch(",
|
|
31029
|
+
".findFirst(",
|
|
31030
|
+
".findAny("
|
|
31031
|
+
];
|
|
31032
|
+
DEFAULT_CHAIN_THRESHOLD = 3;
|
|
31033
|
+
javaStreamOveruseRule = createRule({
|
|
31034
|
+
id: "java/stream-overuse",
|
|
31035
|
+
category: "typo",
|
|
31036
|
+
severity: "low",
|
|
31037
|
+
aiSpecific: true,
|
|
31038
|
+
description: "Stream API chain over-use \u2014 for-loop is faster for simple transformations",
|
|
31039
|
+
create(_context) {
|
|
31040
|
+
return { chainThreshold: DEFAULT_CHAIN_THRESHOLD };
|
|
31041
|
+
},
|
|
31042
|
+
analyze(context, facts) {
|
|
31043
|
+
const issues = [];
|
|
31044
|
+
const source = facts.v2?._source;
|
|
31045
|
+
if (!source) return issues;
|
|
31046
|
+
if (!/\.java$/i.test(facts.filePath)) return issues;
|
|
31047
|
+
const lines = source.split("\n");
|
|
31048
|
+
const streamOpPattern = new RegExp(STREAM_OPS.map((op) => op.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|"), "g");
|
|
31049
|
+
let firstOffendingLine = 0;
|
|
31050
|
+
let firstOffendingCount = 0;
|
|
31051
|
+
for (let i = 0; i < lines.length; i++) {
|
|
31052
|
+
const line = lines[i] ?? "";
|
|
31053
|
+
if (line.trim().startsWith("//") || line.trim().startsWith("*")) continue;
|
|
31054
|
+
const matches = line.match(streamOpPattern);
|
|
31055
|
+
if (matches && matches.length >= context.chainThreshold) {
|
|
31056
|
+
if (firstOffendingLine === 0) {
|
|
31057
|
+
firstOffendingLine = i + 1;
|
|
31058
|
+
firstOffendingCount = matches.length;
|
|
31059
|
+
}
|
|
31060
|
+
}
|
|
31061
|
+
}
|
|
31062
|
+
if (firstOffendingLine === 0) return issues;
|
|
31063
|
+
issues.push({
|
|
31064
|
+
ruleId: "java/stream-overuse",
|
|
31065
|
+
category: "typo",
|
|
31066
|
+
severity: "low",
|
|
31067
|
+
aiSpecific: true,
|
|
31068
|
+
message: `${firstOffendingCount} stream operations on a single line \u2014 for-loop is faster`,
|
|
31069
|
+
line: firstOffendingLine,
|
|
31070
|
+
column: 1,
|
|
31071
|
+
advice: "Prefer a for-loop for simple transformations. AI agents default to Stream API chains because their training data emphasizes functional-style Java. Stream chains allocate intermediate objects; for small collections, a for-loop is faster and more readable. Reference: java/stream-overuse v0.26.0."
|
|
31072
|
+
});
|
|
31073
|
+
return issues;
|
|
31074
|
+
}
|
|
31075
|
+
});
|
|
31076
|
+
}
|
|
31077
|
+
});
|
|
31078
|
+
|
|
30844
31079
|
// src/rules/java/string-concat-loop.ts
|
|
30845
31080
|
var STRING_CONCAT_REGEX, javaStringConcatLoopRule;
|
|
30846
31081
|
var init_string_concat_loop = __esm({
|
|
@@ -30885,13 +31120,13 @@ var init_string_concat_loop = __esm({
|
|
|
30885
31120
|
});
|
|
30886
31121
|
|
|
30887
31122
|
// src/rules/java/system-out-println.ts
|
|
30888
|
-
var PRINTLN_REGEX,
|
|
31123
|
+
var PRINTLN_REGEX, DEFAULT_THRESHOLD2, javaSystemOutPrintlnRule;
|
|
30889
31124
|
var init_system_out_println = __esm({
|
|
30890
31125
|
"src/rules/java/system-out-println.ts"() {
|
|
30891
31126
|
"use strict";
|
|
30892
31127
|
init_rule();
|
|
30893
31128
|
PRINTLN_REGEX = /System\.out\.println\s*\(/g;
|
|
30894
|
-
|
|
31129
|
+
DEFAULT_THRESHOLD2 = 1;
|
|
30895
31130
|
javaSystemOutPrintlnRule = createRule({
|
|
30896
31131
|
id: "java/system-out-println",
|
|
30897
31132
|
category: "typo",
|
|
@@ -30899,7 +31134,7 @@ var init_system_out_println = __esm({
|
|
|
30899
31134
|
aiSpecific: true,
|
|
30900
31135
|
description: "System.out.println in production code \u2014 use a logger (SLF4J, Log4j, etc.)",
|
|
30901
31136
|
create(_context) {
|
|
30902
|
-
return { threshold:
|
|
31137
|
+
return { threshold: DEFAULT_THRESHOLD2 };
|
|
30903
31138
|
},
|
|
30904
31139
|
analyze(context, facts) {
|
|
30905
31140
|
const issues = [];
|
|
@@ -30934,6 +31169,63 @@ var init_system_out_println = __esm({
|
|
|
30934
31169
|
}
|
|
30935
31170
|
});
|
|
30936
31171
|
|
|
31172
|
+
// src/rules/java/verbose-javadoc.ts
|
|
31173
|
+
var TAG_REGEX, DEFAULT_TAG_THRESHOLD, DEFAULT_BODY_LENGTH_CAP, javaVerboseJavadocRule;
|
|
31174
|
+
var init_verbose_javadoc = __esm({
|
|
31175
|
+
"src/rules/java/verbose-javadoc.ts"() {
|
|
31176
|
+
"use strict";
|
|
31177
|
+
init_rule();
|
|
31178
|
+
TAG_REGEX = /@(param|return|throws)\b/g;
|
|
31179
|
+
DEFAULT_TAG_THRESHOLD = 3;
|
|
31180
|
+
DEFAULT_BODY_LENGTH_CAP = 5;
|
|
31181
|
+
javaVerboseJavadocRule = createRule({
|
|
31182
|
+
id: "java/verbose-javadoc",
|
|
31183
|
+
category: "typo",
|
|
31184
|
+
severity: "low",
|
|
31185
|
+
aiSpecific: true,
|
|
31186
|
+
description: "Excessive Javadoc tags on trivial methods \u2014 over-documentation is an AI fingerprint",
|
|
31187
|
+
create(_context) {
|
|
31188
|
+
return {
|
|
31189
|
+
tagThreshold: DEFAULT_TAG_THRESHOLD,
|
|
31190
|
+
bodyLengthCap: DEFAULT_BODY_LENGTH_CAP
|
|
31191
|
+
};
|
|
31192
|
+
},
|
|
31193
|
+
analyze(context, facts) {
|
|
31194
|
+
const issues = [];
|
|
31195
|
+
const source = facts.v2?._source;
|
|
31196
|
+
if (!source) return issues;
|
|
31197
|
+
if (!/\.java$/i.test(facts.filePath)) return issues;
|
|
31198
|
+
TAG_REGEX.lastIndex = 0;
|
|
31199
|
+
let tagCount = 0;
|
|
31200
|
+
let firstTagLine = 0;
|
|
31201
|
+
let m;
|
|
31202
|
+
while ((m = TAG_REGEX.exec(source)) !== null) {
|
|
31203
|
+
tagCount++;
|
|
31204
|
+
if (firstTagLine === 0) {
|
|
31205
|
+
firstTagLine = source.slice(0, m.index).split("\n").length;
|
|
31206
|
+
}
|
|
31207
|
+
}
|
|
31208
|
+
if (tagCount < context.tagThreshold) return issues;
|
|
31209
|
+
const lineCount = source.split("\n").length;
|
|
31210
|
+
const tagDensity = tagCount / Math.max(lineCount, 1);
|
|
31211
|
+
if (tagDensity < 0.05) return issues;
|
|
31212
|
+
if (lineCount > 200) return issues;
|
|
31213
|
+
issues.push({
|
|
31214
|
+
ruleId: "java/verbose-javadoc",
|
|
31215
|
+
category: "typo",
|
|
31216
|
+
severity: "low",
|
|
31217
|
+
aiSpecific: true,
|
|
31218
|
+
message: `${tagCount} Javadoc tags in ${lineCount} lines (density ${(tagDensity * 100).toFixed(1)}%) \u2014 likely over-documented`,
|
|
31219
|
+
line: firstTagLine,
|
|
31220
|
+
column: 1,
|
|
31221
|
+
advice: "Skip Javadoc on trivial methods (getters, setters, builders). AI agents default to over-documentation because their training data has countless textbook Javadoc examples. Real Java code limits Javadoc to public API surface. Reference: java/verbose-javadoc v0.26.0."
|
|
31222
|
+
});
|
|
31223
|
+
return issues;
|
|
31224
|
+
}
|
|
31225
|
+
});
|
|
31226
|
+
}
|
|
31227
|
+
});
|
|
31228
|
+
|
|
30937
31229
|
// src/rules/kotlin/coroutine-global-scope.ts
|
|
30938
31230
|
var GLOBAL_SCOPE_REGEX, kotlinCoroutineGlobalScopeRule;
|
|
30939
31231
|
var init_coroutine_global_scope = __esm({
|
|
@@ -31098,13 +31390,13 @@ var init_object_singleton_misuse = __esm({
|
|
|
31098
31390
|
});
|
|
31099
31391
|
|
|
31100
31392
|
// src/rules/kotlin/println-debug.ts
|
|
31101
|
-
var PRINTLN_REGEX2,
|
|
31393
|
+
var PRINTLN_REGEX2, DEFAULT_THRESHOLD3, kotlinPrintlnDebugRule;
|
|
31102
31394
|
var init_println_debug = __esm({
|
|
31103
31395
|
"src/rules/kotlin/println-debug.ts"() {
|
|
31104
31396
|
"use strict";
|
|
31105
31397
|
init_rule();
|
|
31106
31398
|
PRINTLN_REGEX2 = /^\s*println\s*\(/gm;
|
|
31107
|
-
|
|
31399
|
+
DEFAULT_THRESHOLD3 = 1;
|
|
31108
31400
|
kotlinPrintlnDebugRule = createRule({
|
|
31109
31401
|
id: "kotlin/println-debug",
|
|
31110
31402
|
category: "typo",
|
|
@@ -31112,7 +31404,7 @@ var init_println_debug = __esm({
|
|
|
31112
31404
|
aiSpecific: true,
|
|
31113
31405
|
description: "println(...) in production code \u2014 use Timber, android.util.Log, or an SLF4J facade",
|
|
31114
31406
|
create(_context) {
|
|
31115
|
-
return { threshold:
|
|
31407
|
+
return { threshold: DEFAULT_THRESHOLD3 };
|
|
31116
31408
|
},
|
|
31117
31409
|
analyze(context, facts) {
|
|
31118
31410
|
const issues = [];
|
|
@@ -40817,13 +41109,13 @@ var init_implicitly_unwrapped_optional = __esm({
|
|
|
40817
41109
|
});
|
|
40818
41110
|
|
|
40819
41111
|
// src/rules/swift/print-debug.ts
|
|
40820
|
-
var PRINT_REGEX,
|
|
41112
|
+
var PRINT_REGEX, DEFAULT_THRESHOLD4, swiftPrintDebugRule;
|
|
40821
41113
|
var init_print_debug = __esm({
|
|
40822
41114
|
"src/rules/swift/print-debug.ts"() {
|
|
40823
41115
|
"use strict";
|
|
40824
41116
|
init_rule();
|
|
40825
41117
|
PRINT_REGEX = /\bprint\s*\(/g;
|
|
40826
|
-
|
|
41118
|
+
DEFAULT_THRESHOLD4 = 1;
|
|
40827
41119
|
swiftPrintDebugRule = createRule({
|
|
40828
41120
|
id: "swift/print-debug",
|
|
40829
41121
|
category: "typo",
|
|
@@ -40831,7 +41123,7 @@ var init_print_debug = __esm({
|
|
|
40831
41123
|
aiSpecific: true,
|
|
40832
41124
|
description: "print(...) in production Swift \u2014 use Logger (os.log) for level-controlled output",
|
|
40833
41125
|
create(_context) {
|
|
40834
|
-
return { threshold:
|
|
41126
|
+
return { threshold: DEFAULT_THRESHOLD4 };
|
|
40835
41127
|
},
|
|
40836
41128
|
analyze(context, facts) {
|
|
40837
41129
|
const issues = [];
|
|
@@ -46582,11 +46874,16 @@ var init_builtins = __esm({
|
|
|
46582
46874
|
init_nil_slice_vs_empty();
|
|
46583
46875
|
init_struct_tag_inconsistency();
|
|
46584
46876
|
init_arraylist_vs_linkedlist();
|
|
46877
|
+
init_builder_overuse();
|
|
46585
46878
|
init_empty_catch_block();
|
|
46879
|
+
init_immutable_collection_preference();
|
|
46586
46880
|
init_legacy_date_api();
|
|
46881
|
+
init_optional_overuse();
|
|
46587
46882
|
init_raw_type_overuse();
|
|
46883
|
+
init_stream_overuse();
|
|
46588
46884
|
init_string_concat_loop();
|
|
46589
46885
|
init_system_out_println();
|
|
46886
|
+
init_verbose_javadoc();
|
|
46590
46887
|
init_coroutine_global_scope();
|
|
46591
46888
|
init_data_class_defaults_overuse();
|
|
46592
46889
|
init_object_singleton_misuse();
|
|
@@ -46717,11 +47014,16 @@ var init_builtins = __esm({
|
|
|
46717
47014
|
goNilSliceVsEmptyRule,
|
|
46718
47015
|
goStructTagInconsistencyRule,
|
|
46719
47016
|
javaArraylistVsLinkedlistRule,
|
|
47017
|
+
javaBuilderOveruseRule,
|
|
46720
47018
|
javaEmptyCatchBlockRule,
|
|
47019
|
+
javaImmutableCollectionPreferenceRule,
|
|
46721
47020
|
javaLegacyDateApiRule,
|
|
47021
|
+
javaOptionalOveruseRule,
|
|
46722
47022
|
javaRawTypeOveruseRule,
|
|
47023
|
+
javaStreamOveruseRule,
|
|
46723
47024
|
javaStringConcatLoopRule,
|
|
46724
47025
|
javaSystemOutPrintlnRule,
|
|
47026
|
+
javaVerboseJavadocRule,
|
|
46725
47027
|
kotlinCoroutineGlobalScopeRule,
|
|
46726
47028
|
kotlinDataClassDefaultsOveruseRule,
|
|
46727
47029
|
kotlinObjectSingletonMisuseRule,
|
|
@@ -49889,13 +50191,13 @@ var init_signal_strength = __esm({
|
|
|
49889
50191
|
defaultOff: true
|
|
49890
50192
|
},
|
|
49891
50193
|
"java/arraylist-vs-linkedlist": {
|
|
49892
|
-
recall:
|
|
49893
|
-
fpRate:
|
|
49894
|
-
ratio:
|
|
49895
|
-
precision: 0,
|
|
49896
|
-
lastCalibratedAt: "2026-07-
|
|
50194
|
+
recall: 35e-4,
|
|
50195
|
+
fpRate: 94e-4,
|
|
50196
|
+
ratio: 0.37,
|
|
50197
|
+
precision: 0.0446,
|
|
50198
|
+
lastCalibratedAt: "2026-07-02T19:34:00Z",
|
|
49897
50199
|
verdict: "DORMANT",
|
|
49898
|
-
_calibrationNote: "v0.20: new rule (new LinkedList<>() \u2014 use ArrayList
|
|
50200
|
+
_calibrationNote: "v9 Java corpus calibration (v0.25.0, 2026-07-02): 81891 neg + 10305 pos Java files = 92196 total. v9 TP=36, FP=771, P=4.46%, FPR=0.94%, recall=0.35%, ratio=0.37, lift=P/FPR=4.74. Rule fires more on legacy enterprise Java (neg) than on AI/ML-integration Java (pos) because modern Java idiom defaults to ArrayList. v0.20: new rule (new LinkedList<>() \u2014 use ArrayList, Effective Java Item 28).",
|
|
49899
50201
|
aiSpecific: true,
|
|
49900
50202
|
_v7Verdict: "DORMANT",
|
|
49901
50203
|
_v7Lift: 1,
|
|
@@ -49904,16 +50206,21 @@ var init_signal_strength = __esm({
|
|
|
49904
50206
|
_v7Precision: 0,
|
|
49905
50207
|
_v8Verdict: "DORMANT",
|
|
49906
50208
|
_v8Lift: 1,
|
|
50209
|
+
_v9Verdict: "DORMANT",
|
|
50210
|
+
_v9Lift: 4.74,
|
|
50211
|
+
_v9Recall: 35e-4,
|
|
50212
|
+
_v9FpRate: 94e-4,
|
|
50213
|
+
_v9Precision: 0.0446,
|
|
49907
50214
|
defaultOff: true
|
|
49908
50215
|
},
|
|
49909
50216
|
"java/empty-catch-block": {
|
|
49910
|
-
recall:
|
|
49911
|
-
fpRate: 0,
|
|
49912
|
-
ratio:
|
|
49913
|
-
precision:
|
|
49914
|
-
lastCalibratedAt: "2026-07-
|
|
50217
|
+
recall: 8e-3,
|
|
50218
|
+
fpRate: 0.1118,
|
|
50219
|
+
ratio: 0.07,
|
|
50220
|
+
precision: 89e-4,
|
|
50221
|
+
lastCalibratedAt: "2026-07-02T19:34:00Z",
|
|
49915
50222
|
verdict: "DORMANT",
|
|
49916
|
-
_calibrationNote: "v0.
|
|
50223
|
+
_calibrationNote: "v9 Java corpus calibration (v0.25.0, 2026-07-02): 81891 neg + 10305 pos Java files. v9 TP=82, FP=9159, P=0.89%, FPR=11.18%, recall=0.80%, ratio=0.07, lift=P/FPR=0.08. Strongly INVERTED: empty catch blocks are 14x more common in legacy enterprise Java than in AI/Java-modern pos repos. Heuristic likely needs to be tightened (e.g., require at least a comment) before it can serve as a meaningful discriminator. v0.20: new rule.",
|
|
49917
50224
|
aiSpecific: true,
|
|
49918
50225
|
_v7Verdict: "DORMANT",
|
|
49919
50226
|
_v7Lift: 1,
|
|
@@ -49922,16 +50229,21 @@ var init_signal_strength = __esm({
|
|
|
49922
50229
|
_v7Precision: 0,
|
|
49923
50230
|
_v8Verdict: "DORMANT",
|
|
49924
50231
|
_v8Lift: 1,
|
|
50232
|
+
_v9Verdict: "DORMANT",
|
|
50233
|
+
_v9Lift: 0.08,
|
|
50234
|
+
_v9Recall: 8e-3,
|
|
50235
|
+
_v9FpRate: 0.1118,
|
|
50236
|
+
_v9Precision: 89e-4,
|
|
49925
50237
|
defaultOff: true
|
|
49926
50238
|
},
|
|
49927
50239
|
"java/legacy-date-api": {
|
|
49928
|
-
recall: 0,
|
|
49929
|
-
fpRate: 0,
|
|
49930
|
-
ratio:
|
|
49931
|
-
precision: 0,
|
|
49932
|
-
lastCalibratedAt: "2026-07-
|
|
50240
|
+
recall: 0.0285,
|
|
50241
|
+
fpRate: 0.0511,
|
|
50242
|
+
ratio: 0.56,
|
|
50243
|
+
precision: 0.0657,
|
|
50244
|
+
lastCalibratedAt: "2026-07-02T19:34:00Z",
|
|
49933
50245
|
verdict: "DORMANT",
|
|
49934
|
-
_calibrationNote: "v0.
|
|
50246
|
+
_calibrationNote: "v9 Java corpus calibration (v0.25.0, 2026-07-02): 81891 neg + 10305 pos Java files. v9 TP=294, FP=4181, P=6.57%, FPR=5.11%, recall=2.85%, ratio=0.56, lift=P/FPR=1.29. INVERTED-to-NOISY: legacy date API is more common in older enterprise Java (neg) than in modern AI/Java repos (pos). The heuristic correctly flags the legacy pattern, but the legacy pattern is over-represented in the neg baseline (older codebases). v0.20: new rule.",
|
|
49935
50247
|
aiSpecific: true,
|
|
49936
50248
|
_v7Verdict: "DORMANT",
|
|
49937
50249
|
_v7Lift: 1,
|
|
@@ -49940,16 +50252,101 @@ var init_signal_strength = __esm({
|
|
|
49940
50252
|
_v7Precision: 0,
|
|
49941
50253
|
_v8Verdict: "DORMANT",
|
|
49942
50254
|
_v8Lift: 1,
|
|
50255
|
+
_v9Verdict: "DORMANT",
|
|
50256
|
+
_v9Lift: 1.29,
|
|
50257
|
+
_v9Recall: 0.0285,
|
|
50258
|
+
_v9FpRate: 0.0511,
|
|
50259
|
+
_v9Precision: 0.0657,
|
|
49943
50260
|
defaultOff: true
|
|
49944
50261
|
},
|
|
49945
|
-
"java/
|
|
50262
|
+
"java/verbose-javadoc": {
|
|
49946
50263
|
recall: 0,
|
|
49947
50264
|
fpRate: 0,
|
|
49948
50265
|
ratio: 1,
|
|
49949
50266
|
precision: 0,
|
|
49950
|
-
lastCalibratedAt: "2026-07-
|
|
50267
|
+
lastCalibratedAt: "2026-07-03T00:00:00Z",
|
|
50268
|
+
verdict: "DORMANT",
|
|
50269
|
+
_calibrationNote: "v0.26.0: new positive AI-signal rule. Triggers when a small Java file (< 200 lines) has 3+ Javadoc tags with density >= 0.05. Calibration pending v9 Java corpus re-run; placeholder values until then. v0.20.0: anti-pattern design was wrong (humans write more Javadoc on trivial methods because their training data has it). v0.26.0: redesigned as positive signal (AI over-documents trivial methods). Reference: java/verbose-javadoc v0.26.0.",
|
|
50270
|
+
aiSpecific: true,
|
|
50271
|
+
_v9Verdict: "DORMANT",
|
|
50272
|
+
_v9Lift: 1,
|
|
50273
|
+
_v9Recall: 0,
|
|
50274
|
+
_v9FpRate: 0,
|
|
50275
|
+
_v9Precision: 0,
|
|
50276
|
+
defaultOff: true
|
|
50277
|
+
},
|
|
50278
|
+
"java/optional-overuse": {
|
|
50279
|
+
recall: 0,
|
|
50280
|
+
fpRate: 0,
|
|
50281
|
+
ratio: 1,
|
|
50282
|
+
precision: 0,
|
|
50283
|
+
lastCalibratedAt: "2026-07-03T00:00:00Z",
|
|
49951
50284
|
verdict: "DORMANT",
|
|
49952
|
-
_calibrationNote: "v0.
|
|
50285
|
+
_calibrationNote: "v0.26.0: new positive AI-signal rule. Triggers when a Java file has 2+ .orElseThrow() calls AND 0 Objects.requireNonNull()/null checks (optionalRatio > 0.6). Calibration pending v9 Java corpus re-run; placeholder values until then. v0.26.0: redesigned as positive signal (AI chains Optional.ofNullable().orElseThrow() where null checks would be cleaner). Reference: java/optional-overuse v0.26.0.",
|
|
50286
|
+
aiSpecific: true,
|
|
50287
|
+
_v9Verdict: "DORMANT",
|
|
50288
|
+
_v9Lift: 1,
|
|
50289
|
+
_v9Recall: 0,
|
|
50290
|
+
_v9FpRate: 0,
|
|
50291
|
+
_v9Precision: 0,
|
|
50292
|
+
defaultOff: true
|
|
50293
|
+
},
|
|
50294
|
+
"java/immutable-collection-preference": {
|
|
50295
|
+
recall: 0,
|
|
50296
|
+
fpRate: 0,
|
|
50297
|
+
ratio: 1,
|
|
50298
|
+
precision: 0,
|
|
50299
|
+
lastCalibratedAt: "2026-07-03T00:00:00Z",
|
|
50300
|
+
verdict: "DORMANT",
|
|
50301
|
+
_calibrationNote: "v0.26.0: new positive AI-signal rule. Triggers when a Java file has 5+ List.of/Map.of/Set.of calls AND < 1 new ArrayList/HashMap/HashSet/LinkedList/TreeMap calls. Calibration pending v9 Java corpus re-run; placeholder values until then. v0.26.0: redesigned as positive signal (AI defaults to immutable factory methods). Reference: java/immutable-collection-preference v0.26.0.",
|
|
50302
|
+
aiSpecific: true,
|
|
50303
|
+
_v9Verdict: "DORMANT",
|
|
50304
|
+
_v9Lift: 1,
|
|
50305
|
+
_v9Recall: 0,
|
|
50306
|
+
_v9FpRate: 0,
|
|
50307
|
+
_v9Precision: 0,
|
|
50308
|
+
defaultOff: true
|
|
50309
|
+
},
|
|
50310
|
+
"java/builder-overuse": {
|
|
50311
|
+
recall: 0,
|
|
50312
|
+
fpRate: 0,
|
|
50313
|
+
ratio: 1,
|
|
50314
|
+
precision: 0,
|
|
50315
|
+
lastCalibratedAt: "2026-07-03T00:00:00Z",
|
|
50316
|
+
verdict: "DORMANT",
|
|
50317
|
+
_calibrationNote: "v0.26.0: new positive AI-signal rule. Triggers when @Builder annotation (Lombok) is used on a class with <= 3 fields. Calibration pending v9 Java corpus re-run; placeholder values until then. v0.26.0: redesigned as positive signal (AI defaults to Builder pattern even for simple data classes). Reference: java/builder-overuse v0.26.0.",
|
|
50318
|
+
aiSpecific: true,
|
|
50319
|
+
_v9Verdict: "DORMANT",
|
|
50320
|
+
_v9Lift: 1,
|
|
50321
|
+
_v9Recall: 0,
|
|
50322
|
+
_v9FpRate: 0,
|
|
50323
|
+
_v9Precision: 0,
|
|
50324
|
+
defaultOff: true
|
|
50325
|
+
},
|
|
50326
|
+
"java/stream-overuse": {
|
|
50327
|
+
recall: 0,
|
|
50328
|
+
fpRate: 0,
|
|
50329
|
+
ratio: 1,
|
|
50330
|
+
precision: 0,
|
|
50331
|
+
lastCalibratedAt: "2026-07-03T00:00:00Z",
|
|
50332
|
+
verdict: "DORMANT",
|
|
50333
|
+
_calibrationNote: "v0.26.0: new positive AI-signal rule. Triggers when a single line has 3+ Stream API operations (.map, .filter, .flatMap, .collect, .reduce, .sorted, .distinct, .limit, .skip, .anyMatch, .allMatch, .noneMatch, .findFirst, .findAny). Calibration pending v9 Java corpus re-run; placeholder values until then. v0.26.0: redesigned as positive signal (AI chains Stream API for everything). Reference: java/stream-overuse v0.26.0.",
|
|
50334
|
+
aiSpecific: true,
|
|
50335
|
+
_v9Verdict: "DORMANT",
|
|
50336
|
+
_v9Lift: 1,
|
|
50337
|
+
_v9Recall: 0,
|
|
50338
|
+
_v9FpRate: 0,
|
|
50339
|
+
_v9Precision: 0,
|
|
50340
|
+
defaultOff: true
|
|
50341
|
+
},
|
|
50342
|
+
"java/raw-type-overuse": {
|
|
50343
|
+
recall: 0.1093,
|
|
50344
|
+
fpRate: 0.2041,
|
|
50345
|
+
ratio: 0.54,
|
|
50346
|
+
precision: 0.0632,
|
|
50347
|
+
lastCalibratedAt: "2026-07-02T19:34:00Z",
|
|
50348
|
+
verdict: "DORMANT",
|
|
50349
|
+
_calibrationNote: "v9 Java corpus calibration (v0.25.0, 2026-07-02): 81891 neg + 10305 pos Java files. v9 TP=1126, FP=16712, P=6.32%, FPR=20.41%, recall=10.93%, ratio=0.54, lift=P/FPR=0.31. Strongly INVERTED: raw types (no generics) are 2x more common in legacy enterprise Java (neg) than in modern Java repos (pos). Heuristic is correctly identifying the legacy anti-pattern, but it's an age marker more than an AI-fingerprint. v0.20: new rule.",
|
|
49953
50350
|
aiSpecific: true,
|
|
49954
50351
|
_v7Verdict: "DORMANT",
|
|
49955
50352
|
_v7Lift: 1,
|
|
@@ -49958,16 +50355,21 @@ var init_signal_strength = __esm({
|
|
|
49958
50355
|
_v7Precision: 0,
|
|
49959
50356
|
_v8Verdict: "DORMANT",
|
|
49960
50357
|
_v8Lift: 1,
|
|
50358
|
+
_v9Verdict: "DORMANT",
|
|
50359
|
+
_v9Lift: 0.31,
|
|
50360
|
+
_v9Recall: 0.1093,
|
|
50361
|
+
_v9FpRate: 0.2041,
|
|
50362
|
+
_v9Precision: 0.0632,
|
|
49961
50363
|
defaultOff: true
|
|
49962
50364
|
},
|
|
49963
50365
|
"java/string-concat-loop": {
|
|
49964
|
-
recall:
|
|
49965
|
-
fpRate: 0,
|
|
49966
|
-
ratio:
|
|
49967
|
-
precision: 0,
|
|
49968
|
-
lastCalibratedAt: "2026-07-
|
|
50366
|
+
recall: 46e-4,
|
|
50367
|
+
fpRate: 0.0358,
|
|
50368
|
+
ratio: 0.13,
|
|
50369
|
+
precision: 0.0158,
|
|
50370
|
+
lastCalibratedAt: "2026-07-02T19:34:00Z",
|
|
49969
50371
|
verdict: "DORMANT",
|
|
49970
|
-
_calibrationNote: "v0.
|
|
50372
|
+
_calibrationNote: "v9 Java corpus calibration (v0.25.0, 2026-07-02): 81891 neg + 10305 pos Java files. v9 TP=47, FP=2933, P=1.58%, FPR=3.58%, recall=0.46%, ratio=0.13, lift=P/FPR=0.44. Strongly INVERTED: string concatenation in a loop is 8x more common in legacy enterprise Java (neg) than in AI/ML/Java-modern pos repos. Modern Java training data and modern IDE warnings discourage the pattern. v0.20: new rule.",
|
|
49971
50373
|
aiSpecific: true,
|
|
49972
50374
|
_v7Verdict: "DORMANT",
|
|
49973
50375
|
_v7Lift: 1,
|
|
@@ -49976,16 +50378,21 @@ var init_signal_strength = __esm({
|
|
|
49976
50378
|
_v7Precision: 0,
|
|
49977
50379
|
_v8Verdict: "DORMANT",
|
|
49978
50380
|
_v8Lift: 1,
|
|
50381
|
+
_v9Verdict: "DORMANT",
|
|
50382
|
+
_v9Lift: 0.44,
|
|
50383
|
+
_v9Recall: 46e-4,
|
|
50384
|
+
_v9FpRate: 0.0358,
|
|
50385
|
+
_v9Precision: 0.0158,
|
|
49979
50386
|
defaultOff: true
|
|
49980
50387
|
},
|
|
49981
50388
|
"java/system-out-println": {
|
|
49982
|
-
recall: 0,
|
|
49983
|
-
fpRate: 0,
|
|
49984
|
-
ratio:
|
|
49985
|
-
precision: 0,
|
|
49986
|
-
lastCalibratedAt: "2026-07-
|
|
50389
|
+
recall: 0.1503,
|
|
50390
|
+
fpRate: 0.2533,
|
|
50391
|
+
ratio: 0.59,
|
|
50392
|
+
precision: 0.0695,
|
|
50393
|
+
lastCalibratedAt: "2026-07-02T19:34:00Z",
|
|
49987
50394
|
verdict: "DORMANT",
|
|
49988
|
-
_calibrationNote: "v0.
|
|
50395
|
+
_calibrationNote: "v9 Java corpus calibration (v0.25.0, 2026-07-02): 81891 neg + 10305 pos Java files. v9 TP=1549, FP=20737, P=6.95%, FPR=25.32%, recall=15.03%, ratio=0.59, lift=P/FPR=0.27. INVERTED: System.out.println is more common in legacy enterprise Java (neg) than in modern AI/Java repos (pos). Modern Java defaults to SLF4J/Log4j, AI-generated Java starts with a logger import. The pattern is the opposite of the v0.20 design intent (which assumed println was the AI-fingerprint signal). v0.25.x: consider gating this rule by Java era (recent file mtime) or making it an age-fingerprint rather than AI-fingerprint. v0.20: new rule.",
|
|
49989
50396
|
aiSpecific: true,
|
|
49990
50397
|
_v7Verdict: "DORMANT",
|
|
49991
50398
|
_v7Lift: 1,
|
|
@@ -49994,6 +50401,11 @@ var init_signal_strength = __esm({
|
|
|
49994
50401
|
_v7Precision: 0,
|
|
49995
50402
|
_v8Verdict: "DORMANT",
|
|
49996
50403
|
_v8Lift: 1,
|
|
50404
|
+
_v9Verdict: "DORMANT",
|
|
50405
|
+
_v9Lift: 0.27,
|
|
50406
|
+
_v9Recall: 0.1503,
|
|
50407
|
+
_v9FpRate: 0.2533,
|
|
50408
|
+
_v9Precision: 0.0695,
|
|
49997
50409
|
defaultOff: true
|
|
49998
50410
|
},
|
|
49999
50411
|
"layout/forced-layout": {
|
|
@@ -59465,6 +59877,11 @@ var RULE_HINTS = {
|
|
|
59465
59877
|
"java/legacy-date-api": "Replace `java.util.Date` / `Calendar` with `java.time` (`LocalDate`, `LocalDateTime`, `Instant`, `ZonedDateTime`). java.time is immutable and thread-safe. AI agents default to the legacy API.",
|
|
59466
59878
|
"java/raw-type-overuse": "Replace raw `List` / `Map` / `Set` with the parameterized form. Raw types disable generic type checking (Effective Java, Item 23). AI agents default to raw types when unsure of the correct generic parameters.",
|
|
59467
59879
|
"java/string-concat-loop": "Declare a `StringBuilder` outside the loop: `StringBuilder sb = new StringBuilder(); sb.append(...);` then `return sb.toString();` after. String concat in a loop is O(n\xB2).",
|
|
59880
|
+
"java/verbose-javadoc": "Skip Javadoc on trivial methods (getters, setters, builders). AI over-documents; real Java limits Javadoc to public API surface. (v0.26.0 \u2014 DORMANT.)",
|
|
59881
|
+
"java/optional-overuse": "Use Objects.requireNonNull(x) for null checks; reserve Optional for return values. AI chains .ofNullable().orElseThrow() where null checks suffice. (v0.26.0 \u2014 DORMANT.)",
|
|
59882
|
+
"java/immutable-collection-preference": "Prefer mutable (new ArrayList<>()) when the collection will be modified. AI defaults to List.of/Map.of/Set.of; real Java uses mutable. (v0.26.0 \u2014 DORMANT.)",
|
|
59883
|
+
"java/builder-overuse": "Use a plain constructor for classes with \u2264 3 fields. AI defaults to @Builder; Builder adds Lombok dep and a Builder inner class per class. (v0.26.0 \u2014 DORMANT.)",
|
|
59884
|
+
"java/stream-overuse": "Prefer a for-loop for simple transformations. AI chains Stream API for everything; for small collections a for-loop is faster. (v0.26.0 \u2014 DORMANT.)",
|
|
59468
59885
|
// v0.24.0 — Kotlin rules (DORMANT until v9 Kotlin corpus calibration)
|
|
59469
59886
|
"kotlin/data-class-defaults-overuse": "Audit which fields are genuinely optional. Real Kotlin uses defaults sparingly (1-2 callbacks, the rest required). v0.24.0 \u2014 DORMANT until v9 calibration.",
|
|
59470
59887
|
"kotlin/coroutine-global-scope": "Replace with `viewModelScope.launch { ... }`, `lifecycleScope.launch { ... }`, or `coroutineScope { ... }`. GlobalScope bypasses cancellation. (v0.24.0 \u2014 DORMANT.)",
|