77import java .io .InputStream ;
88import java .io .OutputStream ;
99import java .io .PrintStream ;
10+ import java .io .PrintWriter ;
11+ import java .io .StringWriter ;
1012import java .nio .file .Files ;
1113import java .util .Map ;
1214
1820import org .apache .commons .cli .Options ;
1921
2022import com .dashjoin .jsonata .Functions ;
23+ import com .dashjoin .jsonata .JException ;
2124import com .dashjoin .jsonata .Jsonata ;
2225import com .dashjoin .jsonata .json .Json ;
2326
2730public class Main {
2831
2932 Options options ;
33+ String expr ;
34+ String exprFile ;
3035
3136 Main () {
3237 initCli ();
@@ -88,9 +93,9 @@ void run(String[] args) throws Throwable {
8893 printHelp ();
8994 return ;
9095 }
91- String expr = cmd .getOptionValue ("e" );
92- if (expr != null )
93- expr = readFile (expr );
96+ exprFile = cmd .getOptionValue ("e" );
97+ if (exprFile != null )
98+ expr = readFile (exprFile );
9499 else
95100 expr = cmd .getArgList ().get (0 );
96101
@@ -191,6 +196,65 @@ void printVersion() {
191196 System .out .println (Version .getVersion ());
192197 }
193198
199+ static class ErrorDetails {
200+ /**
201+ * Hint string showing the error location
202+ */
203+ String hint ;
204+ /**
205+ * Row of the error
206+ */
207+ int row ;
208+ /**
209+ * Column of the error
210+ */
211+ int column ;
212+ }
213+
214+ /**
215+ * Returns the error details: row, column,
216+ * and a hint that points to the error.
217+ * Supports multi-line expressions
218+ *
219+ * @param location (character index)
220+ * @return error details
221+ */
222+ ErrorDetails getErrorDetails (int location ) {
223+ int lineStart = -1 ;
224+ int line = 0 ;
225+
226+ StringWriter sw = new StringWriter ();
227+ PrintWriter err = new PrintWriter (sw );
228+
229+ for (int i =0 ; i <expr .length (); i ++) {
230+ if (i >=location )
231+ break ;
232+ if ("\n \r " .contains ("" +expr .charAt (i ))) {
233+ lineStart = i ;
234+ line ++;
235+ }
236+ }
237+ int col = location - lineStart - 1 ;
238+ for (int i =lineStart +1 ; i <expr .length (); i ++) {
239+ if ("\n \r " .contains ("" +expr .charAt (i )))
240+ break ;
241+ err .print (expr .charAt (i ));
242+ }
243+ err .println ();
244+ for (int i =0 ; i <col -1 ; i ++) {
245+ err .print (" " );
246+ }
247+ err .println ("^" );
248+
249+ err .close ();
250+
251+ ErrorDetails e = new ErrorDetails ();
252+ e .hint = sw .toString ();
253+ e .row = line ;
254+ e .column = col ;
255+ return e ;
256+ }
257+
194258 /**
195259 * Main program
196260 *
@@ -199,6 +263,17 @@ void printVersion() {
199263 */
200264 public static void main (String [] args ) throws Throwable {
201265 Main main = new Main ();
202- main .run (args );
266+ try {
267+ main .run (args );
268+ } catch (JException jex ) {
269+ ErrorDetails e = main .getErrorDetails (jex .getLocation ());
270+ // Print error location so that VSCode directly jumps to the error
271+ // (if it's in a file "-e exprfile")
272+ System .err .println ("JSONata error at " +
273+ (main .exprFile ==null ? "expression" :main .exprFile )+":" +(e .row +1 )+"." +(e .column ));
274+ System .err .println (jex .getMessage ());
275+ System .err .println ();
276+ System .err .println (e .hint );
277+ }
203278 }
204279}
0 commit comments