slopbrick 0.26.1 → 0.28.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 +79 -782
- package/dist/engine/worker.js +79 -782
- package/dist/index.cjs +85 -888
- package/dist/index.js +85 -888
- 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.28.0";
|
|
23
23
|
}
|
|
24
24
|
});
|
|
25
25
|
|
|
@@ -30643,589 +30643,6 @@ var init_struct_tag_inconsistency = __esm({
|
|
|
30643
30643
|
}
|
|
30644
30644
|
});
|
|
30645
30645
|
|
|
30646
|
-
// src/rules/java/arraylist-vs-linkedlist.ts
|
|
30647
|
-
var NEW_LINKED_LIST_REGEX, javaArraylistVsLinkedlistRule;
|
|
30648
|
-
var init_arraylist_vs_linkedlist = __esm({
|
|
30649
|
-
"src/rules/java/arraylist-vs-linkedlist.ts"() {
|
|
30650
|
-
"use strict";
|
|
30651
|
-
init_rule();
|
|
30652
|
-
NEW_LINKED_LIST_REGEX = /new\s+LinkedList\s*</g;
|
|
30653
|
-
javaArraylistVsLinkedlistRule = createRule({
|
|
30654
|
-
id: "java/arraylist-vs-linkedlist",
|
|
30655
|
-
category: "typo",
|
|
30656
|
-
severity: "low",
|
|
30657
|
-
aiSpecific: true,
|
|
30658
|
-
description: "new LinkedList<>() \u2014 use ArrayList (Effective Java, Item 28)",
|
|
30659
|
-
create(_context) {
|
|
30660
|
-
return {};
|
|
30661
|
-
},
|
|
30662
|
-
analyze(_context, facts) {
|
|
30663
|
-
const issues = [];
|
|
30664
|
-
const source = facts.v2?._source;
|
|
30665
|
-
if (!source) return issues;
|
|
30666
|
-
if (!/\.java$/i.test(facts.filePath)) return issues;
|
|
30667
|
-
let m;
|
|
30668
|
-
NEW_LINKED_LIST_REGEX.lastIndex = 0;
|
|
30669
|
-
while ((m = NEW_LINKED_LIST_REGEX.exec(source)) !== null) {
|
|
30670
|
-
const line = source.slice(0, m.index).split("\n").length;
|
|
30671
|
-
issues.push({
|
|
30672
|
-
ruleId: "java/arraylist-vs-linkedlist",
|
|
30673
|
-
category: "typo",
|
|
30674
|
-
severity: "low",
|
|
30675
|
-
aiSpecific: true,
|
|
30676
|
-
message: `new LinkedList at line ${line} \u2014 use ArrayList instead`,
|
|
30677
|
-
line,
|
|
30678
|
-
column: 1,
|
|
30679
|
-
advice: "Replace `new LinkedList<>()` with `new ArrayList<>()`. LinkedList is rarely the right choice (worse cache locality, 5x more memory per element, O(n) indexed access). Joshua Bloch (Effective Java, Item 28) recommends ArrayList unless you specifically need a Deque. AI agents default to LinkedList because of textbook examples. Reference: java/arraylist-vs-linkedlist v0.20."
|
|
30680
|
-
});
|
|
30681
|
-
}
|
|
30682
|
-
return issues;
|
|
30683
|
-
}
|
|
30684
|
-
});
|
|
30685
|
-
}
|
|
30686
|
-
});
|
|
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
|
-
|
|
30737
|
-
// src/rules/java/empty-catch-block.ts
|
|
30738
|
-
var SINGLE_LINE_EMPTY_CATCH_REGEX, javaEmptyCatchBlockRule;
|
|
30739
|
-
var init_empty_catch_block = __esm({
|
|
30740
|
-
"src/rules/java/empty-catch-block.ts"() {
|
|
30741
|
-
"use strict";
|
|
30742
|
-
init_rule();
|
|
30743
|
-
SINGLE_LINE_EMPTY_CATCH_REGEX = /catch\s*\([^)]*\)\s*\{\s*\}/g;
|
|
30744
|
-
javaEmptyCatchBlockRule = createRule({
|
|
30745
|
-
id: "java/empty-catch-block",
|
|
30746
|
-
category: "logic",
|
|
30747
|
-
severity: "medium",
|
|
30748
|
-
aiSpecific: true,
|
|
30749
|
-
description: "Empty catch block \u2014 silently swallows exceptions",
|
|
30750
|
-
create(_context) {
|
|
30751
|
-
return {};
|
|
30752
|
-
},
|
|
30753
|
-
analyze(_context, facts) {
|
|
30754
|
-
const issues = [];
|
|
30755
|
-
const source = facts.v2?._source;
|
|
30756
|
-
if (!source) return issues;
|
|
30757
|
-
if (!/\.java$/i.test(facts.filePath)) return issues;
|
|
30758
|
-
let m;
|
|
30759
|
-
SINGLE_LINE_EMPTY_CATCH_REGEX.lastIndex = 0;
|
|
30760
|
-
while ((m = SINGLE_LINE_EMPTY_CATCH_REGEX.exec(source)) !== null) {
|
|
30761
|
-
const line = source.slice(0, m.index).split("\n").length;
|
|
30762
|
-
issues.push({
|
|
30763
|
-
ruleId: "java/empty-catch-block",
|
|
30764
|
-
category: "logic",
|
|
30765
|
-
severity: "medium",
|
|
30766
|
-
aiSpecific: true,
|
|
30767
|
-
message: `Empty catch block at line ${line} \u2014 exception is silently swallowed`,
|
|
30768
|
-
line,
|
|
30769
|
-
column: 1,
|
|
30770
|
-
advice: 'Log the exception (`log.error("...", e)`), re-throw it, or both. Empty catch blocks hide bugs. The pattern is common in AI-generated code that wants to look defensive. Reference: java/empty-catch-block v0.20.'
|
|
30771
|
-
});
|
|
30772
|
-
}
|
|
30773
|
-
return issues;
|
|
30774
|
-
}
|
|
30775
|
-
});
|
|
30776
|
-
}
|
|
30777
|
-
});
|
|
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
|
-
|
|
30838
|
-
// src/rules/java/legacy-date-api.ts
|
|
30839
|
-
var LEGACY_IMPORT_REGEX, LEGACY_USAGE_REGEX, CALENDAR_GET_INSTANCE_REGEX, javaLegacyDateApiRule;
|
|
30840
|
-
var init_legacy_date_api = __esm({
|
|
30841
|
-
"src/rules/java/legacy-date-api.ts"() {
|
|
30842
|
-
"use strict";
|
|
30843
|
-
init_rule();
|
|
30844
|
-
LEGACY_IMPORT_REGEX = /^import\s+(?:static\s+)?java\.(?:util|sql)\.(?:Date|Calendar|GregorianCalendar)\s*;/gm;
|
|
30845
|
-
LEGACY_USAGE_REGEX = /\bnew\s+(?:Date|GregorianCalendar)\s*\(/g;
|
|
30846
|
-
CALENDAR_GET_INSTANCE_REGEX = /Calendar\.getInstance\s*\(/g;
|
|
30847
|
-
javaLegacyDateApiRule = createRule({
|
|
30848
|
-
id: "java/legacy-date-api",
|
|
30849
|
-
category: "typo",
|
|
30850
|
-
severity: "low",
|
|
30851
|
-
aiSpecific: true,
|
|
30852
|
-
description: "Legacy java.util.Date / Calendar \u2014 use java.time (JSR-310) from Java 8+",
|
|
30853
|
-
create(_context) {
|
|
30854
|
-
return {};
|
|
30855
|
-
},
|
|
30856
|
-
analyze(_context, facts) {
|
|
30857
|
-
const issues = [];
|
|
30858
|
-
const source = facts.v2?._source;
|
|
30859
|
-
if (!source) return issues;
|
|
30860
|
-
if (!/\.java$/i.test(facts.filePath)) return issues;
|
|
30861
|
-
const flagged = /* @__PURE__ */ new Set();
|
|
30862
|
-
let m;
|
|
30863
|
-
LEGACY_IMPORT_REGEX.lastIndex = 0;
|
|
30864
|
-
while ((m = LEGACY_IMPORT_REGEX.exec(source)) !== null) {
|
|
30865
|
-
const line = source.slice(0, m.index).split("\n").length;
|
|
30866
|
-
flagged.add(line);
|
|
30867
|
-
issues.push({
|
|
30868
|
-
ruleId: "java/legacy-date-api",
|
|
30869
|
-
category: "typo",
|
|
30870
|
-
severity: "low",
|
|
30871
|
-
aiSpecific: true,
|
|
30872
|
-
message: `Legacy date import at line ${line} \u2014 use java.time (JSR-310) from Java 8+`,
|
|
30873
|
-
line,
|
|
30874
|
-
column: 1,
|
|
30875
|
-
advice: "Replace `java.util.Date` / `java.util.Calendar` with `java.time` (`LocalDate`, `LocalDateTime`, `Instant`, `ZonedDateTime`). java.time is immutable, thread-safe, and has a much better API. AI agents default to the legacy API because their training data predates Java 8 (2014). Reference: java/legacy-date-api v0.20."
|
|
30876
|
-
});
|
|
30877
|
-
}
|
|
30878
|
-
LEGACY_USAGE_REGEX.lastIndex = 0;
|
|
30879
|
-
while ((m = LEGACY_USAGE_REGEX.exec(source)) !== null) {
|
|
30880
|
-
const line = source.slice(0, m.index).split("\n").length;
|
|
30881
|
-
if (flagged.has(line)) continue;
|
|
30882
|
-
issues.push({
|
|
30883
|
-
ruleId: "java/legacy-date-api",
|
|
30884
|
-
category: "typo",
|
|
30885
|
-
severity: "low",
|
|
30886
|
-
aiSpecific: true,
|
|
30887
|
-
message: `new Date() / GregorianCalendar at line ${line} \u2014 use java.time`,
|
|
30888
|
-
line,
|
|
30889
|
-
column: 1,
|
|
30890
|
-
advice: "Replace with `LocalDate.now()`, `Instant.now()`, or `ZonedDateTime.now()`. Reference: java/legacy-date-api v0.20."
|
|
30891
|
-
});
|
|
30892
|
-
}
|
|
30893
|
-
CALENDAR_GET_INSTANCE_REGEX.lastIndex = 0;
|
|
30894
|
-
while ((m = CALENDAR_GET_INSTANCE_REGEX.exec(source)) !== null) {
|
|
30895
|
-
const line = source.slice(0, m.index).split("\n").length;
|
|
30896
|
-
if (flagged.has(line)) continue;
|
|
30897
|
-
issues.push({
|
|
30898
|
-
ruleId: "java/legacy-date-api",
|
|
30899
|
-
category: "typo",
|
|
30900
|
-
severity: "low",
|
|
30901
|
-
aiSpecific: true,
|
|
30902
|
-
message: `Calendar.getInstance() at line ${line} \u2014 use java.time`,
|
|
30903
|
-
line,
|
|
30904
|
-
column: 1,
|
|
30905
|
-
advice: "Replace with `LocalDate.now()` (date-only) or `ZonedDateTime.now()`. Reference: java/legacy-date-api v0.20."
|
|
30906
|
-
});
|
|
30907
|
-
}
|
|
30908
|
-
return issues;
|
|
30909
|
-
}
|
|
30910
|
-
});
|
|
30911
|
-
}
|
|
30912
|
-
});
|
|
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
|
-
|
|
30967
|
-
// src/rules/java/raw-type-overuse.ts
|
|
30968
|
-
var RAW_TYPE_REGEX, javaRawTypeOveruseRule;
|
|
30969
|
-
var init_raw_type_overuse = __esm({
|
|
30970
|
-
"src/rules/java/raw-type-overuse.ts"() {
|
|
30971
|
-
"use strict";
|
|
30972
|
-
init_rule();
|
|
30973
|
-
RAW_TYPE_REGEX = /\b(List|Map|Set|Collection|Iterable)\s+(?![<A-Z])(\w+)/g;
|
|
30974
|
-
javaRawTypeOveruseRule = createRule({
|
|
30975
|
-
id: "java/raw-type-overuse",
|
|
30976
|
-
category: "typo",
|
|
30977
|
-
severity: "low",
|
|
30978
|
-
aiSpecific: true,
|
|
30979
|
-
description: "Raw type usage (List, Map, Set) \u2014 use generics (Effective Java, Item 23)",
|
|
30980
|
-
create(_context) {
|
|
30981
|
-
return {};
|
|
30982
|
-
},
|
|
30983
|
-
analyze(_context, facts) {
|
|
30984
|
-
const issues = [];
|
|
30985
|
-
const source = facts.v2?._source;
|
|
30986
|
-
if (!source) return issues;
|
|
30987
|
-
if (!/\.java$/i.test(facts.filePath)) return issues;
|
|
30988
|
-
let m;
|
|
30989
|
-
RAW_TYPE_REGEX.lastIndex = 0;
|
|
30990
|
-
while ((m = RAW_TYPE_REGEX.exec(source)) !== null) {
|
|
30991
|
-
const typeName = m[1];
|
|
30992
|
-
const line = source.slice(0, m.index).split("\n").length;
|
|
30993
|
-
issues.push({
|
|
30994
|
-
ruleId: "java/raw-type-overuse",
|
|
30995
|
-
category: "typo",
|
|
30996
|
-
severity: "low",
|
|
30997
|
-
aiSpecific: true,
|
|
30998
|
-
message: `Raw type ${typeName} at line ${line} \u2014 add type parameters`,
|
|
30999
|
-
line,
|
|
31000
|
-
column: 1,
|
|
31001
|
-
advice: `Replace raw \`${typeName}\` with \`${typeName}<...>\`. Raw types disable generic type checking. Effective Java, Item 23: 'Don't use raw types in new code'. AI agents default to raw types when unsure of the correct generic parameters. Reference: java/raw-type-overuse v0.20.`
|
|
31002
|
-
});
|
|
31003
|
-
}
|
|
31004
|
-
return issues;
|
|
31005
|
-
}
|
|
31006
|
-
});
|
|
31007
|
-
}
|
|
31008
|
-
});
|
|
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
|
-
|
|
31079
|
-
// src/rules/java/string-concat-loop.ts
|
|
31080
|
-
var STRING_CONCAT_REGEX, javaStringConcatLoopRule;
|
|
31081
|
-
var init_string_concat_loop = __esm({
|
|
31082
|
-
"src/rules/java/string-concat-loop.ts"() {
|
|
31083
|
-
"use strict";
|
|
31084
|
-
init_rule();
|
|
31085
|
-
STRING_CONCAT_REGEX = /(\b\w+)\s*=\s*\1\s*\+\s*[^;]+;|(\b\w+)\s*\+=\s*['"`]/g;
|
|
31086
|
-
javaStringConcatLoopRule = createRule({
|
|
31087
|
-
id: "java/string-concat-loop",
|
|
31088
|
-
category: "perf",
|
|
31089
|
-
severity: "low",
|
|
31090
|
-
aiSpecific: true,
|
|
31091
|
-
description: "String concatenation in a loop \u2014 use StringBuilder",
|
|
31092
|
-
create(_context) {
|
|
31093
|
-
return {};
|
|
31094
|
-
},
|
|
31095
|
-
analyze(_context, facts) {
|
|
31096
|
-
const issues = [];
|
|
31097
|
-
const source = facts.v2?._source;
|
|
31098
|
-
if (!source) return issues;
|
|
31099
|
-
if (!/\.java$/i.test(facts.filePath)) return issues;
|
|
31100
|
-
if (!/\b(for|while|do)\b/.test(source)) return issues;
|
|
31101
|
-
let m;
|
|
31102
|
-
STRING_CONCAT_REGEX.lastIndex = 0;
|
|
31103
|
-
while ((m = STRING_CONCAT_REGEX.exec(source)) !== null) {
|
|
31104
|
-
const line = source.slice(0, m.index).split("\n").length;
|
|
31105
|
-
issues.push({
|
|
31106
|
-
ruleId: "java/string-concat-loop",
|
|
31107
|
-
category: "perf",
|
|
31108
|
-
severity: "low",
|
|
31109
|
-
aiSpecific: true,
|
|
31110
|
-
message: `String concatenation in a loop at line ${line} \u2014 use StringBuilder`,
|
|
31111
|
-
line,
|
|
31112
|
-
column: 1,
|
|
31113
|
-
advice: "Declare a `StringBuilder` outside the loop: `StringBuilder sb = new StringBuilder(); sb.append(...);` then `return sb.toString();` after the loop. String concatenation in a loop is O(n\xB2) \u2014 each iteration copies the prior string. AI agents concatenate strings in loops because of training-data examples. Reference: java/string-concat-loop v0.20."
|
|
31114
|
-
});
|
|
31115
|
-
}
|
|
31116
|
-
return issues;
|
|
31117
|
-
}
|
|
31118
|
-
});
|
|
31119
|
-
}
|
|
31120
|
-
});
|
|
31121
|
-
|
|
31122
|
-
// src/rules/java/system-out-println.ts
|
|
31123
|
-
var PRINTLN_REGEX, DEFAULT_THRESHOLD2, javaSystemOutPrintlnRule;
|
|
31124
|
-
var init_system_out_println = __esm({
|
|
31125
|
-
"src/rules/java/system-out-println.ts"() {
|
|
31126
|
-
"use strict";
|
|
31127
|
-
init_rule();
|
|
31128
|
-
PRINTLN_REGEX = /System\.out\.println\s*\(/g;
|
|
31129
|
-
DEFAULT_THRESHOLD2 = 1;
|
|
31130
|
-
javaSystemOutPrintlnRule = createRule({
|
|
31131
|
-
id: "java/system-out-println",
|
|
31132
|
-
category: "typo",
|
|
31133
|
-
severity: "low",
|
|
31134
|
-
aiSpecific: true,
|
|
31135
|
-
description: "System.out.println in production code \u2014 use a logger (SLF4J, Log4j, etc.)",
|
|
31136
|
-
create(_context) {
|
|
31137
|
-
return { threshold: DEFAULT_THRESHOLD2 };
|
|
31138
|
-
},
|
|
31139
|
-
analyze(context, facts) {
|
|
31140
|
-
const issues = [];
|
|
31141
|
-
const source = facts.v2?._source;
|
|
31142
|
-
if (!source) return issues;
|
|
31143
|
-
if (!/\.java$/i.test(facts.filePath)) return issues;
|
|
31144
|
-
const matches = [];
|
|
31145
|
-
let m;
|
|
31146
|
-
PRINTLN_REGEX.lastIndex = 0;
|
|
31147
|
-
while ((m = PRINTLN_REGEX.exec(source)) !== null) {
|
|
31148
|
-
matches.push(m.index);
|
|
31149
|
-
}
|
|
31150
|
-
if (matches.length <= context.threshold) return issues;
|
|
31151
|
-
const cap = Math.min(matches.length, 10);
|
|
31152
|
-
for (let i = 0; i < cap; i++) {
|
|
31153
|
-
const idx = matches[i];
|
|
31154
|
-
const line = source.slice(0, idx).split("\n").length;
|
|
31155
|
-
issues.push({
|
|
31156
|
-
ruleId: "java/system-out-println",
|
|
31157
|
-
category: "typo",
|
|
31158
|
-
severity: "low",
|
|
31159
|
-
aiSpecific: true,
|
|
31160
|
-
message: `System.out.println at line ${line} \u2014 use a logger for production output`,
|
|
31161
|
-
line,
|
|
31162
|
-
column: 1,
|
|
31163
|
-
advice: "Replace with `private static final Logger log = LoggerFactory.getLogger(...);` then `log.info(...)`. AI agents default to println because their training data has countless textbook examples. Real Java code uses a logger. Reference: java/system-out-println v0.20."
|
|
31164
|
-
});
|
|
31165
|
-
}
|
|
31166
|
-
return issues;
|
|
31167
|
-
}
|
|
31168
|
-
});
|
|
31169
|
-
}
|
|
31170
|
-
});
|
|
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
|
-
|
|
31229
30646
|
// src/rules/kotlin/coroutine-global-scope.ts
|
|
31230
30647
|
var GLOBAL_SCOPE_REGEX, kotlinCoroutineGlobalScopeRule;
|
|
31231
30648
|
var init_coroutine_global_scope = __esm({
|
|
@@ -31246,7 +30663,7 @@ var init_coroutine_global_scope = __esm({
|
|
|
31246
30663
|
const issues = [];
|
|
31247
30664
|
const source = facts.v2?._source;
|
|
31248
30665
|
if (!source) return issues;
|
|
31249
|
-
if (!/\.
|
|
30666
|
+
if (!/\.kts?$/i.test(facts.filePath)) return issues;
|
|
31250
30667
|
let m;
|
|
31251
30668
|
GLOBAL_SCOPE_REGEX.lastIndex = 0;
|
|
31252
30669
|
while ((m = GLOBAL_SCOPE_REGEX.exec(source)) !== null) {
|
|
@@ -31290,7 +30707,7 @@ var init_data_class_defaults_overuse = __esm({
|
|
|
31290
30707
|
const issues = [];
|
|
31291
30708
|
const source = facts.v2?._source;
|
|
31292
30709
|
if (!source) return issues;
|
|
31293
|
-
if (!/\.
|
|
30710
|
+
if (!/\.kts?$/i.test(facts.filePath)) return issues;
|
|
31294
30711
|
let m;
|
|
31295
30712
|
DATA_CLASS_HEAD_REGEX.lastIndex = 0;
|
|
31296
30713
|
while ((m = DATA_CLASS_HEAD_REGEX.exec(source)) !== null) {
|
|
@@ -31352,7 +30769,7 @@ var init_object_singleton_misuse = __esm({
|
|
|
31352
30769
|
const issues = [];
|
|
31353
30770
|
const source = facts.v2?._source;
|
|
31354
30771
|
if (!source) return issues;
|
|
31355
|
-
if (!/\.
|
|
30772
|
+
if (!/\.kts?$/i.test(facts.filePath)) return issues;
|
|
31356
30773
|
let m;
|
|
31357
30774
|
OBJECT_DECL_REGEX.lastIndex = 0;
|
|
31358
30775
|
while ((m = OBJECT_DECL_REGEX.exec(source)) !== null) {
|
|
@@ -31390,13 +30807,13 @@ var init_object_singleton_misuse = __esm({
|
|
|
31390
30807
|
});
|
|
31391
30808
|
|
|
31392
30809
|
// src/rules/kotlin/println-debug.ts
|
|
31393
|
-
var
|
|
30810
|
+
var PRINTLN_REGEX, DEFAULT_THRESHOLD, kotlinPrintlnDebugRule;
|
|
31394
30811
|
var init_println_debug = __esm({
|
|
31395
30812
|
"src/rules/kotlin/println-debug.ts"() {
|
|
31396
30813
|
"use strict";
|
|
31397
30814
|
init_rule();
|
|
31398
|
-
|
|
31399
|
-
|
|
30815
|
+
PRINTLN_REGEX = /^\s*println\s*\(/gm;
|
|
30816
|
+
DEFAULT_THRESHOLD = 1;
|
|
31400
30817
|
kotlinPrintlnDebugRule = createRule({
|
|
31401
30818
|
id: "kotlin/println-debug",
|
|
31402
30819
|
category: "typo",
|
|
@@ -31404,17 +30821,17 @@ var init_println_debug = __esm({
|
|
|
31404
30821
|
aiSpecific: true,
|
|
31405
30822
|
description: "println(...) in production code \u2014 use Timber, android.util.Log, or an SLF4J facade",
|
|
31406
30823
|
create(_context) {
|
|
31407
|
-
return { threshold:
|
|
30824
|
+
return { threshold: DEFAULT_THRESHOLD };
|
|
31408
30825
|
},
|
|
31409
30826
|
analyze(context, facts) {
|
|
31410
30827
|
const issues = [];
|
|
31411
30828
|
const source = facts.v2?._source;
|
|
31412
30829
|
if (!source) return issues;
|
|
31413
|
-
if (!/\.
|
|
30830
|
+
if (!/\.kts?$/i.test(facts.filePath)) return issues;
|
|
31414
30831
|
const matches = [];
|
|
31415
30832
|
let m;
|
|
31416
|
-
|
|
31417
|
-
while ((m =
|
|
30833
|
+
PRINTLN_REGEX.lastIndex = 0;
|
|
30834
|
+
while ((m = PRINTLN_REGEX.exec(source)) !== null) {
|
|
31418
30835
|
matches.push(m.index);
|
|
31419
30836
|
}
|
|
31420
30837
|
if (matches.length <= context.threshold) return issues;
|
|
@@ -31440,12 +30857,12 @@ var init_println_debug = __esm({
|
|
|
31440
30857
|
});
|
|
31441
30858
|
|
|
31442
30859
|
// src/rules/kotlin/string-concat-loop.ts
|
|
31443
|
-
var
|
|
31444
|
-
var
|
|
30860
|
+
var STRING_CONCAT_REGEX, kotlinStringConcatLoopRule;
|
|
30861
|
+
var init_string_concat_loop = __esm({
|
|
31445
30862
|
"src/rules/kotlin/string-concat-loop.ts"() {
|
|
31446
30863
|
"use strict";
|
|
31447
30864
|
init_rule();
|
|
31448
|
-
|
|
30865
|
+
STRING_CONCAT_REGEX = /\b(\w+)\s*=\s*\1\s*\+\s*[^;}]+[;}\n]/g;
|
|
31449
30866
|
kotlinStringConcatLoopRule = createRule({
|
|
31450
30867
|
id: "kotlin/string-concat-loop",
|
|
31451
30868
|
category: "perf",
|
|
@@ -31459,11 +30876,11 @@ var init_string_concat_loop2 = __esm({
|
|
|
31459
30876
|
const issues = [];
|
|
31460
30877
|
const source = facts.v2?._source;
|
|
31461
30878
|
if (!source) return issues;
|
|
31462
|
-
if (!/\.
|
|
30879
|
+
if (!/\.kts?$/i.test(facts.filePath)) return issues;
|
|
31463
30880
|
if (!/\b(?:for|while|repeat|forEach)\b/.test(source)) return issues;
|
|
31464
30881
|
let m;
|
|
31465
|
-
|
|
31466
|
-
while ((m =
|
|
30882
|
+
STRING_CONCAT_REGEX.lastIndex = 0;
|
|
30883
|
+
while ((m = STRING_CONCAT_REGEX.exec(source)) !== null) {
|
|
31467
30884
|
const line = source.slice(0, m.index).split("\n").length;
|
|
31468
30885
|
const lineText = source.slice(0, m.index).split("\n").pop() ?? "";
|
|
31469
30886
|
if (/\.append\s*\(/.test(lineText)) continue;
|
|
@@ -36690,6 +36107,15 @@ function parseSource(source, filePath) {
|
|
|
36690
36107
|
case "go":
|
|
36691
36108
|
case "rs":
|
|
36692
36109
|
case "java":
|
|
36110
|
+
// v0.28.0: Kotlin files get the same parseBlankModule path as
|
|
36111
|
+
// Java (v0.24.5). All 5 `kotlin/*` rules are regex-based and
|
|
36112
|
+
// gate themselves on `/\.kts?$/i.test(filePath)` inside their
|
|
36113
|
+
// `analyze()`. The tree-sitter Kotlin integration is a larger
|
|
36114
|
+
// lift; the v0.27.0 methodology paper confirmed era-confounding
|
|
36115
|
+
// is the dominant signal anyway, so a regex-only Kotlin pass is
|
|
36116
|
+
// sufficient for the v9 calibration goal.
|
|
36117
|
+
case "kt":
|
|
36118
|
+
case "kts":
|
|
36693
36119
|
return parseBlankModule(source);
|
|
36694
36120
|
default:
|
|
36695
36121
|
return parseWithSwc(source, filePath);
|
|
@@ -41109,13 +40535,13 @@ var init_implicitly_unwrapped_optional = __esm({
|
|
|
41109
40535
|
});
|
|
41110
40536
|
|
|
41111
40537
|
// src/rules/swift/print-debug.ts
|
|
41112
|
-
var PRINT_REGEX,
|
|
40538
|
+
var PRINT_REGEX, DEFAULT_THRESHOLD2, swiftPrintDebugRule;
|
|
41113
40539
|
var init_print_debug = __esm({
|
|
41114
40540
|
"src/rules/swift/print-debug.ts"() {
|
|
41115
40541
|
"use strict";
|
|
41116
40542
|
init_rule();
|
|
41117
40543
|
PRINT_REGEX = /\bprint\s*\(/g;
|
|
41118
|
-
|
|
40544
|
+
DEFAULT_THRESHOLD2 = 1;
|
|
41119
40545
|
swiftPrintDebugRule = createRule({
|
|
41120
40546
|
id: "swift/print-debug",
|
|
41121
40547
|
category: "typo",
|
|
@@ -41123,7 +40549,7 @@ var init_print_debug = __esm({
|
|
|
41123
40549
|
aiSpecific: true,
|
|
41124
40550
|
description: "print(...) in production Swift \u2014 use Logger (os.log) for level-controlled output",
|
|
41125
40551
|
create(_context) {
|
|
41126
|
-
return { threshold:
|
|
40552
|
+
return { threshold: DEFAULT_THRESHOLD2 };
|
|
41127
40553
|
},
|
|
41128
40554
|
analyze(context, facts) {
|
|
41129
40555
|
const issues = [];
|
|
@@ -46873,22 +46299,11 @@ var init_builtins = __esm({
|
|
|
46873
46299
|
init_error_wrap_without_context();
|
|
46874
46300
|
init_nil_slice_vs_empty();
|
|
46875
46301
|
init_struct_tag_inconsistency();
|
|
46876
|
-
init_arraylist_vs_linkedlist();
|
|
46877
|
-
init_builder_overuse();
|
|
46878
|
-
init_empty_catch_block();
|
|
46879
|
-
init_immutable_collection_preference();
|
|
46880
|
-
init_legacy_date_api();
|
|
46881
|
-
init_optional_overuse();
|
|
46882
|
-
init_raw_type_overuse();
|
|
46883
|
-
init_stream_overuse();
|
|
46884
|
-
init_string_concat_loop();
|
|
46885
|
-
init_system_out_println();
|
|
46886
|
-
init_verbose_javadoc();
|
|
46887
46302
|
init_coroutine_global_scope();
|
|
46888
46303
|
init_data_class_defaults_overuse();
|
|
46889
46304
|
init_object_singleton_misuse();
|
|
46890
46305
|
init_println_debug();
|
|
46891
|
-
|
|
46306
|
+
init_string_concat_loop();
|
|
46892
46307
|
init_gap_monopoly();
|
|
46893
46308
|
init_math_element_uniformity();
|
|
46894
46309
|
init_math_grid_uniformity();
|
|
@@ -47013,17 +46428,6 @@ var init_builtins = __esm({
|
|
|
47013
46428
|
goErrorWrapWithoutContextRule,
|
|
47014
46429
|
goNilSliceVsEmptyRule,
|
|
47015
46430
|
goStructTagInconsistencyRule,
|
|
47016
|
-
javaArraylistVsLinkedlistRule,
|
|
47017
|
-
javaBuilderOveruseRule,
|
|
47018
|
-
javaEmptyCatchBlockRule,
|
|
47019
|
-
javaImmutableCollectionPreferenceRule,
|
|
47020
|
-
javaLegacyDateApiRule,
|
|
47021
|
-
javaOptionalOveruseRule,
|
|
47022
|
-
javaRawTypeOveruseRule,
|
|
47023
|
-
javaStreamOveruseRule,
|
|
47024
|
-
javaStringConcatLoopRule,
|
|
47025
|
-
javaSystemOutPrintlnRule,
|
|
47026
|
-
javaVerboseJavadocRule,
|
|
47027
46431
|
kotlinCoroutineGlobalScopeRule,
|
|
47028
46432
|
kotlinDataClassDefaultsOveruseRule,
|
|
47029
46433
|
kotlinObjectSingletonMisuseRule,
|
|
@@ -50190,224 +49594,6 @@ var init_signal_strength = __esm({
|
|
|
50190
49594
|
_v8Lift: 1,
|
|
50191
49595
|
defaultOff: true
|
|
50192
49596
|
},
|
|
50193
|
-
"java/arraylist-vs-linkedlist": {
|
|
50194
|
-
recall: 35e-4,
|
|
50195
|
-
fpRate: 94e-4,
|
|
50196
|
-
ratio: 0.37,
|
|
50197
|
-
precision: 0.0446,
|
|
50198
|
-
lastCalibratedAt: "2026-07-02T19:34:00Z",
|
|
50199
|
-
verdict: "DORMANT",
|
|
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).",
|
|
50201
|
-
aiSpecific: true,
|
|
50202
|
-
_v7Verdict: "DORMANT",
|
|
50203
|
-
_v7Lift: 1,
|
|
50204
|
-
_v7Recall: 0,
|
|
50205
|
-
_v7FpRate: 0,
|
|
50206
|
-
_v7Precision: 0,
|
|
50207
|
-
_v8Verdict: "DORMANT",
|
|
50208
|
-
_v8Lift: 1,
|
|
50209
|
-
_v9Verdict: "DORMANT",
|
|
50210
|
-
_v9Lift: 4.74,
|
|
50211
|
-
_v9Recall: 35e-4,
|
|
50212
|
-
_v9FpRate: 94e-4,
|
|
50213
|
-
_v9Precision: 0.0446,
|
|
50214
|
-
defaultOff: true
|
|
50215
|
-
},
|
|
50216
|
-
"java/empty-catch-block": {
|
|
50217
|
-
recall: 8e-3,
|
|
50218
|
-
fpRate: 0.1118,
|
|
50219
|
-
ratio: 0.07,
|
|
50220
|
-
precision: 89e-4,
|
|
50221
|
-
lastCalibratedAt: "2026-07-02T19:34:00Z",
|
|
50222
|
-
verdict: "DORMANT",
|
|
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.",
|
|
50224
|
-
aiSpecific: true,
|
|
50225
|
-
_v7Verdict: "DORMANT",
|
|
50226
|
-
_v7Lift: 1,
|
|
50227
|
-
_v7Recall: 0,
|
|
50228
|
-
_v7FpRate: 0,
|
|
50229
|
-
_v7Precision: 0,
|
|
50230
|
-
_v8Verdict: "DORMANT",
|
|
50231
|
-
_v8Lift: 1,
|
|
50232
|
-
_v9Verdict: "DORMANT",
|
|
50233
|
-
_v9Lift: 0.08,
|
|
50234
|
-
_v9Recall: 8e-3,
|
|
50235
|
-
_v9FpRate: 0.1118,
|
|
50236
|
-
_v9Precision: 89e-4,
|
|
50237
|
-
defaultOff: true
|
|
50238
|
-
},
|
|
50239
|
-
"java/legacy-date-api": {
|
|
50240
|
-
recall: 0.0285,
|
|
50241
|
-
fpRate: 0.0511,
|
|
50242
|
-
ratio: 0.56,
|
|
50243
|
-
precision: 0.0657,
|
|
50244
|
-
lastCalibratedAt: "2026-07-02T19:34:00Z",
|
|
50245
|
-
verdict: "DORMANT",
|
|
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.",
|
|
50247
|
-
aiSpecific: true,
|
|
50248
|
-
_v7Verdict: "DORMANT",
|
|
50249
|
-
_v7Lift: 1,
|
|
50250
|
-
_v7Recall: 0,
|
|
50251
|
-
_v7FpRate: 0,
|
|
50252
|
-
_v7Precision: 0,
|
|
50253
|
-
_v8Verdict: "DORMANT",
|
|
50254
|
-
_v8Lift: 1,
|
|
50255
|
-
_v9Verdict: "DORMANT",
|
|
50256
|
-
_v9Lift: 1.29,
|
|
50257
|
-
_v9Recall: 0.0285,
|
|
50258
|
-
_v9FpRate: 0.0511,
|
|
50259
|
-
_v9Precision: 0.0657,
|
|
50260
|
-
defaultOff: true
|
|
50261
|
-
},
|
|
50262
|
-
"java/verbose-javadoc": {
|
|
50263
|
-
recall: 0,
|
|
50264
|
-
fpRate: 0,
|
|
50265
|
-
ratio: 1,
|
|
50266
|
-
precision: 0,
|
|
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. v0.26.1 CALIBRATION (14769-file biased sample from v9-java corpus, files that fired >=1 of the 6 existing java rules): TP=0, FP=0, ratio=N/A. HYPOTHESIS FAILED. The v0.26.0 intuition that 'AI over-documents trivial methods' is NOT supported by the v9 corpus \u2014 AI code in Spring AI, LangChain4j, etc. has the same Javadoc density as human code. v0.20 hypothesis (humans avoid println/Date/raw types) and v0.26 hypothesis (AI over-documents/over-Opts/over-Builders) are both wrong for the v9 corpus. v0.27+ will redesign with a different approach: either train a classifier on the v9 features or use AST-based detection rather than regex heuristics. Reference: java/verbose-javadoc v0.26.0; calibration v0.26.1.",
|
|
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",
|
|
50284
|
-
verdict: "DORMANT",
|
|
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). v0.26.1 CALIBRATION (14769-file biased sample): TP=0, FP=0, ratio=N/A. HYPOTHESIS FAILED. AI in the v9 corpus does NOT use Optional chains more than humans. v0.27+ will redesign. Reference: java/optional-overuse v0.26.0; calibration v0.26.1.",
|
|
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. v0.26.1 CALIBRATION (14769-file biased sample): TP=0, FP=0, ratio=N/A. HYPOTHESIS FAILED. AI does NOT use immutable factory methods more than humans. v0.27+ will redesign. Reference: java/immutable-collection-preference v0.26.0; calibration v0.26.1.",
|
|
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. v0.26.1 CALIBRATION (14769-file biased sample): TP=0, FP=0, ratio=N/A. HYPOTHESIS FAILED. AI does NOT use @Builder on small classes more than humans. v0.27+ will redesign. Reference: java/builder-overuse v0.26.0; calibration v0.26.1.",
|
|
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). v0.26.1 CALIBRATION (14769-file biased sample): TP=0, FP=0, ratio=N/A. HYPOTHESIS FAILED. AI does NOT use Stream API chains more than humans. v0.27+ will redesign. Reference: java/stream-overuse v0.26.0; calibration v0.26.1.",
|
|
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.",
|
|
50350
|
-
aiSpecific: true,
|
|
50351
|
-
_v7Verdict: "DORMANT",
|
|
50352
|
-
_v7Lift: 1,
|
|
50353
|
-
_v7Recall: 0,
|
|
50354
|
-
_v7FpRate: 0,
|
|
50355
|
-
_v7Precision: 0,
|
|
50356
|
-
_v8Verdict: "DORMANT",
|
|
50357
|
-
_v8Lift: 1,
|
|
50358
|
-
_v9Verdict: "DORMANT",
|
|
50359
|
-
_v9Lift: 0.31,
|
|
50360
|
-
_v9Recall: 0.1093,
|
|
50361
|
-
_v9FpRate: 0.2041,
|
|
50362
|
-
_v9Precision: 0.0632,
|
|
50363
|
-
defaultOff: true
|
|
50364
|
-
},
|
|
50365
|
-
"java/string-concat-loop": {
|
|
50366
|
-
recall: 46e-4,
|
|
50367
|
-
fpRate: 0.0358,
|
|
50368
|
-
ratio: 0.13,
|
|
50369
|
-
precision: 0.0158,
|
|
50370
|
-
lastCalibratedAt: "2026-07-02T19:34:00Z",
|
|
50371
|
-
verdict: "DORMANT",
|
|
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.",
|
|
50373
|
-
aiSpecific: true,
|
|
50374
|
-
_v7Verdict: "DORMANT",
|
|
50375
|
-
_v7Lift: 1,
|
|
50376
|
-
_v7Recall: 0,
|
|
50377
|
-
_v7FpRate: 0,
|
|
50378
|
-
_v7Precision: 0,
|
|
50379
|
-
_v8Verdict: "DORMANT",
|
|
50380
|
-
_v8Lift: 1,
|
|
50381
|
-
_v9Verdict: "DORMANT",
|
|
50382
|
-
_v9Lift: 0.44,
|
|
50383
|
-
_v9Recall: 46e-4,
|
|
50384
|
-
_v9FpRate: 0.0358,
|
|
50385
|
-
_v9Precision: 0.0158,
|
|
50386
|
-
defaultOff: true
|
|
50387
|
-
},
|
|
50388
|
-
"java/system-out-println": {
|
|
50389
|
-
recall: 0.1503,
|
|
50390
|
-
fpRate: 0.2533,
|
|
50391
|
-
ratio: 0.59,
|
|
50392
|
-
precision: 0.0695,
|
|
50393
|
-
lastCalibratedAt: "2026-07-02T19:34:00Z",
|
|
50394
|
-
verdict: "DORMANT",
|
|
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.",
|
|
50396
|
-
aiSpecific: true,
|
|
50397
|
-
_v7Verdict: "DORMANT",
|
|
50398
|
-
_v7Lift: 1,
|
|
50399
|
-
_v7Recall: 0,
|
|
50400
|
-
_v7FpRate: 0,
|
|
50401
|
-
_v7Precision: 0,
|
|
50402
|
-
_v8Verdict: "DORMANT",
|
|
50403
|
-
_v8Lift: 1,
|
|
50404
|
-
_v9Verdict: "DORMANT",
|
|
50405
|
-
_v9Lift: 0.27,
|
|
50406
|
-
_v9Recall: 0.1503,
|
|
50407
|
-
_v9FpRate: 0.2533,
|
|
50408
|
-
_v9Precision: 0.0695,
|
|
50409
|
-
defaultOff: true
|
|
50410
|
-
},
|
|
50411
49597
|
"layout/forced-layout": {
|
|
50412
49598
|
recall: 0,
|
|
50413
49599
|
fpRate: 0,
|
|
@@ -51652,13 +50838,13 @@ var init_signal_strength = __esm({
|
|
|
51652
50838
|
defaultOff: true
|
|
51653
50839
|
},
|
|
51654
50840
|
"kotlin/data-class-defaults-overuse": {
|
|
51655
|
-
recall:
|
|
51656
|
-
fpRate:
|
|
51657
|
-
ratio:
|
|
51658
|
-
precision: 0,
|
|
51659
|
-
lastCalibratedAt: "2026-07-
|
|
50841
|
+
recall: 469e-5,
|
|
50842
|
+
fpRate: 222e-5,
|
|
50843
|
+
ratio: 2.11,
|
|
50844
|
+
precision: 0.1429,
|
|
50845
|
+
lastCalibratedAt: "2026-07-03T00:00:00Z",
|
|
51660
50846
|
verdict: "DORMANT",
|
|
51661
|
-
_calibrationNote: "v0.
|
|
50847
|
+
_calibrationNote: "v0.28: v9 Kotlin calibration (2698 neg, 213 pos). ratio=2.11 (\u22651.5) but precision=14.3% (<50%) \u2014 verdict DORMANT. Era-confounding: pre-2022 Kotlin is sparse; the rule fires on the rare .kt file with multiple default values regardless of authorship.",
|
|
51662
50848
|
aiSpecific: true,
|
|
51663
50849
|
_v7Verdict: "DORMANT",
|
|
51664
50850
|
_v7Lift: 1,
|
|
@@ -51667,16 +50853,21 @@ var init_signal_strength = __esm({
|
|
|
51667
50853
|
_v7Precision: 0,
|
|
51668
50854
|
_v8Verdict: "DORMANT",
|
|
51669
50855
|
_v8Lift: 1,
|
|
50856
|
+
_v9Verdict: "DORMANT",
|
|
50857
|
+
_v9Lift: 2.11,
|
|
50858
|
+
_v9Recall: 469e-5,
|
|
50859
|
+
_v9FpRate: 222e-5,
|
|
50860
|
+
_v9Precision: 0.1429,
|
|
51670
50861
|
defaultOff: true
|
|
51671
50862
|
},
|
|
51672
50863
|
"kotlin/coroutine-global-scope": {
|
|
51673
|
-
recall:
|
|
51674
|
-
fpRate: 0,
|
|
51675
|
-
ratio:
|
|
51676
|
-
precision:
|
|
51677
|
-
lastCalibratedAt: "2026-07-
|
|
50864
|
+
recall: 469e-5,
|
|
50865
|
+
fpRate: 0.05004,
|
|
50866
|
+
ratio: 0.09,
|
|
50867
|
+
precision: 735e-5,
|
|
50868
|
+
lastCalibratedAt: "2026-07-03T00:00:00Z",
|
|
51678
50869
|
verdict: "DORMANT",
|
|
51679
|
-
_calibrationNote: "v0.
|
|
50870
|
+
_calibrationNote: "v0.28: v9 Kotlin calibration (2698 neg, 213 pos). ratio=0.09 (FAR <1.0) \u2014 fires 135x more on neg than pos. Classic era-confound: pre-2022 Kotlin coroutines had GlobalScope as the default; modern Kotlin uses viewModelScope / lifecycleScope. The rule detects era, not AI authorship.",
|
|
51680
50871
|
aiSpecific: true,
|
|
51681
50872
|
_v7Verdict: "DORMANT",
|
|
51682
50873
|
_v7Lift: 1,
|
|
@@ -51685,16 +50876,21 @@ var init_signal_strength = __esm({
|
|
|
51685
50876
|
_v7Precision: 0,
|
|
51686
50877
|
_v8Verdict: "DORMANT",
|
|
51687
50878
|
_v8Lift: 1,
|
|
50879
|
+
_v9Verdict: "DORMANT",
|
|
50880
|
+
_v9Lift: 0.09,
|
|
50881
|
+
_v9Recall: 469e-5,
|
|
50882
|
+
_v9FpRate: 0.05004,
|
|
50883
|
+
_v9Precision: 735e-5,
|
|
51688
50884
|
defaultOff: true
|
|
51689
50885
|
},
|
|
51690
50886
|
"kotlin/println-debug": {
|
|
51691
|
-
recall: 0,
|
|
51692
|
-
fpRate: 0,
|
|
51693
|
-
ratio:
|
|
51694
|
-
precision: 0,
|
|
51695
|
-
lastCalibratedAt: "2026-07-
|
|
50887
|
+
recall: 0.07042,
|
|
50888
|
+
fpRate: 0.11379,
|
|
50889
|
+
ratio: 0.62,
|
|
50890
|
+
precision: 0.04659,
|
|
50891
|
+
lastCalibratedAt: "2026-07-03T00:00:00Z",
|
|
51696
50892
|
verdict: "DORMANT",
|
|
51697
|
-
_calibrationNote: "v0.
|
|
50893
|
+
_calibrationNote: "v0.28: v9 Kotlin calibration (2698 neg, 213 pos). ratio=0.62 (\u226A1.0) \u2014 fires 20x more on neg than pos. Classic era-confound: pre-2022 Kotlin code uses println() for debug; modern Kotlin uses Timber / android.util.Log / kermit.",
|
|
51698
50894
|
aiSpecific: true,
|
|
51699
50895
|
_v7Verdict: "DORMANT",
|
|
51700
50896
|
_v7Lift: 1,
|
|
@@ -51703,16 +50899,21 @@ var init_signal_strength = __esm({
|
|
|
51703
50899
|
_v7Precision: 0,
|
|
51704
50900
|
_v8Verdict: "DORMANT",
|
|
51705
50901
|
_v8Lift: 1,
|
|
50902
|
+
_v9Verdict: "DORMANT",
|
|
50903
|
+
_v9Lift: 0.62,
|
|
50904
|
+
_v9Recall: 0.07042,
|
|
50905
|
+
_v9FpRate: 0.11379,
|
|
50906
|
+
_v9Precision: 0.04659,
|
|
51706
50907
|
defaultOff: true
|
|
51707
50908
|
},
|
|
51708
50909
|
"kotlin/object-singleton-misuse": {
|
|
51709
|
-
recall:
|
|
51710
|
-
fpRate:
|
|
51711
|
-
ratio: 1,
|
|
51712
|
-
precision: 0,
|
|
51713
|
-
lastCalibratedAt: "2026-07-
|
|
50910
|
+
recall: 469e-5,
|
|
50911
|
+
fpRate: 371e-5,
|
|
50912
|
+
ratio: 1.27,
|
|
50913
|
+
precision: 0.09091,
|
|
50914
|
+
lastCalibratedAt: "2026-07-03T00:00:00Z",
|
|
51714
50915
|
verdict: "DORMANT",
|
|
51715
|
-
_calibrationNote: "v0.
|
|
50916
|
+
_calibrationNote: "v0.28: v9 Kotlin calibration (2698 neg, 213 pos). ratio=1.27 (\u22651.0) but <1.5; precision=9.1% \u2014 verdict DORMANT. INSUFFICIENT_DATA: pos arm only 213 files (under 10k minimum).",
|
|
51716
50917
|
aiSpecific: true,
|
|
51717
50918
|
_v7Verdict: "DORMANT",
|
|
51718
50919
|
_v7Lift: 1,
|
|
@@ -51721,16 +50922,21 @@ var init_signal_strength = __esm({
|
|
|
51721
50922
|
_v7Precision: 0,
|
|
51722
50923
|
_v8Verdict: "DORMANT",
|
|
51723
50924
|
_v8Lift: 1,
|
|
50925
|
+
_v9Verdict: "DORMANT",
|
|
50926
|
+
_v9Lift: 1.27,
|
|
50927
|
+
_v9Recall: 469e-5,
|
|
50928
|
+
_v9FpRate: 371e-5,
|
|
50929
|
+
_v9Precision: 0.09091,
|
|
51724
50930
|
defaultOff: true
|
|
51725
50931
|
},
|
|
51726
50932
|
"kotlin/string-concat-loop": {
|
|
51727
|
-
recall:
|
|
51728
|
-
fpRate:
|
|
51729
|
-
ratio: 1,
|
|
51730
|
-
precision: 0,
|
|
51731
|
-
lastCalibratedAt: "2026-07-
|
|
50933
|
+
recall: 939e-5,
|
|
50934
|
+
fpRate: 519e-5,
|
|
50935
|
+
ratio: 1.81,
|
|
50936
|
+
precision: 0.125,
|
|
50937
|
+
lastCalibratedAt: "2026-07-03T00:00:00Z",
|
|
51732
50938
|
verdict: "DORMANT",
|
|
51733
|
-
_calibrationNote: "v0.
|
|
50939
|
+
_calibrationNote: "v0.28: v9 Kotlin calibration (2698 neg, 213 pos). ratio=1.81 (\u22651.5) but precision=12.5% (<50%) \u2014 verdict DORMANT. INSUFFICIENT_DATA: pos arm only 213 files.",
|
|
51734
50940
|
aiSpecific: true,
|
|
51735
50941
|
_v7Verdict: "DORMANT",
|
|
51736
50942
|
_v7Lift: 1,
|
|
@@ -51739,6 +50945,11 @@ var init_signal_strength = __esm({
|
|
|
51739
50945
|
_v7Precision: 0,
|
|
51740
50946
|
_v8Verdict: "DORMANT",
|
|
51741
50947
|
_v8Lift: 1,
|
|
50948
|
+
_v9Verdict: "DORMANT",
|
|
50949
|
+
_v9Lift: 1.81,
|
|
50950
|
+
_v9Recall: 939e-5,
|
|
50951
|
+
_v9FpRate: 519e-5,
|
|
50952
|
+
_v9Precision: 0.125,
|
|
51742
50953
|
defaultOff: true
|
|
51743
50954
|
},
|
|
51744
50955
|
"swift/force-unwrap": {
|
|
@@ -52003,8 +51214,6 @@ async function scanFile(filePath, config, registry, cwd = process.cwd()) {
|
|
|
52003
51214
|
const ext = extname5(filePath).toLowerCase();
|
|
52004
51215
|
const UNSUPPORTED_LANGS = /* @__PURE__ */ new Set([
|
|
52005
51216
|
".swift",
|
|
52006
|
-
".kt",
|
|
52007
|
-
".kts",
|
|
52008
51217
|
".dart",
|
|
52009
51218
|
".cpp",
|
|
52010
51219
|
".cc",
|
|
@@ -59870,18 +59079,6 @@ var RULE_HINTS = {
|
|
|
59870
59079
|
"dup/near-duplicate": "Refactor to a shared helper. Type-2 near-duplicate: same identifiers + structure, different whitespace/comments. AI-iterated code regenerates the same function with cosmetic edits. (v0.23.0 \u2014 MinHash + LSH, k=5, thr 0.7.)",
|
|
59871
59080
|
// v0.24.0 — Type-3 structural clone detector (two-stage MinHash)
|
|
59872
59081
|
"dup/structural-clone": "Refactor to a shared helper. Type-3 clone: same shape as another file after identifier canonicalization, with renames and/or added/removed statements. AI agents and copy-paste both produce this. Extract the shared part. (v0.24.0.)",
|
|
59873
|
-
// v0.20.0 — Java-specific rules
|
|
59874
|
-
"java/system-out-println": "Replace with `private static final Logger log = LoggerFactory.getLogger(...);` then `log.info(...)`. AI agents default to println because of textbook examples; real Java code uses a logger.",
|
|
59875
|
-
"java/empty-catch-block": 'Log the exception (`log.error("...", e)`), re-throw it, or both. Empty catch blocks hide bugs. Common in AI-generated code that wants to look defensive.',
|
|
59876
|
-
"java/arraylist-vs-linkedlist": "Replace `new LinkedList<>()` with `new ArrayList<>()`. LinkedList is rarely the right choice (worse cache locality, 5x more memory per element, O(n) indexed access). Joshua Bloch recommends ArrayList unless you need a Deque.",
|
|
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.",
|
|
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.",
|
|
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.)",
|
|
59885
59082
|
// v0.24.0 — Kotlin rules (DORMANT until v9 Kotlin corpus calibration)
|
|
59886
59083
|
"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.",
|
|
59887
59084
|
"kotlin/coroutine-global-scope": "Replace with `viewModelScope.launch { ... }`, `lifecycleScope.launch { ... }`, or `coroutineScope { ... }`. GlobalScope bypasses cancellation. (v0.24.0 \u2014 DORMANT.)",
|