1 ///////////////////////////////////////////////////////////////////////////////////////////////
2 // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3 // Copyright (C) 2001-2026 the original author or authors.
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 ///////////////////////////////////////////////////////////////////////////////////////////////
19
20 package com.puppycrawl.tools.checkstyle.site;
21
22 import javax.annotation.Nullable;
23
24 /**
25 * Represents a single entry in the client-side search index.
26 *
27 * @param title display name
28 * @param url relative URL
29 * @param category category label
30 * @param type document type
31 * @param description short description
32 * @param keywords comma-separated keywords
33 * @param since the version this module/property was introduced (can be empty)
34 * @param weight ranking weight for search results
35 */
36 public record SearchIndexEntry(String title, String url, String category,
37 String type, String description, String keywords,
38 String since, int weight) {
39
40 /** String literal for comma. */
41 private static final String COMMA = ",";
42
43 /** Maximum ASCII value for the lookup table. */
44 private static final int ASCII_MAX = 128;
45
46 /** Lookup table for JSON escape sequences for characters {@literal <} 128 (ASCII range). */
47 private static final String[] JSON_ESCAPES;
48
49 static {
50 JSON_ESCAPES = new String[ASCII_MAX];
51 JSON_ESCAPES['\\'] = "\\\\";
52 JSON_ESCAPES['\"'] = "\\\"";
53 JSON_ESCAPES['\n'] = "\\n";
54 JSON_ESCAPES['\r'] = "\\r";
55 JSON_ESCAPES['\t'] = "\\t";
56 }
57
58 /**
59 * Serialises this entry to a compact JSON object string.
60 *
61 * @return JSON object string
62 */
63 public String toJson() {
64 return "{"
65 + "\"title\":" + jsonString(title) + COMMA
66 + "\"url\":" + jsonString(url) + COMMA
67 + "\"category\":" + jsonString(category) + COMMA
68 + "\"type\":" + jsonString(type) + COMMA
69 + "\"description\":" + jsonString(description) + COMMA
70 + "\"since\":" + jsonString(since) + COMMA
71 + "\"weight\":" + weight + COMMA
72 + "\"keywords\":" + jsonString(keywords)
73 + "}";
74 }
75
76 /**
77 * Wraps a string value in JSON double quotes and escapes special characters.
78 *
79 * @param value the raw string to encode
80 * @return JSON-safe quoted string, or {@code ""} if value is null
81 */
82 private static String jsonString(@Nullable String value) {
83 String result = "\"\"";
84 if (value != null) {
85 final int length = value.length();
86 final StringBuilder sb = new StringBuilder(length + 2);
87 sb.append('\"');
88 for (int index = 0; index < length; index++) {
89 final char ch = value.charAt(index);
90 final String escape;
91 if (ch < ASCII_MAX) {
92 escape = JSON_ESCAPES[ch];
93 }
94 else {
95 escape = null;
96 }
97 if (escape == null) {
98 sb.append(ch);
99 }
100 else {
101 sb.append(escape);
102 }
103 }
104 sb.append('\"');
105 result = sb.toString();
106 }
107 return result;
108 }
109
110 }