1
+ /*
2
+ * Copyright 2025 Vonage
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in
12
+ * all copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ * THE SOFTWARE.
21
+ */
22
+
1
23
import java .io .File ;
2
24
import java .io .IOException ;
3
25
import java .nio .file .Files ;
4
26
import java .nio .file .Path ;
5
27
import java .nio .file .Paths ;
6
28
import java .nio .file .StandardOpenOption ;
7
- import java .util .Objects ;
29
+ import java .util .*;
30
+
31
+ public final class AggregateSnippets {
8
32
9
- public class AggregateSnippets {
10
- public static void main (String [] args ) throws Throwable {
33
+ public static void main (String ... args ) throws Throwable {
11
34
final var repoRoot = Paths .get ("" ).toAbsolutePath ();
12
35
final var snippetsSrcRoot = repoRoot .resolve ("src/main/java/com/vonage/quickstart" );
13
- final var classFileName = "AggregateSnippets.java" ;
14
- var sb = new StringBuilder (1 << 17 )
36
+ final var aggregator = new AggregateSnippets (snippetsSrcRoot );
37
+ aggregator .computeContents ();
38
+ aggregator .saveContentsToFile (repoRoot .resolve ("SNIPPETS.md" ));
39
+ if (args .length > 0 ) {
40
+ aggregator .saveLineNumbersToCsv (Paths .get (args [0 ]));
41
+ }
42
+ }
43
+
44
+
45
+ public record CodeSnippetFileInfo (
46
+ Path file ,
47
+ int mainStartIndex , int mainEndIndex ,
48
+ int clientStartIndex , int clientEndIndex
49
+ ) { }
50
+
51
+ private StringBuilder sb ;
52
+ private final Path snippetsSrcRoot ;
53
+ private Collection <CodeSnippetFileInfo > snippetFiles ;
54
+
55
+ public AggregateSnippets (Path snippetsSrcRoot ) {
56
+ this .snippetsSrcRoot = Objects .requireNonNull (snippetsSrcRoot );
57
+ }
58
+
59
+ private void checkComputed () {
60
+ if (sb == null || sb .isEmpty ()) {
61
+ throw new IllegalStateException ("Contents not computed yet." );
62
+ }
63
+ }
64
+
65
+ public Collection <CodeSnippetFileInfo > getLineNumbers () {
66
+ checkComputed ();
67
+ return snippetFiles ;
68
+ }
69
+
70
+ public String getContents () {
71
+ checkComputed ();
72
+ return sb .toString ();
73
+ }
74
+
75
+ public void saveContentsToFile (Path destPath ) throws IOException {
76
+ Files .writeString (destPath , getContents (), StandardOpenOption .CREATE );
77
+ }
78
+
79
+ public void saveLineNumbersToCsv (Path destPath ) throws IOException {
80
+ checkComputed ();
81
+ try (var writer = Files .newBufferedWriter (destPath , StandardOpenOption .CREATE )) {
82
+ writer .write ("File,MainStart,MainEnd,ClientStart,ClientEnd\n " );
83
+ for (var metadata : snippetFiles ) {
84
+ writer .write (
85
+ metadata .file .getFileName () + "," +
86
+ metadata .mainStartIndex + "," +
87
+ metadata .mainEndIndex + "," +
88
+ metadata .clientStartIndex + "," +
89
+ metadata .clientEndIndex + "\n "
90
+ );
91
+ }
92
+ }
93
+ }
94
+
95
+ public void computeContents () throws IOException {
96
+ snippetFiles = new ArrayList <>(256 );
97
+ final String classFileName = getClass ().getSimpleName () + ".java" ;
98
+ sb = new StringBuilder (1 << 17 )
15
99
.append ("# Vonage Java SDK Code Snippets\n " )
16
100
.append ("Here are all the snippets in this repository.\n " )
17
101
.append ("This file was generated by running [" ).append (classFileName )
18
102
.append ("](src/main/java/" ).append (classFileName )
19
103
.append (") from the root of the repository." )
20
104
.append ("\n \n ## Contents" );
21
105
22
- var allDirs = Files .list (snippetsSrcRoot )
23
- .filter (Files ::isDirectory )
106
+ var allDirs = getAllDirsSorted ();
107
+
108
+ for (var file : allDirs ) {
109
+ var title = toHeadingTitle (file .getName ());
110
+ sb .append ("\n - [**" ).append (title ).append ("**](#" )
111
+ .append (title .toLowerCase ().replace (' ' , '-' )).append (")" );
112
+ }
113
+ sb .append ("\n \n " );
114
+
115
+ for (var file : allDirs ) {
116
+ appendSnippetContent (file , 2 );
117
+ }
118
+ }
119
+
120
+ private List <File > getAllDirsSorted () {
121
+ try (var pathStream = Files .list (snippetsSrcRoot )) {
122
+ return pathStream .filter (Files ::isDirectory )
24
123
.map (Path ::toFile )
25
124
.sorted ((f1 , f2 ) -> {
26
125
if (isInitialize (f1 )) return -1 ;
27
126
if (isInitialize (f2 )) return 1 ;
28
127
return f1 .getName ().compareToIgnoreCase (f2 .getName ());
29
128
})
30
129
.toList ();
130
+ }
131
+ catch (IOException ex ) {
132
+ System .err .println ("Could not read " +snippetsSrcRoot +": " + ex .getMessage ());
133
+ return List .of ();
134
+ }
135
+ }
31
136
32
- for (var file : allDirs ) {
33
- var title = toHeadingTitle (file .getName ());
34
- sb .append ("\n - [**" ).append (title ).append ("**](#" )
35
- .append (title .toLowerCase ().replace (' ' , '-' )).append (")" );
137
+ private void appendSnippetContent (File path , int level ) throws IOException {
138
+ var fileName = path .getName ();
139
+ if (path .isFile ()) {
140
+ fileName = fileName .substring (0 , fileName .lastIndexOf ('.' ));
141
+ }
142
+ if (fileName .trim ().length () < 3 ) return ;
143
+
144
+ sb .append ("#" .repeat (level )).append (' ' ).append (toHeadingTitle (fileName )).append ('\n' );
145
+ if (path .isDirectory ()) {
146
+ for (var file : Objects .requireNonNull (path .listFiles ())) {
147
+ appendSnippetContent (file , level + 1 );
148
+ }
36
149
}
37
- sb .append ("\n " );
150
+ else if (level > 2 && path .getName ().endsWith (".java" )) {
151
+ final String fileContent = Files .readString (path .toPath ()),
152
+ clientInitEndStr = ".build();\n \n " ,
153
+ clientInitStartStr = "VonageClient client" ;
38
154
39
- for (var file : allDirs ) {
40
- appendSnippetContent (sb , file , 2 );
155
+ final int clientInitStartIndex = fileContent .indexOf (clientInitStartStr ) - 8 ,
156
+ clientInitEndIndex = fileContent .indexOf (clientInitEndStr ) + 11 ,
157
+ endIndex = fileContent .lastIndexOf ('}' , fileContent .lastIndexOf ('}' ) - 1 ) - 1 ,
158
+ startIndex = Math .min (endIndex , clientInitStartIndex > 0 ?
159
+ (isInitialize (path .getParentFile ()) ? clientInitStartIndex : clientInitEndIndex ) :
160
+ fileContent .indexOf ('{' , fileContent .indexOf ('{' ) + 1 ) + 2
161
+ );
162
+
163
+ final String nugget = fileContent .substring (startIndex , endIndex )
164
+ .stripTrailing ().stripIndent ().replace ("\t " , " " );
165
+
166
+ sb .append ("\n ```java\n " ).append (nugget ).append ("\n ```\n " );
167
+
168
+ boolean standalone = clientInitEndIndex < 12 ;
169
+ snippetFiles .add (new CodeSnippetFileInfo (path .toPath (),
170
+ lineNumberFromIndex (fileContent , startIndex ) + 1 ,
171
+ lineNumberFromIndex (fileContent , endIndex ),
172
+ standalone ? -1 : lineNumberFromIndex (fileContent , clientInitStartIndex ) + 1 ,
173
+ standalone ? -1 : lineNumberFromIndex (fileContent , clientInitEndIndex )
174
+ ));
41
175
}
176
+ }
42
177
43
- var destPath = repoRoot . resolve ( "SNIPPETS.md" );
44
- Files . deleteIfExists ( destPath ) ;
45
- Files . writeString ( destPath , sb . toString (), StandardOpenOption . CREATE_NEW ) ;
178
+ private static int lineNumberFromIndex ( String content , int index ) {
179
+ if ( index < 0 ) return - 1 ;
180
+ return content . substring ( 0 , index ). split ( " \n " ). length ;
46
181
}
47
182
48
- static boolean isInitialize (File file ) {
183
+ private static boolean isInitialize (File file ) {
49
184
return file .getName ().equals ("initialize" );
50
185
}
51
186
52
- static String toHeadingTitle (String title ) {
187
+ private static String toHeadingTitle (String title ) {
53
188
var acronyms = new String []{
54
189
"jwt" , "id" , "uuid" , "url" , "sim" ,
55
190
"sms" , "rcs" , "mms" , "psd2" , "dlr" , "cnam" ,
@@ -73,34 +208,4 @@ static String toHeadingTitle(String title) {
73
208
}
74
209
return result ;
75
210
}
76
-
77
- static void appendSnippetContent (StringBuilder contentBuilder , File path , int level ) throws IOException {
78
- var fileName = path .getName ();
79
- if (path .isFile ()) {
80
- fileName = fileName .substring (0 , fileName .lastIndexOf ('.' ));
81
- }
82
- if (fileName .trim ().length () < 3 ) return ;
83
-
84
- contentBuilder .append ("#" .repeat (level )).append (' ' ).append (toHeadingTitle (fileName )).append ('\n' );
85
- if (path .isDirectory ()) {
86
- for (var file : Objects .requireNonNull (path .listFiles ())) {
87
- appendSnippetContent (contentBuilder , file , level + 1 );
88
- }
89
- }
90
- else if (level > 2 && path .getName ().endsWith (".java" )) {
91
- final var fileContent = Files .readString (path .toPath ());
92
- final var clientInitEndStr = ".build();\n \n " ;
93
- final var clientInitStartStr = "VonageClient client" ;
94
- final int endIndex = fileContent .lastIndexOf ('}' , fileContent .lastIndexOf ('}' ) - 1 ) - 1 ;
95
- final int startIndex = Math .min (endIndex , fileContent .contains (clientInitStartStr ) ?
96
- (isInitialize (path .getParentFile ()) ? fileContent .indexOf (clientInitStartStr ) - 8 :
97
- fileContent .indexOf (clientInitEndStr ) + clientInitEndStr .length ()) :
98
- fileContent .indexOf ('{' , fileContent .indexOf ('{' ) + 1 ) + 2
99
- );
100
-
101
- final var nugget = fileContent .substring (startIndex , endIndex )
102
- .stripTrailing ().stripIndent ().replace ("\t " , " " );
103
- contentBuilder .append ("\n ```java\n " ).append (nugget ).append ("\n ```\n " );
104
- }
105
- }
106
211
}
0 commit comments