slopbrick 0.25.1 → 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 +343 -6
- package/dist/engine/worker.js +343 -6
- package/dist/index.cjs +392 -10
- package/dist/index.js +392 -10
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -19,7 +19,7 @@ var VERSION;
|
|
|
19
19
|
var init_header = __esm({
|
|
20
20
|
"src/types/_header.ts"() {
|
|
21
21
|
"use strict";
|
|
22
|
-
VERSION = "0.
|
|
22
|
+
VERSION = "0.26.0";
|
|
23
23
|
}
|
|
24
24
|
});
|
|
25
25
|
|
|
@@ -30685,6 +30685,55 @@ var init_arraylist_vs_linkedlist = __esm({
|
|
|
30685
30685
|
}
|
|
30686
30686
|
});
|
|
30687
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
|
+
|
|
30688
30737
|
// src/rules/java/empty-catch-block.ts
|
|
30689
30738
|
var SINGLE_LINE_EMPTY_CATCH_REGEX, javaEmptyCatchBlockRule;
|
|
30690
30739
|
var init_empty_catch_block = __esm({
|
|
@@ -30727,6 +30776,65 @@ var init_empty_catch_block = __esm({
|
|
|
30727
30776
|
}
|
|
30728
30777
|
});
|
|
30729
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
|
+
|
|
30730
30838
|
// src/rules/java/legacy-date-api.ts
|
|
30731
30839
|
var LEGACY_IMPORT_REGEX, LEGACY_USAGE_REGEX, CALENDAR_GET_INSTANCE_REGEX, javaLegacyDateApiRule;
|
|
30732
30840
|
var init_legacy_date_api = __esm({
|
|
@@ -30803,6 +30911,59 @@ var init_legacy_date_api = __esm({
|
|
|
30803
30911
|
}
|
|
30804
30912
|
});
|
|
30805
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
|
+
|
|
30806
30967
|
// src/rules/java/raw-type-overuse.ts
|
|
30807
30968
|
var RAW_TYPE_REGEX, javaRawTypeOveruseRule;
|
|
30808
30969
|
var init_raw_type_overuse = __esm({
|
|
@@ -30846,6 +31007,75 @@ var init_raw_type_overuse = __esm({
|
|
|
30846
31007
|
}
|
|
30847
31008
|
});
|
|
30848
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
|
+
|
|
30849
31079
|
// src/rules/java/string-concat-loop.ts
|
|
30850
31080
|
var STRING_CONCAT_REGEX, javaStringConcatLoopRule;
|
|
30851
31081
|
var init_string_concat_loop = __esm({
|
|
@@ -30890,13 +31120,13 @@ var init_string_concat_loop = __esm({
|
|
|
30890
31120
|
});
|
|
30891
31121
|
|
|
30892
31122
|
// src/rules/java/system-out-println.ts
|
|
30893
|
-
var PRINTLN_REGEX,
|
|
31123
|
+
var PRINTLN_REGEX, DEFAULT_THRESHOLD2, javaSystemOutPrintlnRule;
|
|
30894
31124
|
var init_system_out_println = __esm({
|
|
30895
31125
|
"src/rules/java/system-out-println.ts"() {
|
|
30896
31126
|
"use strict";
|
|
30897
31127
|
init_rule();
|
|
30898
31128
|
PRINTLN_REGEX = /System\.out\.println\s*\(/g;
|
|
30899
|
-
|
|
31129
|
+
DEFAULT_THRESHOLD2 = 1;
|
|
30900
31130
|
javaSystemOutPrintlnRule = createRule({
|
|
30901
31131
|
id: "java/system-out-println",
|
|
30902
31132
|
category: "typo",
|
|
@@ -30904,7 +31134,7 @@ var init_system_out_println = __esm({
|
|
|
30904
31134
|
aiSpecific: true,
|
|
30905
31135
|
description: "System.out.println in production code \u2014 use a logger (SLF4J, Log4j, etc.)",
|
|
30906
31136
|
create(_context) {
|
|
30907
|
-
return { threshold:
|
|
31137
|
+
return { threshold: DEFAULT_THRESHOLD2 };
|
|
30908
31138
|
},
|
|
30909
31139
|
analyze(context, facts) {
|
|
30910
31140
|
const issues = [];
|
|
@@ -30939,6 +31169,63 @@ var init_system_out_println = __esm({
|
|
|
30939
31169
|
}
|
|
30940
31170
|
});
|
|
30941
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
|
+
|
|
30942
31229
|
// src/rules/kotlin/coroutine-global-scope.ts
|
|
30943
31230
|
var GLOBAL_SCOPE_REGEX, kotlinCoroutineGlobalScopeRule;
|
|
30944
31231
|
var init_coroutine_global_scope = __esm({
|
|
@@ -31103,13 +31390,13 @@ var init_object_singleton_misuse = __esm({
|
|
|
31103
31390
|
});
|
|
31104
31391
|
|
|
31105
31392
|
// src/rules/kotlin/println-debug.ts
|
|
31106
|
-
var PRINTLN_REGEX2,
|
|
31393
|
+
var PRINTLN_REGEX2, DEFAULT_THRESHOLD3, kotlinPrintlnDebugRule;
|
|
31107
31394
|
var init_println_debug = __esm({
|
|
31108
31395
|
"src/rules/kotlin/println-debug.ts"() {
|
|
31109
31396
|
"use strict";
|
|
31110
31397
|
init_rule();
|
|
31111
31398
|
PRINTLN_REGEX2 = /^\s*println\s*\(/gm;
|
|
31112
|
-
|
|
31399
|
+
DEFAULT_THRESHOLD3 = 1;
|
|
31113
31400
|
kotlinPrintlnDebugRule = createRule({
|
|
31114
31401
|
id: "kotlin/println-debug",
|
|
31115
31402
|
category: "typo",
|
|
@@ -31117,7 +31404,7 @@ var init_println_debug = __esm({
|
|
|
31117
31404
|
aiSpecific: true,
|
|
31118
31405
|
description: "println(...) in production code \u2014 use Timber, android.util.Log, or an SLF4J facade",
|
|
31119
31406
|
create(_context) {
|
|
31120
|
-
return { threshold:
|
|
31407
|
+
return { threshold: DEFAULT_THRESHOLD3 };
|
|
31121
31408
|
},
|
|
31122
31409
|
analyze(context, facts) {
|
|
31123
31410
|
const issues = [];
|
|
@@ -40822,13 +41109,13 @@ var init_implicitly_unwrapped_optional = __esm({
|
|
|
40822
41109
|
});
|
|
40823
41110
|
|
|
40824
41111
|
// src/rules/swift/print-debug.ts
|
|
40825
|
-
var PRINT_REGEX,
|
|
41112
|
+
var PRINT_REGEX, DEFAULT_THRESHOLD4, swiftPrintDebugRule;
|
|
40826
41113
|
var init_print_debug = __esm({
|
|
40827
41114
|
"src/rules/swift/print-debug.ts"() {
|
|
40828
41115
|
"use strict";
|
|
40829
41116
|
init_rule();
|
|
40830
41117
|
PRINT_REGEX = /\bprint\s*\(/g;
|
|
40831
|
-
|
|
41118
|
+
DEFAULT_THRESHOLD4 = 1;
|
|
40832
41119
|
swiftPrintDebugRule = createRule({
|
|
40833
41120
|
id: "swift/print-debug",
|
|
40834
41121
|
category: "typo",
|
|
@@ -40836,7 +41123,7 @@ var init_print_debug = __esm({
|
|
|
40836
41123
|
aiSpecific: true,
|
|
40837
41124
|
description: "print(...) in production Swift \u2014 use Logger (os.log) for level-controlled output",
|
|
40838
41125
|
create(_context) {
|
|
40839
|
-
return { threshold:
|
|
41126
|
+
return { threshold: DEFAULT_THRESHOLD4 };
|
|
40840
41127
|
},
|
|
40841
41128
|
analyze(context, facts) {
|
|
40842
41129
|
const issues = [];
|
|
@@ -46587,11 +46874,16 @@ var init_builtins = __esm({
|
|
|
46587
46874
|
init_nil_slice_vs_empty();
|
|
46588
46875
|
init_struct_tag_inconsistency();
|
|
46589
46876
|
init_arraylist_vs_linkedlist();
|
|
46877
|
+
init_builder_overuse();
|
|
46590
46878
|
init_empty_catch_block();
|
|
46879
|
+
init_immutable_collection_preference();
|
|
46591
46880
|
init_legacy_date_api();
|
|
46881
|
+
init_optional_overuse();
|
|
46592
46882
|
init_raw_type_overuse();
|
|
46883
|
+
init_stream_overuse();
|
|
46593
46884
|
init_string_concat_loop();
|
|
46594
46885
|
init_system_out_println();
|
|
46886
|
+
init_verbose_javadoc();
|
|
46595
46887
|
init_coroutine_global_scope();
|
|
46596
46888
|
init_data_class_defaults_overuse();
|
|
46597
46889
|
init_object_singleton_misuse();
|
|
@@ -46722,11 +47014,16 @@ var init_builtins = __esm({
|
|
|
46722
47014
|
goNilSliceVsEmptyRule,
|
|
46723
47015
|
goStructTagInconsistencyRule,
|
|
46724
47016
|
javaArraylistVsLinkedlistRule,
|
|
47017
|
+
javaBuilderOveruseRule,
|
|
46725
47018
|
javaEmptyCatchBlockRule,
|
|
47019
|
+
javaImmutableCollectionPreferenceRule,
|
|
46726
47020
|
javaLegacyDateApiRule,
|
|
47021
|
+
javaOptionalOveruseRule,
|
|
46727
47022
|
javaRawTypeOveruseRule,
|
|
47023
|
+
javaStreamOveruseRule,
|
|
46728
47024
|
javaStringConcatLoopRule,
|
|
46729
47025
|
javaSystemOutPrintlnRule,
|
|
47026
|
+
javaVerboseJavadocRule,
|
|
46730
47027
|
kotlinCoroutineGlobalScopeRule,
|
|
46731
47028
|
kotlinDataClassDefaultsOveruseRule,
|
|
46732
47029
|
kotlinObjectSingletonMisuseRule,
|
|
@@ -49962,6 +50259,86 @@ var init_signal_strength = __esm({
|
|
|
49962
50259
|
_v9Precision: 0.0657,
|
|
49963
50260
|
defaultOff: true
|
|
49964
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. Calibration pending v9 Java corpus re-run; placeholder values until then. v0.20.0: anti-pattern design was wrong (humans write more Javadoc on trivial methods because their training data has it). v0.26.0: redesigned as positive signal (AI over-documents trivial methods). Reference: java/verbose-javadoc v0.26.0.",
|
|
50270
|
+
aiSpecific: true,
|
|
50271
|
+
_v9Verdict: "DORMANT",
|
|
50272
|
+
_v9Lift: 1,
|
|
50273
|
+
_v9Recall: 0,
|
|
50274
|
+
_v9FpRate: 0,
|
|
50275
|
+
_v9Precision: 0,
|
|
50276
|
+
defaultOff: true
|
|
50277
|
+
},
|
|
50278
|
+
"java/optional-overuse": {
|
|
50279
|
+
recall: 0,
|
|
50280
|
+
fpRate: 0,
|
|
50281
|
+
ratio: 1,
|
|
50282
|
+
precision: 0,
|
|
50283
|
+
lastCalibratedAt: "2026-07-03T00:00:00Z",
|
|
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). Calibration pending v9 Java corpus re-run; placeholder values until then. v0.26.0: redesigned as positive signal (AI chains Optional.ofNullable().orElseThrow() where null checks would be cleaner). Reference: java/optional-overuse v0.26.0.",
|
|
50286
|
+
aiSpecific: true,
|
|
50287
|
+
_v9Verdict: "DORMANT",
|
|
50288
|
+
_v9Lift: 1,
|
|
50289
|
+
_v9Recall: 0,
|
|
50290
|
+
_v9FpRate: 0,
|
|
50291
|
+
_v9Precision: 0,
|
|
50292
|
+
defaultOff: true
|
|
50293
|
+
},
|
|
50294
|
+
"java/immutable-collection-preference": {
|
|
50295
|
+
recall: 0,
|
|
50296
|
+
fpRate: 0,
|
|
50297
|
+
ratio: 1,
|
|
50298
|
+
precision: 0,
|
|
50299
|
+
lastCalibratedAt: "2026-07-03T00:00:00Z",
|
|
50300
|
+
verdict: "DORMANT",
|
|
50301
|
+
_calibrationNote: "v0.26.0: new positive AI-signal rule. Triggers when a Java file has 5+ List.of/Map.of/Set.of calls AND < 1 new ArrayList/HashMap/HashSet/LinkedList/TreeMap calls. Calibration pending v9 Java corpus re-run; placeholder values until then. v0.26.0: redesigned as positive signal (AI defaults to immutable factory methods). Reference: java/immutable-collection-preference v0.26.0.",
|
|
50302
|
+
aiSpecific: true,
|
|
50303
|
+
_v9Verdict: "DORMANT",
|
|
50304
|
+
_v9Lift: 1,
|
|
50305
|
+
_v9Recall: 0,
|
|
50306
|
+
_v9FpRate: 0,
|
|
50307
|
+
_v9Precision: 0,
|
|
50308
|
+
defaultOff: true
|
|
50309
|
+
},
|
|
50310
|
+
"java/builder-overuse": {
|
|
50311
|
+
recall: 0,
|
|
50312
|
+
fpRate: 0,
|
|
50313
|
+
ratio: 1,
|
|
50314
|
+
precision: 0,
|
|
50315
|
+
lastCalibratedAt: "2026-07-03T00:00:00Z",
|
|
50316
|
+
verdict: "DORMANT",
|
|
50317
|
+
_calibrationNote: "v0.26.0: new positive AI-signal rule. Triggers when @Builder annotation (Lombok) is used on a class with <= 3 fields. Calibration pending v9 Java corpus re-run; placeholder values until then. v0.26.0: redesigned as positive signal (AI defaults to Builder pattern even for simple data classes). Reference: java/builder-overuse v0.26.0.",
|
|
50318
|
+
aiSpecific: true,
|
|
50319
|
+
_v9Verdict: "DORMANT",
|
|
50320
|
+
_v9Lift: 1,
|
|
50321
|
+
_v9Recall: 0,
|
|
50322
|
+
_v9FpRate: 0,
|
|
50323
|
+
_v9Precision: 0,
|
|
50324
|
+
defaultOff: true
|
|
50325
|
+
},
|
|
50326
|
+
"java/stream-overuse": {
|
|
50327
|
+
recall: 0,
|
|
50328
|
+
fpRate: 0,
|
|
50329
|
+
ratio: 1,
|
|
50330
|
+
precision: 0,
|
|
50331
|
+
lastCalibratedAt: "2026-07-03T00:00:00Z",
|
|
50332
|
+
verdict: "DORMANT",
|
|
50333
|
+
_calibrationNote: "v0.26.0: new positive AI-signal rule. Triggers when a single line has 3+ Stream API operations (.map, .filter, .flatMap, .collect, .reduce, .sorted, .distinct, .limit, .skip, .anyMatch, .allMatch, .noneMatch, .findFirst, .findAny). Calibration pending v9 Java corpus re-run; placeholder values until then. v0.26.0: redesigned as positive signal (AI chains Stream API for everything). Reference: java/stream-overuse v0.26.0.",
|
|
50334
|
+
aiSpecific: true,
|
|
50335
|
+
_v9Verdict: "DORMANT",
|
|
50336
|
+
_v9Lift: 1,
|
|
50337
|
+
_v9Recall: 0,
|
|
50338
|
+
_v9FpRate: 0,
|
|
50339
|
+
_v9Precision: 0,
|
|
50340
|
+
defaultOff: true
|
|
50341
|
+
},
|
|
49965
50342
|
"java/raw-type-overuse": {
|
|
49966
50343
|
recall: 0.1093,
|
|
49967
50344
|
fpRate: 0.2041,
|
|
@@ -59500,6 +59877,11 @@ var RULE_HINTS = {
|
|
|
59500
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.",
|
|
59501
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.",
|
|
59502
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.)",
|
|
59503
59885
|
// v0.24.0 — Kotlin rules (DORMANT until v9 Kotlin corpus calibration)
|
|
59504
59886
|
"kotlin/data-class-defaults-overuse": "Audit which fields are genuinely optional. Real Kotlin uses defaults sparingly (1-2 callbacks, the rest required). v0.24.0 \u2014 DORMANT until v9 calibration.",
|
|
59505
59887
|
"kotlin/coroutine-global-scope": "Replace with `viewModelScope.launch { ... }`, `lifecycleScope.launch { ... }`, or `coroutineScope { ... }`. GlobalScope bypasses cancellation. (v0.24.0 \u2014 DORMANT.)",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "slopbrick",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"description": "Discovered, modeled, and governed repository structure. SlopBrick scans source code, classifies it against 95+ rules in 15 categories, computes 4 scores (aiSlopScore: lower=cleaner, engineeringHygiene, security, repositoryHealth composite), and persists the structure for AI agents and CI.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|