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.cjs
CHANGED
|
@@ -36,7 +36,7 @@ var VERSION;
|
|
|
36
36
|
var init_header = __esm({
|
|
37
37
|
"src/types/_header.ts"() {
|
|
38
38
|
"use strict";
|
|
39
|
-
VERSION = "0.
|
|
39
|
+
VERSION = "0.26.0";
|
|
40
40
|
}
|
|
41
41
|
});
|
|
42
42
|
|
|
@@ -344,19 +344,24 @@ var init_defaults = __esm({
|
|
|
344
344
|
* - `tests/rules/**` — rule test files contain expected-issue
|
|
345
345
|
* assertions, also meta-code.
|
|
346
346
|
*
|
|
347
|
-
* Three patterns
|
|
348
|
-
*
|
|
349
|
-
*
|
|
350
|
-
*
|
|
347
|
+
* Three patterns (broadened in v0.25.1 from the v0.25.0 narrow
|
|
348
|
+
* set, which missed `tests/engine/**`, `tests/cli/**`, and
|
|
349
|
+
* `snippet/**`), ~80 issues removed per self-scan. Combined
|
|
350
|
+
* with the v0.25.0 graded security cap, this restores the
|
|
351
|
+
* v9 plan's "security ≥ 80" criterion (unachievable in
|
|
352
|
+
* v0.24.0 due to 90 self-scan FPs collapsing the score to 0).
|
|
351
353
|
*
|
|
352
354
|
* Set `selfScan: { excludePaths: [] }` in `slopbrick.config.mjs`
|
|
353
355
|
* to opt out and scan every file (legacy behavior).
|
|
354
356
|
*/
|
|
355
357
|
selfScan: {
|
|
356
358
|
excludePaths: [
|
|
357
|
-
"src/rules/**",
|
|
358
|
-
|
|
359
|
-
"
|
|
359
|
+
"**/src/rules/**",
|
|
360
|
+
// rule definitions are meta-code
|
|
361
|
+
"**/snippet/**",
|
|
362
|
+
// RULE_HINTS examples are intentional bad code
|
|
363
|
+
"**/tests/**"
|
|
364
|
+
// all test files (fixtures + unit + integration)
|
|
360
365
|
]
|
|
361
366
|
}
|
|
362
367
|
};
|
|
@@ -30699,6 +30704,55 @@ var init_arraylist_vs_linkedlist = __esm({
|
|
|
30699
30704
|
}
|
|
30700
30705
|
});
|
|
30701
30706
|
|
|
30707
|
+
// src/rules/java/builder-overuse.ts
|
|
30708
|
+
var BUILDER_ANNOTATION_REGEX, FIELD_DECL_REGEX, DEFAULT_FIELD_COUNT_CAP, javaBuilderOveruseRule;
|
|
30709
|
+
var init_builder_overuse = __esm({
|
|
30710
|
+
"src/rules/java/builder-overuse.ts"() {
|
|
30711
|
+
"use strict";
|
|
30712
|
+
init_rule();
|
|
30713
|
+
BUILDER_ANNOTATION_REGEX = /@Builder\b/;
|
|
30714
|
+
FIELD_DECL_REGEX = /(?:private|public|protected)\s+(?:final\s+)?[\w<>,\s]+\s+(\w+)\s*[=;]/g;
|
|
30715
|
+
DEFAULT_FIELD_COUNT_CAP = 3;
|
|
30716
|
+
javaBuilderOveruseRule = createRule({
|
|
30717
|
+
id: "java/builder-overuse",
|
|
30718
|
+
category: "typo",
|
|
30719
|
+
severity: "low",
|
|
30720
|
+
aiSpecific: true,
|
|
30721
|
+
description: "@Builder on a class with few fields \u2014 plain constructor is simpler",
|
|
30722
|
+
create(_context) {
|
|
30723
|
+
return { fieldCountCap: DEFAULT_FIELD_COUNT_CAP };
|
|
30724
|
+
},
|
|
30725
|
+
analyze(context, facts) {
|
|
30726
|
+
const issues = [];
|
|
30727
|
+
const source = facts.v2?._source;
|
|
30728
|
+
if (!source) return issues;
|
|
30729
|
+
if (!/\.java$/i.test(facts.filePath)) return issues;
|
|
30730
|
+
BUILDER_ANNOTATION_REGEX.lastIndex = 0;
|
|
30731
|
+
const builderMatch = BUILDER_ANNOTATION_REGEX.exec(source);
|
|
30732
|
+
if (!builderMatch) return issues;
|
|
30733
|
+
const firstBuilderLine = source.slice(0, builderMatch.index).split("\n").length;
|
|
30734
|
+
FIELD_DECL_REGEX.lastIndex = 0;
|
|
30735
|
+
let fieldCount = 0;
|
|
30736
|
+
while (FIELD_DECL_REGEX.exec(source) !== null) {
|
|
30737
|
+
fieldCount++;
|
|
30738
|
+
}
|
|
30739
|
+
if (fieldCount > context.fieldCountCap) return issues;
|
|
30740
|
+
issues.push({
|
|
30741
|
+
ruleId: "java/builder-overuse",
|
|
30742
|
+
category: "typo",
|
|
30743
|
+
severity: "low",
|
|
30744
|
+
aiSpecific: true,
|
|
30745
|
+
message: `@Builder on a class with ${fieldCount} field(s) \u2014 plain constructor is simpler`,
|
|
30746
|
+
line: firstBuilderLine,
|
|
30747
|
+
column: 1,
|
|
30748
|
+
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."
|
|
30749
|
+
});
|
|
30750
|
+
return issues;
|
|
30751
|
+
}
|
|
30752
|
+
});
|
|
30753
|
+
}
|
|
30754
|
+
});
|
|
30755
|
+
|
|
30702
30756
|
// src/rules/java/empty-catch-block.ts
|
|
30703
30757
|
var SINGLE_LINE_EMPTY_CATCH_REGEX, javaEmptyCatchBlockRule;
|
|
30704
30758
|
var init_empty_catch_block = __esm({
|
|
@@ -30741,6 +30795,65 @@ var init_empty_catch_block = __esm({
|
|
|
30741
30795
|
}
|
|
30742
30796
|
});
|
|
30743
30797
|
|
|
30798
|
+
// src/rules/java/immutable-collection-preference.ts
|
|
30799
|
+
var IMMUTABLE_REGEX, MUTABLE_REGEX, DEFAULT_IMMUTABLE_THRESHOLD, DEFAULT_MUTABLE_CAP, javaImmutableCollectionPreferenceRule;
|
|
30800
|
+
var init_immutable_collection_preference = __esm({
|
|
30801
|
+
"src/rules/java/immutable-collection-preference.ts"() {
|
|
30802
|
+
"use strict";
|
|
30803
|
+
init_rule();
|
|
30804
|
+
IMMUTABLE_REGEX = /\b(List|Map|Set)\.of\s*\(/g;
|
|
30805
|
+
MUTABLE_REGEX = /new\s+(ArrayList|HashMap|HashSet|LinkedList|TreeMap)\s*[<(]/g;
|
|
30806
|
+
DEFAULT_IMMUTABLE_THRESHOLD = 5;
|
|
30807
|
+
DEFAULT_MUTABLE_CAP = 1;
|
|
30808
|
+
javaImmutableCollectionPreferenceRule = createRule({
|
|
30809
|
+
id: "java/immutable-collection-preference",
|
|
30810
|
+
category: "typo",
|
|
30811
|
+
severity: "low",
|
|
30812
|
+
aiSpecific: true,
|
|
30813
|
+
description: "Immutable factory method over-use \u2014 prefer mutable when collection will be modified",
|
|
30814
|
+
create(_context) {
|
|
30815
|
+
return {
|
|
30816
|
+
immutableThreshold: DEFAULT_IMMUTABLE_THRESHOLD,
|
|
30817
|
+
mutableCap: DEFAULT_MUTABLE_CAP
|
|
30818
|
+
};
|
|
30819
|
+
},
|
|
30820
|
+
analyze(context, facts) {
|
|
30821
|
+
const issues = [];
|
|
30822
|
+
const source = facts.v2?._source;
|
|
30823
|
+
if (!source) return issues;
|
|
30824
|
+
if (!/\.java$/i.test(facts.filePath)) return issues;
|
|
30825
|
+
IMMUTABLE_REGEX.lastIndex = 0;
|
|
30826
|
+
let immutableCount = 0;
|
|
30827
|
+
let firstIdx = 0;
|
|
30828
|
+
let m;
|
|
30829
|
+
while ((m = IMMUTABLE_REGEX.exec(source)) !== null) {
|
|
30830
|
+
immutableCount++;
|
|
30831
|
+
if (firstIdx === 0) firstIdx = m.index;
|
|
30832
|
+
}
|
|
30833
|
+
if (immutableCount < context.immutableThreshold) return issues;
|
|
30834
|
+
MUTABLE_REGEX.lastIndex = 0;
|
|
30835
|
+
let mutableCount = 0;
|
|
30836
|
+
while ((m = MUTABLE_REGEX.exec(source)) !== null) {
|
|
30837
|
+
mutableCount++;
|
|
30838
|
+
}
|
|
30839
|
+
if (mutableCount > context.mutableCap) return issues;
|
|
30840
|
+
const line = source.slice(0, firstIdx).split("\n").length;
|
|
30841
|
+
issues.push({
|
|
30842
|
+
ruleId: "java/immutable-collection-preference",
|
|
30843
|
+
category: "typo",
|
|
30844
|
+
severity: "low",
|
|
30845
|
+
aiSpecific: true,
|
|
30846
|
+
message: `${immutableCount} immutable factory calls (List/Map/Set.of) with only ${mutableCount} mutable collection \u2014 likely over-preferring immutability`,
|
|
30847
|
+
line,
|
|
30848
|
+
column: 1,
|
|
30849
|
+
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."
|
|
30850
|
+
});
|
|
30851
|
+
return issues;
|
|
30852
|
+
}
|
|
30853
|
+
});
|
|
30854
|
+
}
|
|
30855
|
+
});
|
|
30856
|
+
|
|
30744
30857
|
// src/rules/java/legacy-date-api.ts
|
|
30745
30858
|
var LEGACY_IMPORT_REGEX, LEGACY_USAGE_REGEX, CALENDAR_GET_INSTANCE_REGEX, javaLegacyDateApiRule;
|
|
30746
30859
|
var init_legacy_date_api = __esm({
|
|
@@ -30817,6 +30930,59 @@ var init_legacy_date_api = __esm({
|
|
|
30817
30930
|
}
|
|
30818
30931
|
});
|
|
30819
30932
|
|
|
30933
|
+
// src/rules/java/optional-overuse.ts
|
|
30934
|
+
var OR_ELSE_THROW_REGEX, NULL_CHECK_REGEX, DEFAULT_THRESHOLD, javaOptionalOveruseRule;
|
|
30935
|
+
var init_optional_overuse = __esm({
|
|
30936
|
+
"src/rules/java/optional-overuse.ts"() {
|
|
30937
|
+
"use strict";
|
|
30938
|
+
init_rule();
|
|
30939
|
+
OR_ELSE_THROW_REGEX = /\.orElseThrow\s*\(/g;
|
|
30940
|
+
NULL_CHECK_REGEX = /Objects\.requireNonNull\s*\(|if\s*\([^)]*==\s*null\)\s*(?:throw|return)/g;
|
|
30941
|
+
DEFAULT_THRESHOLD = 2;
|
|
30942
|
+
javaOptionalOveruseRule = createRule({
|
|
30943
|
+
id: "java/optional-overuse",
|
|
30944
|
+
category: "typo",
|
|
30945
|
+
severity: "low",
|
|
30946
|
+
aiSpecific: true,
|
|
30947
|
+
description: "Optional chain over-use \u2014 null check or Objects.requireNonNull is faster",
|
|
30948
|
+
create(_context) {
|
|
30949
|
+
return { threshold: DEFAULT_THRESHOLD };
|
|
30950
|
+
},
|
|
30951
|
+
analyze(context, facts) {
|
|
30952
|
+
const issues = [];
|
|
30953
|
+
const source = facts.v2?._source;
|
|
30954
|
+
if (!source) return issues;
|
|
30955
|
+
if (!/\.java$/i.test(facts.filePath)) return issues;
|
|
30956
|
+
OR_ELSE_THROW_REGEX.lastIndex = 0;
|
|
30957
|
+
let orElseThrowCount = 0;
|
|
30958
|
+
let firstIdx = 0;
|
|
30959
|
+
let m;
|
|
30960
|
+
while ((m = OR_ELSE_THROW_REGEX.exec(source)) !== null) {
|
|
30961
|
+
orElseThrowCount++;
|
|
30962
|
+
if (firstIdx === 0) firstIdx = m.index;
|
|
30963
|
+
}
|
|
30964
|
+
if (orElseThrowCount < context.threshold) return issues;
|
|
30965
|
+
NULL_CHECK_REGEX.lastIndex = 0;
|
|
30966
|
+
const nullCheckCount = (source.match(NULL_CHECK_REGEX) ?? []).length;
|
|
30967
|
+
const optionalRatio = orElseThrowCount / Math.max(orElseThrowCount + nullCheckCount, 1);
|
|
30968
|
+
if (optionalRatio < 0.6) return issues;
|
|
30969
|
+
const line = source.slice(0, firstIdx).split("\n").length;
|
|
30970
|
+
issues.push({
|
|
30971
|
+
ruleId: "java/optional-overuse",
|
|
30972
|
+
category: "typo",
|
|
30973
|
+
severity: "low",
|
|
30974
|
+
aiSpecific: true,
|
|
30975
|
+
message: `${orElseThrowCount} .orElseThrow() calls with ${nullCheckCount} null checks \u2014 Optional chain over-use`,
|
|
30976
|
+
line,
|
|
30977
|
+
column: 1,
|
|
30978
|
+
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.'
|
|
30979
|
+
});
|
|
30980
|
+
return issues;
|
|
30981
|
+
}
|
|
30982
|
+
});
|
|
30983
|
+
}
|
|
30984
|
+
});
|
|
30985
|
+
|
|
30820
30986
|
// src/rules/java/raw-type-overuse.ts
|
|
30821
30987
|
var RAW_TYPE_REGEX, javaRawTypeOveruseRule;
|
|
30822
30988
|
var init_raw_type_overuse = __esm({
|
|
@@ -30860,6 +31026,75 @@ var init_raw_type_overuse = __esm({
|
|
|
30860
31026
|
}
|
|
30861
31027
|
});
|
|
30862
31028
|
|
|
31029
|
+
// src/rules/java/stream-overuse.ts
|
|
31030
|
+
var STREAM_OPS, DEFAULT_CHAIN_THRESHOLD, javaStreamOveruseRule;
|
|
31031
|
+
var init_stream_overuse = __esm({
|
|
31032
|
+
"src/rules/java/stream-overuse.ts"() {
|
|
31033
|
+
"use strict";
|
|
31034
|
+
init_rule();
|
|
31035
|
+
STREAM_OPS = [
|
|
31036
|
+
".map(",
|
|
31037
|
+
".filter(",
|
|
31038
|
+
".flatMap(",
|
|
31039
|
+
".collect(",
|
|
31040
|
+
".reduce(",
|
|
31041
|
+
".sorted(",
|
|
31042
|
+
".distinct(",
|
|
31043
|
+
".limit(",
|
|
31044
|
+
".skip(",
|
|
31045
|
+
".anyMatch(",
|
|
31046
|
+
".allMatch(",
|
|
31047
|
+
".noneMatch(",
|
|
31048
|
+
".findFirst(",
|
|
31049
|
+
".findAny("
|
|
31050
|
+
];
|
|
31051
|
+
DEFAULT_CHAIN_THRESHOLD = 3;
|
|
31052
|
+
javaStreamOveruseRule = createRule({
|
|
31053
|
+
id: "java/stream-overuse",
|
|
31054
|
+
category: "typo",
|
|
31055
|
+
severity: "low",
|
|
31056
|
+
aiSpecific: true,
|
|
31057
|
+
description: "Stream API chain over-use \u2014 for-loop is faster for simple transformations",
|
|
31058
|
+
create(_context) {
|
|
31059
|
+
return { chainThreshold: DEFAULT_CHAIN_THRESHOLD };
|
|
31060
|
+
},
|
|
31061
|
+
analyze(context, facts) {
|
|
31062
|
+
const issues = [];
|
|
31063
|
+
const source = facts.v2?._source;
|
|
31064
|
+
if (!source) return issues;
|
|
31065
|
+
if (!/\.java$/i.test(facts.filePath)) return issues;
|
|
31066
|
+
const lines = source.split("\n");
|
|
31067
|
+
const streamOpPattern = new RegExp(STREAM_OPS.map((op) => op.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|"), "g");
|
|
31068
|
+
let firstOffendingLine = 0;
|
|
31069
|
+
let firstOffendingCount = 0;
|
|
31070
|
+
for (let i = 0; i < lines.length; i++) {
|
|
31071
|
+
const line = lines[i] ?? "";
|
|
31072
|
+
if (line.trim().startsWith("//") || line.trim().startsWith("*")) continue;
|
|
31073
|
+
const matches = line.match(streamOpPattern);
|
|
31074
|
+
if (matches && matches.length >= context.chainThreshold) {
|
|
31075
|
+
if (firstOffendingLine === 0) {
|
|
31076
|
+
firstOffendingLine = i + 1;
|
|
31077
|
+
firstOffendingCount = matches.length;
|
|
31078
|
+
}
|
|
31079
|
+
}
|
|
31080
|
+
}
|
|
31081
|
+
if (firstOffendingLine === 0) return issues;
|
|
31082
|
+
issues.push({
|
|
31083
|
+
ruleId: "java/stream-overuse",
|
|
31084
|
+
category: "typo",
|
|
31085
|
+
severity: "low",
|
|
31086
|
+
aiSpecific: true,
|
|
31087
|
+
message: `${firstOffendingCount} stream operations on a single line \u2014 for-loop is faster`,
|
|
31088
|
+
line: firstOffendingLine,
|
|
31089
|
+
column: 1,
|
|
31090
|
+
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."
|
|
31091
|
+
});
|
|
31092
|
+
return issues;
|
|
31093
|
+
}
|
|
31094
|
+
});
|
|
31095
|
+
}
|
|
31096
|
+
});
|
|
31097
|
+
|
|
30863
31098
|
// src/rules/java/string-concat-loop.ts
|
|
30864
31099
|
var STRING_CONCAT_REGEX, javaStringConcatLoopRule;
|
|
30865
31100
|
var init_string_concat_loop = __esm({
|
|
@@ -30904,13 +31139,13 @@ var init_string_concat_loop = __esm({
|
|
|
30904
31139
|
});
|
|
30905
31140
|
|
|
30906
31141
|
// src/rules/java/system-out-println.ts
|
|
30907
|
-
var PRINTLN_REGEX,
|
|
31142
|
+
var PRINTLN_REGEX, DEFAULT_THRESHOLD2, javaSystemOutPrintlnRule;
|
|
30908
31143
|
var init_system_out_println = __esm({
|
|
30909
31144
|
"src/rules/java/system-out-println.ts"() {
|
|
30910
31145
|
"use strict";
|
|
30911
31146
|
init_rule();
|
|
30912
31147
|
PRINTLN_REGEX = /System\.out\.println\s*\(/g;
|
|
30913
|
-
|
|
31148
|
+
DEFAULT_THRESHOLD2 = 1;
|
|
30914
31149
|
javaSystemOutPrintlnRule = createRule({
|
|
30915
31150
|
id: "java/system-out-println",
|
|
30916
31151
|
category: "typo",
|
|
@@ -30918,7 +31153,7 @@ var init_system_out_println = __esm({
|
|
|
30918
31153
|
aiSpecific: true,
|
|
30919
31154
|
description: "System.out.println in production code \u2014 use a logger (SLF4J, Log4j, etc.)",
|
|
30920
31155
|
create(_context) {
|
|
30921
|
-
return { threshold:
|
|
31156
|
+
return { threshold: DEFAULT_THRESHOLD2 };
|
|
30922
31157
|
},
|
|
30923
31158
|
analyze(context, facts) {
|
|
30924
31159
|
const issues = [];
|
|
@@ -30953,6 +31188,63 @@ var init_system_out_println = __esm({
|
|
|
30953
31188
|
}
|
|
30954
31189
|
});
|
|
30955
31190
|
|
|
31191
|
+
// src/rules/java/verbose-javadoc.ts
|
|
31192
|
+
var TAG_REGEX, DEFAULT_TAG_THRESHOLD, DEFAULT_BODY_LENGTH_CAP, javaVerboseJavadocRule;
|
|
31193
|
+
var init_verbose_javadoc = __esm({
|
|
31194
|
+
"src/rules/java/verbose-javadoc.ts"() {
|
|
31195
|
+
"use strict";
|
|
31196
|
+
init_rule();
|
|
31197
|
+
TAG_REGEX = /@(param|return|throws)\b/g;
|
|
31198
|
+
DEFAULT_TAG_THRESHOLD = 3;
|
|
31199
|
+
DEFAULT_BODY_LENGTH_CAP = 5;
|
|
31200
|
+
javaVerboseJavadocRule = createRule({
|
|
31201
|
+
id: "java/verbose-javadoc",
|
|
31202
|
+
category: "typo",
|
|
31203
|
+
severity: "low",
|
|
31204
|
+
aiSpecific: true,
|
|
31205
|
+
description: "Excessive Javadoc tags on trivial methods \u2014 over-documentation is an AI fingerprint",
|
|
31206
|
+
create(_context) {
|
|
31207
|
+
return {
|
|
31208
|
+
tagThreshold: DEFAULT_TAG_THRESHOLD,
|
|
31209
|
+
bodyLengthCap: DEFAULT_BODY_LENGTH_CAP
|
|
31210
|
+
};
|
|
31211
|
+
},
|
|
31212
|
+
analyze(context, facts) {
|
|
31213
|
+
const issues = [];
|
|
31214
|
+
const source = facts.v2?._source;
|
|
31215
|
+
if (!source) return issues;
|
|
31216
|
+
if (!/\.java$/i.test(facts.filePath)) return issues;
|
|
31217
|
+
TAG_REGEX.lastIndex = 0;
|
|
31218
|
+
let tagCount = 0;
|
|
31219
|
+
let firstTagLine = 0;
|
|
31220
|
+
let m;
|
|
31221
|
+
while ((m = TAG_REGEX.exec(source)) !== null) {
|
|
31222
|
+
tagCount++;
|
|
31223
|
+
if (firstTagLine === 0) {
|
|
31224
|
+
firstTagLine = source.slice(0, m.index).split("\n").length;
|
|
31225
|
+
}
|
|
31226
|
+
}
|
|
31227
|
+
if (tagCount < context.tagThreshold) return issues;
|
|
31228
|
+
const lineCount = source.split("\n").length;
|
|
31229
|
+
const tagDensity = tagCount / Math.max(lineCount, 1);
|
|
31230
|
+
if (tagDensity < 0.05) return issues;
|
|
31231
|
+
if (lineCount > 200) return issues;
|
|
31232
|
+
issues.push({
|
|
31233
|
+
ruleId: "java/verbose-javadoc",
|
|
31234
|
+
category: "typo",
|
|
31235
|
+
severity: "low",
|
|
31236
|
+
aiSpecific: true,
|
|
31237
|
+
message: `${tagCount} Javadoc tags in ${lineCount} lines (density ${(tagDensity * 100).toFixed(1)}%) \u2014 likely over-documented`,
|
|
31238
|
+
line: firstTagLine,
|
|
31239
|
+
column: 1,
|
|
31240
|
+
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."
|
|
31241
|
+
});
|
|
31242
|
+
return issues;
|
|
31243
|
+
}
|
|
31244
|
+
});
|
|
31245
|
+
}
|
|
31246
|
+
});
|
|
31247
|
+
|
|
30956
31248
|
// src/rules/kotlin/coroutine-global-scope.ts
|
|
30957
31249
|
var GLOBAL_SCOPE_REGEX, kotlinCoroutineGlobalScopeRule;
|
|
30958
31250
|
var init_coroutine_global_scope = __esm({
|
|
@@ -31117,13 +31409,13 @@ var init_object_singleton_misuse = __esm({
|
|
|
31117
31409
|
});
|
|
31118
31410
|
|
|
31119
31411
|
// src/rules/kotlin/println-debug.ts
|
|
31120
|
-
var PRINTLN_REGEX2,
|
|
31412
|
+
var PRINTLN_REGEX2, DEFAULT_THRESHOLD3, kotlinPrintlnDebugRule;
|
|
31121
31413
|
var init_println_debug = __esm({
|
|
31122
31414
|
"src/rules/kotlin/println-debug.ts"() {
|
|
31123
31415
|
"use strict";
|
|
31124
31416
|
init_rule();
|
|
31125
31417
|
PRINTLN_REGEX2 = /^\s*println\s*\(/gm;
|
|
31126
|
-
|
|
31418
|
+
DEFAULT_THRESHOLD3 = 1;
|
|
31127
31419
|
kotlinPrintlnDebugRule = createRule({
|
|
31128
31420
|
id: "kotlin/println-debug",
|
|
31129
31421
|
category: "typo",
|
|
@@ -31131,7 +31423,7 @@ var init_println_debug = __esm({
|
|
|
31131
31423
|
aiSpecific: true,
|
|
31132
31424
|
description: "println(...) in production code \u2014 use Timber, android.util.Log, or an SLF4J facade",
|
|
31133
31425
|
create(_context) {
|
|
31134
|
-
return { threshold:
|
|
31426
|
+
return { threshold: DEFAULT_THRESHOLD3 };
|
|
31135
31427
|
},
|
|
31136
31428
|
analyze(context, facts) {
|
|
31137
31429
|
const issues = [];
|
|
@@ -40836,13 +41128,13 @@ var init_implicitly_unwrapped_optional = __esm({
|
|
|
40836
41128
|
});
|
|
40837
41129
|
|
|
40838
41130
|
// src/rules/swift/print-debug.ts
|
|
40839
|
-
var PRINT_REGEX,
|
|
41131
|
+
var PRINT_REGEX, DEFAULT_THRESHOLD4, swiftPrintDebugRule;
|
|
40840
41132
|
var init_print_debug = __esm({
|
|
40841
41133
|
"src/rules/swift/print-debug.ts"() {
|
|
40842
41134
|
"use strict";
|
|
40843
41135
|
init_rule();
|
|
40844
41136
|
PRINT_REGEX = /\bprint\s*\(/g;
|
|
40845
|
-
|
|
41137
|
+
DEFAULT_THRESHOLD4 = 1;
|
|
40846
41138
|
swiftPrintDebugRule = createRule({
|
|
40847
41139
|
id: "swift/print-debug",
|
|
40848
41140
|
category: "typo",
|
|
@@ -40850,7 +41142,7 @@ var init_print_debug = __esm({
|
|
|
40850
41142
|
aiSpecific: true,
|
|
40851
41143
|
description: "print(...) in production Swift \u2014 use Logger (os.log) for level-controlled output",
|
|
40852
41144
|
create(_context) {
|
|
40853
|
-
return { threshold:
|
|
41145
|
+
return { threshold: DEFAULT_THRESHOLD4 };
|
|
40854
41146
|
},
|
|
40855
41147
|
analyze(context, facts) {
|
|
40856
41148
|
const issues = [];
|
|
@@ -46601,11 +46893,16 @@ var init_builtins = __esm({
|
|
|
46601
46893
|
init_nil_slice_vs_empty();
|
|
46602
46894
|
init_struct_tag_inconsistency();
|
|
46603
46895
|
init_arraylist_vs_linkedlist();
|
|
46896
|
+
init_builder_overuse();
|
|
46604
46897
|
init_empty_catch_block();
|
|
46898
|
+
init_immutable_collection_preference();
|
|
46605
46899
|
init_legacy_date_api();
|
|
46900
|
+
init_optional_overuse();
|
|
46606
46901
|
init_raw_type_overuse();
|
|
46902
|
+
init_stream_overuse();
|
|
46607
46903
|
init_string_concat_loop();
|
|
46608
46904
|
init_system_out_println();
|
|
46905
|
+
init_verbose_javadoc();
|
|
46609
46906
|
init_coroutine_global_scope();
|
|
46610
46907
|
init_data_class_defaults_overuse();
|
|
46611
46908
|
init_object_singleton_misuse();
|
|
@@ -46736,11 +47033,16 @@ var init_builtins = __esm({
|
|
|
46736
47033
|
goNilSliceVsEmptyRule,
|
|
46737
47034
|
goStructTagInconsistencyRule,
|
|
46738
47035
|
javaArraylistVsLinkedlistRule,
|
|
47036
|
+
javaBuilderOveruseRule,
|
|
46739
47037
|
javaEmptyCatchBlockRule,
|
|
47038
|
+
javaImmutableCollectionPreferenceRule,
|
|
46740
47039
|
javaLegacyDateApiRule,
|
|
47040
|
+
javaOptionalOveruseRule,
|
|
46741
47041
|
javaRawTypeOveruseRule,
|
|
47042
|
+
javaStreamOveruseRule,
|
|
46742
47043
|
javaStringConcatLoopRule,
|
|
46743
47044
|
javaSystemOutPrintlnRule,
|
|
47045
|
+
javaVerboseJavadocRule,
|
|
46744
47046
|
kotlinCoroutineGlobalScopeRule,
|
|
46745
47047
|
kotlinDataClassDefaultsOveruseRule,
|
|
46746
47048
|
kotlinObjectSingletonMisuseRule,
|
|
@@ -49911,13 +50213,13 @@ var init_signal_strength = __esm({
|
|
|
49911
50213
|
defaultOff: true
|
|
49912
50214
|
},
|
|
49913
50215
|
"java/arraylist-vs-linkedlist": {
|
|
49914
|
-
recall:
|
|
49915
|
-
fpRate:
|
|
49916
|
-
ratio:
|
|
49917
|
-
precision: 0,
|
|
49918
|
-
lastCalibratedAt: "2026-07-
|
|
50216
|
+
recall: 35e-4,
|
|
50217
|
+
fpRate: 94e-4,
|
|
50218
|
+
ratio: 0.37,
|
|
50219
|
+
precision: 0.0446,
|
|
50220
|
+
lastCalibratedAt: "2026-07-02T19:34:00Z",
|
|
49919
50221
|
verdict: "DORMANT",
|
|
49920
|
-
_calibrationNote: "v0.20: new rule (new LinkedList<>() \u2014 use ArrayList
|
|
50222
|
+
_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).",
|
|
49921
50223
|
aiSpecific: true,
|
|
49922
50224
|
_v7Verdict: "DORMANT",
|
|
49923
50225
|
_v7Lift: 1,
|
|
@@ -49926,16 +50228,21 @@ var init_signal_strength = __esm({
|
|
|
49926
50228
|
_v7Precision: 0,
|
|
49927
50229
|
_v8Verdict: "DORMANT",
|
|
49928
50230
|
_v8Lift: 1,
|
|
50231
|
+
_v9Verdict: "DORMANT",
|
|
50232
|
+
_v9Lift: 4.74,
|
|
50233
|
+
_v9Recall: 35e-4,
|
|
50234
|
+
_v9FpRate: 94e-4,
|
|
50235
|
+
_v9Precision: 0.0446,
|
|
49929
50236
|
defaultOff: true
|
|
49930
50237
|
},
|
|
49931
50238
|
"java/empty-catch-block": {
|
|
49932
|
-
recall:
|
|
49933
|
-
fpRate: 0,
|
|
49934
|
-
ratio:
|
|
49935
|
-
precision:
|
|
49936
|
-
lastCalibratedAt: "2026-07-
|
|
50239
|
+
recall: 8e-3,
|
|
50240
|
+
fpRate: 0.1118,
|
|
50241
|
+
ratio: 0.07,
|
|
50242
|
+
precision: 89e-4,
|
|
50243
|
+
lastCalibratedAt: "2026-07-02T19:34:00Z",
|
|
49937
50244
|
verdict: "DORMANT",
|
|
49938
|
-
_calibrationNote: "v0.
|
|
50245
|
+
_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.",
|
|
49939
50246
|
aiSpecific: true,
|
|
49940
50247
|
_v7Verdict: "DORMANT",
|
|
49941
50248
|
_v7Lift: 1,
|
|
@@ -49944,16 +50251,21 @@ var init_signal_strength = __esm({
|
|
|
49944
50251
|
_v7Precision: 0,
|
|
49945
50252
|
_v8Verdict: "DORMANT",
|
|
49946
50253
|
_v8Lift: 1,
|
|
50254
|
+
_v9Verdict: "DORMANT",
|
|
50255
|
+
_v9Lift: 0.08,
|
|
50256
|
+
_v9Recall: 8e-3,
|
|
50257
|
+
_v9FpRate: 0.1118,
|
|
50258
|
+
_v9Precision: 89e-4,
|
|
49947
50259
|
defaultOff: true
|
|
49948
50260
|
},
|
|
49949
50261
|
"java/legacy-date-api": {
|
|
49950
|
-
recall: 0,
|
|
49951
|
-
fpRate: 0,
|
|
49952
|
-
ratio:
|
|
49953
|
-
precision: 0,
|
|
49954
|
-
lastCalibratedAt: "2026-07-
|
|
50262
|
+
recall: 0.0285,
|
|
50263
|
+
fpRate: 0.0511,
|
|
50264
|
+
ratio: 0.56,
|
|
50265
|
+
precision: 0.0657,
|
|
50266
|
+
lastCalibratedAt: "2026-07-02T19:34:00Z",
|
|
49955
50267
|
verdict: "DORMANT",
|
|
49956
|
-
_calibrationNote: "v0.
|
|
50268
|
+
_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.",
|
|
49957
50269
|
aiSpecific: true,
|
|
49958
50270
|
_v7Verdict: "DORMANT",
|
|
49959
50271
|
_v7Lift: 1,
|
|
@@ -49962,16 +50274,101 @@ var init_signal_strength = __esm({
|
|
|
49962
50274
|
_v7Precision: 0,
|
|
49963
50275
|
_v8Verdict: "DORMANT",
|
|
49964
50276
|
_v8Lift: 1,
|
|
50277
|
+
_v9Verdict: "DORMANT",
|
|
50278
|
+
_v9Lift: 1.29,
|
|
50279
|
+
_v9Recall: 0.0285,
|
|
50280
|
+
_v9FpRate: 0.0511,
|
|
50281
|
+
_v9Precision: 0.0657,
|
|
49965
50282
|
defaultOff: true
|
|
49966
50283
|
},
|
|
49967
|
-
"java/
|
|
50284
|
+
"java/verbose-javadoc": {
|
|
49968
50285
|
recall: 0,
|
|
49969
50286
|
fpRate: 0,
|
|
49970
50287
|
ratio: 1,
|
|
49971
50288
|
precision: 0,
|
|
49972
|
-
lastCalibratedAt: "2026-07-
|
|
50289
|
+
lastCalibratedAt: "2026-07-03T00:00:00Z",
|
|
50290
|
+
verdict: "DORMANT",
|
|
50291
|
+
_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.",
|
|
50292
|
+
aiSpecific: true,
|
|
50293
|
+
_v9Verdict: "DORMANT",
|
|
50294
|
+
_v9Lift: 1,
|
|
50295
|
+
_v9Recall: 0,
|
|
50296
|
+
_v9FpRate: 0,
|
|
50297
|
+
_v9Precision: 0,
|
|
50298
|
+
defaultOff: true
|
|
50299
|
+
},
|
|
50300
|
+
"java/optional-overuse": {
|
|
50301
|
+
recall: 0,
|
|
50302
|
+
fpRate: 0,
|
|
50303
|
+
ratio: 1,
|
|
50304
|
+
precision: 0,
|
|
50305
|
+
lastCalibratedAt: "2026-07-03T00:00:00Z",
|
|
49973
50306
|
verdict: "DORMANT",
|
|
49974
|
-
_calibrationNote: "v0.
|
|
50307
|
+
_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.",
|
|
50308
|
+
aiSpecific: true,
|
|
50309
|
+
_v9Verdict: "DORMANT",
|
|
50310
|
+
_v9Lift: 1,
|
|
50311
|
+
_v9Recall: 0,
|
|
50312
|
+
_v9FpRate: 0,
|
|
50313
|
+
_v9Precision: 0,
|
|
50314
|
+
defaultOff: true
|
|
50315
|
+
},
|
|
50316
|
+
"java/immutable-collection-preference": {
|
|
50317
|
+
recall: 0,
|
|
50318
|
+
fpRate: 0,
|
|
50319
|
+
ratio: 1,
|
|
50320
|
+
precision: 0,
|
|
50321
|
+
lastCalibratedAt: "2026-07-03T00:00:00Z",
|
|
50322
|
+
verdict: "DORMANT",
|
|
50323
|
+
_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.",
|
|
50324
|
+
aiSpecific: true,
|
|
50325
|
+
_v9Verdict: "DORMANT",
|
|
50326
|
+
_v9Lift: 1,
|
|
50327
|
+
_v9Recall: 0,
|
|
50328
|
+
_v9FpRate: 0,
|
|
50329
|
+
_v9Precision: 0,
|
|
50330
|
+
defaultOff: true
|
|
50331
|
+
},
|
|
50332
|
+
"java/builder-overuse": {
|
|
50333
|
+
recall: 0,
|
|
50334
|
+
fpRate: 0,
|
|
50335
|
+
ratio: 1,
|
|
50336
|
+
precision: 0,
|
|
50337
|
+
lastCalibratedAt: "2026-07-03T00:00:00Z",
|
|
50338
|
+
verdict: "DORMANT",
|
|
50339
|
+
_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.",
|
|
50340
|
+
aiSpecific: true,
|
|
50341
|
+
_v9Verdict: "DORMANT",
|
|
50342
|
+
_v9Lift: 1,
|
|
50343
|
+
_v9Recall: 0,
|
|
50344
|
+
_v9FpRate: 0,
|
|
50345
|
+
_v9Precision: 0,
|
|
50346
|
+
defaultOff: true
|
|
50347
|
+
},
|
|
50348
|
+
"java/stream-overuse": {
|
|
50349
|
+
recall: 0,
|
|
50350
|
+
fpRate: 0,
|
|
50351
|
+
ratio: 1,
|
|
50352
|
+
precision: 0,
|
|
50353
|
+
lastCalibratedAt: "2026-07-03T00:00:00Z",
|
|
50354
|
+
verdict: "DORMANT",
|
|
50355
|
+
_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.",
|
|
50356
|
+
aiSpecific: true,
|
|
50357
|
+
_v9Verdict: "DORMANT",
|
|
50358
|
+
_v9Lift: 1,
|
|
50359
|
+
_v9Recall: 0,
|
|
50360
|
+
_v9FpRate: 0,
|
|
50361
|
+
_v9Precision: 0,
|
|
50362
|
+
defaultOff: true
|
|
50363
|
+
},
|
|
50364
|
+
"java/raw-type-overuse": {
|
|
50365
|
+
recall: 0.1093,
|
|
50366
|
+
fpRate: 0.2041,
|
|
50367
|
+
ratio: 0.54,
|
|
50368
|
+
precision: 0.0632,
|
|
50369
|
+
lastCalibratedAt: "2026-07-02T19:34:00Z",
|
|
50370
|
+
verdict: "DORMANT",
|
|
50371
|
+
_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.",
|
|
49975
50372
|
aiSpecific: true,
|
|
49976
50373
|
_v7Verdict: "DORMANT",
|
|
49977
50374
|
_v7Lift: 1,
|
|
@@ -49980,16 +50377,21 @@ var init_signal_strength = __esm({
|
|
|
49980
50377
|
_v7Precision: 0,
|
|
49981
50378
|
_v8Verdict: "DORMANT",
|
|
49982
50379
|
_v8Lift: 1,
|
|
50380
|
+
_v9Verdict: "DORMANT",
|
|
50381
|
+
_v9Lift: 0.31,
|
|
50382
|
+
_v9Recall: 0.1093,
|
|
50383
|
+
_v9FpRate: 0.2041,
|
|
50384
|
+
_v9Precision: 0.0632,
|
|
49983
50385
|
defaultOff: true
|
|
49984
50386
|
},
|
|
49985
50387
|
"java/string-concat-loop": {
|
|
49986
|
-
recall:
|
|
49987
|
-
fpRate: 0,
|
|
49988
|
-
ratio:
|
|
49989
|
-
precision: 0,
|
|
49990
|
-
lastCalibratedAt: "2026-07-
|
|
50388
|
+
recall: 46e-4,
|
|
50389
|
+
fpRate: 0.0358,
|
|
50390
|
+
ratio: 0.13,
|
|
50391
|
+
precision: 0.0158,
|
|
50392
|
+
lastCalibratedAt: "2026-07-02T19:34:00Z",
|
|
49991
50393
|
verdict: "DORMANT",
|
|
49992
|
-
_calibrationNote: "v0.
|
|
50394
|
+
_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.",
|
|
49993
50395
|
aiSpecific: true,
|
|
49994
50396
|
_v7Verdict: "DORMANT",
|
|
49995
50397
|
_v7Lift: 1,
|
|
@@ -49998,16 +50400,21 @@ var init_signal_strength = __esm({
|
|
|
49998
50400
|
_v7Precision: 0,
|
|
49999
50401
|
_v8Verdict: "DORMANT",
|
|
50000
50402
|
_v8Lift: 1,
|
|
50403
|
+
_v9Verdict: "DORMANT",
|
|
50404
|
+
_v9Lift: 0.44,
|
|
50405
|
+
_v9Recall: 46e-4,
|
|
50406
|
+
_v9FpRate: 0.0358,
|
|
50407
|
+
_v9Precision: 0.0158,
|
|
50001
50408
|
defaultOff: true
|
|
50002
50409
|
},
|
|
50003
50410
|
"java/system-out-println": {
|
|
50004
|
-
recall: 0,
|
|
50005
|
-
fpRate: 0,
|
|
50006
|
-
ratio:
|
|
50007
|
-
precision: 0,
|
|
50008
|
-
lastCalibratedAt: "2026-07-
|
|
50411
|
+
recall: 0.1503,
|
|
50412
|
+
fpRate: 0.2533,
|
|
50413
|
+
ratio: 0.59,
|
|
50414
|
+
precision: 0.0695,
|
|
50415
|
+
lastCalibratedAt: "2026-07-02T19:34:00Z",
|
|
50009
50416
|
verdict: "DORMANT",
|
|
50010
|
-
_calibrationNote: "v0.
|
|
50417
|
+
_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.",
|
|
50011
50418
|
aiSpecific: true,
|
|
50012
50419
|
_v7Verdict: "DORMANT",
|
|
50013
50420
|
_v7Lift: 1,
|
|
@@ -50016,6 +50423,11 @@ var init_signal_strength = __esm({
|
|
|
50016
50423
|
_v7Precision: 0,
|
|
50017
50424
|
_v8Verdict: "DORMANT",
|
|
50018
50425
|
_v8Lift: 1,
|
|
50426
|
+
_v9Verdict: "DORMANT",
|
|
50427
|
+
_v9Lift: 0.27,
|
|
50428
|
+
_v9Recall: 0.1503,
|
|
50429
|
+
_v9FpRate: 0.2533,
|
|
50430
|
+
_v9Precision: 0.0695,
|
|
50019
50431
|
defaultOff: true
|
|
50020
50432
|
},
|
|
50021
50433
|
"layout/forced-layout": {
|
|
@@ -59566,6 +59978,11 @@ var RULE_HINTS = {
|
|
|
59566
59978
|
"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.",
|
|
59567
59979
|
"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.",
|
|
59568
59980
|
"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).",
|
|
59981
|
+
"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.)",
|
|
59982
|
+
"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.)",
|
|
59983
|
+
"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.)",
|
|
59984
|
+
"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.)",
|
|
59985
|
+
"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.)",
|
|
59569
59986
|
// v0.24.0 — Kotlin rules (DORMANT until v9 Kotlin corpus calibration)
|
|
59570
59987
|
"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.",
|
|
59571
59988
|
"kotlin/coroutine-global-scope": "Replace with `viewModelScope.launch { ... }`, `lifecycleScope.launch { ... }`, or `coroutineScope { ... }`. GlobalScope bypasses cancellation. (v0.24.0 \u2014 DORMANT.)",
|