diff --git a/src/main/java/com/codechecker/cache/report/ReportBuilder.java b/src/main/java/com/codechecker/cache/report/ReportBuilder.java index af6a0a5..7317cb2 100644 --- a/src/main/java/com/codechecker/cache/report/ReportBuilder.java +++ b/src/main/java/com/codechecker/cache/report/ReportBuilder.java @@ -130,9 +130,9 @@ public class ReportBuilder { Set oldHighlight = SkeletonAnnotator.pathsForOldSkeleton(kc.getFieldDetails()); Set newHighlight = SkeletonAnnotator.pathsForNewSkeleton(kc.getFieldDetails()); String oldRendered = oldJson.isEmpty() - ? "" : "“" + SkeletonAnnotator.annotateForWecom(oldJson, oldHighlight) + "”"; + ? "" : "“" + SkeletonAnnotator.annotateOldForWecom(oldJson, oldHighlight) + "”"; String newRendered = newJson.isEmpty() - ? "" : "“" + SkeletonAnnotator.annotateForWecom(newJson, newHighlight) + "”"; + ? "" : "“" + SkeletonAnnotator.annotateNewForWecom(newJson, newHighlight) + "”"; if (oldJson.isEmpty() && !newJson.isEmpty()) { sb.append(" > **value 新增为:** ").append(newRendered).append("\n\n"); } else if (!oldJson.isEmpty() && newJson.isEmpty()) { diff --git a/src/main/java/com/codechecker/cache/report/SkeletonAnnotator.java b/src/main/java/com/codechecker/cache/report/SkeletonAnnotator.java index a448770..59aff21 100644 --- a/src/main/java/com/codechecker/cache/report/SkeletonAnnotator.java +++ b/src/main/java/com/codechecker/cache/report/SkeletonAnnotator.java @@ -10,16 +10,20 @@ import java.util.List; import java.util.Set; /** - * 在骨架 JSON 中为改动字段加企微 warning 标注(仅改动片段染色,其余明文)。 + * 在骨架 JSON 中为改动字段加企微颜色标注(仅改动片段染色,其余明文)。 * */ final class SkeletonAnnotator { - private static final String FONT_OPEN = ""; + /** 企微橙:删除 / 旧侧变更 */ + static final String COLOR_REMOVE = "warning"; + /** 企微绿:新增 / 新侧变更 */ + static final String COLOR_ADD = "info"; + private static final String FONT_CLOSE = ""; private SkeletonAnnotator() { @@ -66,14 +70,32 @@ final class SkeletonAnnotator { } /** - * 仅标注改动字段:其余正文保持普通文本(避免整段包反引号导致企微整段变红)。 - * 改动片段格式:{@code "field":value} + * 标注旧骨架改动字段(删除 → 橙色)。 + */ + static String annotateOldForWecom(String json, Set highlightPaths) { + return annotateForWecom(json, highlightPaths, COLOR_REMOVE); + } + + /** + * 标注新骨架改动字段(新增 → 绿色)。 + */ + static String annotateNewForWecom(String json, Set highlightPaths) { + return annotateForWecom(json, highlightPaths, COLOR_ADD); + } + + /** + * 仅标注改动字段:其余正文保持普通文本。 + * 改动片段格式:{@code "field":value} */ static String annotateForWecom(String json, Set highlightPaths) { + return annotateForWecom(json, highlightPaths, COLOR_REMOVE); + } + + static String annotateForWecom(String json, Set highlightPaths, String color) { if (json == null || json.isEmpty()) { return ""; } - return annotate(json, highlightPaths); + return annotate(json, highlightPaths, color); } /** @deprecated 使用 {@link #annotateForWecom},勿再整段包代码块 */ @@ -82,18 +104,27 @@ final class SkeletonAnnotator { } static String annotate(String json, Set highlightPaths) { + return annotate(json, highlightPaths, COLOR_REMOVE); + } + + static String annotate(String json, Set highlightPaths, String color) { if (json == null || json.isEmpty() || highlightPaths == null || highlightPaths.isEmpty()) { return json == null ? "" : json; } + String fontOpen = fontOpen(color); String result = json; List sorted = new ArrayList<>(highlightPaths); sorted.sort(Comparator.comparingInt(String::length).reversed()); for (String path : sorted) { - result = wrapOnePath(result, path); + result = wrapOnePath(result, path, fontOpen); } return result; } + private static String fontOpen(String color) { + String c = color == null || color.isEmpty() ? COLOR_REMOVE : color; + return ""; + } private static void addIfPresent(Set paths, String path) { if (path != null && !path.trim().isEmpty()) { @@ -101,11 +132,10 @@ final class SkeletonAnnotator { } } - private static String wrapOnePath(String json, String path) { + private static String wrapOnePath(String json, String path, String fontOpen) { if (path == null || path.isEmpty()) { return json; } - // 已标注过则跳过(避免重复) String key = lastSegment(path); if (key.isEmpty()) { return json; @@ -114,8 +144,7 @@ final class SkeletonAnnotator { if (propStart < 0) { return json; } - // 已在 font 内则跳过 - int fontBefore = json.lastIndexOf(FONT_OPEN, propStart); + int fontBefore = json.lastIndexOf(" fontCloseBefore) { return json; @@ -127,11 +156,11 @@ final class SkeletonAnnotator { return json; } String frag = json.substring(propStart, valueEnd); - if (frag.contains(FONT_OPEN)) { + if (frag.contains("= arrEnd) { @@ -193,7 +221,6 @@ final class SkeletonAnnotator { if (idx < 0 || idx >= to) { return -1; } - // 粗略校验:前面应是 { 或 , int p = idx - 1; while (p >= from && Character.isWhitespace(json.charAt(p))) { p--; diff --git a/src/test/java/com/codechecker/cache/report/ReportBuilderTest.java b/src/test/java/com/codechecker/cache/report/ReportBuilderTest.java index 882ccf2..49daf99 100644 --- a/src/test/java/com/codechecker/cache/report/ReportBuilderTest.java +++ b/src/test/java/com/codechecker/cache/report/ReportBuilderTest.java @@ -71,23 +71,25 @@ class ReportBuilderTest { String oldPart = md.substring(oldSection, newSection); String newPart = md.substring(newSection); - // 旧骨架:无 warning,且不能整段被反引号包裹 + // 旧骨架:无染色,且不能整段被反引号包裹 assertFalse(oldPart.contains("")); + assertFalse(oldPart.contains("")); assertFalse(oldPart.contains("`" + oldJson + "`")); assertTrue(oldPart.contains(oldJson)); - // 新骨架:仅新增字段带 warning,其余明文 - assertTrue(newPart.contains("\"message\":\"\"")); - assertTrue(newPart.contains("\"lastError\":\"\"")); + // 新骨架:新增字段绿色 info,其余明文 + assertTrue(newPart.contains("\"message\":\"\"")); + assertTrue(newPart.contains("\"lastError\":\"\"")); assertTrue(newPart.contains("\"taskId\":\"\"")); - assertFalse(newPart.contains("\"taskId\":\"\"")); + assertFalse(newPart.contains("\"taskId\":\"\"")); + assertFalse(newPart.contains("")); // 禁止整段代码块 assertFalse(newPart.contains("`" + newJson)); assertFalse(md.contains("### P0")); } @Test - void removedFieldsHighlightedOnlyInOldSkeleton() { + void removedFieldsHighlightedOrangeInOldSkeleton() { SchemaChange removed = new SchemaChange(ChangeType.FIELD_REMOVED); removed.setFieldPath("lastError"); removed.setMessage("删除字段 lastError"); @@ -100,10 +102,11 @@ class ReportBuilderTest { assertEquals(Collections.singleton("lastError"), oldPaths); assertTrue(newPaths.isEmpty()); - String oldMd = SkeletonAnnotator.annotateForWecom(oldJson, oldPaths); - String newMd = SkeletonAnnotator.annotateForWecom(newJson, newPaths); + String oldMd = SkeletonAnnotator.annotateOldForWecom(oldJson, oldPaths); + String newMd = SkeletonAnnotator.annotateNewForWecom(newJson, newPaths); assertTrue(oldMd.contains("\"lastError\":\"\"")); assertFalse(oldMd.contains("\"taskId\":\"\"")); + assertFalse(oldMd.contains("")); assertEquals(newJson, newMd); assertFalse(newMd.startsWith("`")); } @@ -134,6 +137,7 @@ class ReportBuilderTest { assertTrue(console.contains("======== 字段明细 ========")); assertTrue(console.contains("**删除字段**: x")); assertTrue(console.contains("\"x\":\"\"")); + assertFalse(console.contains("\"x\":\"\"")); assertTrue(console.contains("> **位置**: `")); assertTrue(console.contains("> **类型**: `")); assertTrue(console.contains("> **value值由:**")); @@ -169,9 +173,10 @@ class ReportBuilderTest { String json = "{\"vo\":{\"dbName\":\"\",\"id\":\"\"},\"expiresAtMs\":0}"; Set paths = new LinkedHashSet<>(); paths.add("vo.dbName"); - String out = SkeletonAnnotator.annotate(json, paths); - assertTrue(out.contains("\"dbName\":\"\"")); - assertFalse(out.contains("\"id\":\"\"")); + String out = SkeletonAnnotator.annotate(json, paths, SkeletonAnnotator.COLOR_ADD); + assertTrue(out.contains("\"dbName\":\"\"")); + assertFalse(out.contains("\"id\":\"\"")); + assertFalse(out.contains("\"dbName\":\"\"")); } @Test