diff --git a/json/gen/com/intellij/json/_JsonLexer.java b/json/gen/com/intellij/json/_JsonLexer.java
index 32bbee8bf0a5..a46920fcdf54 100644
--- a/json/gen/com/intellij/json/_JsonLexer.java
+++ b/json/gen/com/intellij/json/_JsonLexer.java
@@ -1,4 +1,4 @@
-/* The following code was generated by JFlex 1.7.0-SNAPSHOT tweaked for IntelliJ platform */
+/* The following code was generated by JFlex 1.7.0 tweaked for IntelliJ platform */
package com.intellij.json;
@@ -12,7 +12,7 @@ import static com.intellij.json.JsonElementTypes.*;
/**
* This class is a scanner generated by
- * JFlex 1.7.0-SNAPSHOT
+ * JFlex 1.7.0
* from the specification file _JsonLexer.flex
*/
public class _JsonLexer implements FlexLexer {
@@ -600,71 +600,88 @@ public class _JsonLexer implements FlexLexer {
switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) {
case 1:
{ return BAD_CHARACTER;
- }
+ }
+ // fall through
case 18: break;
case 2:
{ return WHITE_SPACE;
- }
+ }
+ // fall through
case 19: break;
case 3:
{ return IDENTIFIER;
- }
+ }
+ // fall through
case 20: break;
case 4:
{ return DOUBLE_QUOTED_STRING;
- }
+ }
+ // fall through
case 21: break;
case 5:
{ return SINGLE_QUOTED_STRING;
- }
+ }
+ // fall through
case 22: break;
case 6:
{ return NUMBER;
- }
+ }
+ // fall through
case 23: break;
case 7:
{ return L_CURLY;
- }
+ }
+ // fall through
case 24: break;
case 8:
{ return R_CURLY;
- }
+ }
+ // fall through
case 25: break;
case 9:
{ return L_BRACKET;
- }
+ }
+ // fall through
case 26: break;
case 10:
{ return R_BRACKET;
- }
+ }
+ // fall through
case 27: break;
case 11:
{ return COMMA;
- }
+ }
+ // fall through
case 28: break;
case 12:
{ return COLON;
- }
+ }
+ // fall through
case 29: break;
case 13:
{ return LINE_COMMENT;
- }
+ }
+ // fall through
case 30: break;
case 14:
{ return BLOCK_COMMENT;
- }
+ }
+ // fall through
case 31: break;
case 15:
{ return TRUE;
- }
+ }
+ // fall through
case 32: break;
case 16:
{ return NULL;
- }
+ }
+ // fall through
case 33: break;
case 17:
{ return FALSE;
- }
+ }
+ // fall through
case 34: break;
default:
zzScanError(ZZ_NO_MATCH);
diff --git a/json/gen/com/intellij/json/json5/_Json5Lexer.java b/json/gen/com/intellij/json/json5/_Json5Lexer.java
new file mode 100644
index 000000000000..2beff9397079
--- /dev/null
+++ b/json/gen/com/intellij/json/json5/_Json5Lexer.java
@@ -0,0 +1,723 @@
+/* The following code was generated by JFlex 1.7.0 tweaked for IntelliJ platform */
+
+package com.intellij.json.json5;
+
+import com.intellij.lexer.FlexLexer;
+import com.intellij.psi.tree.IElementType;
+
+import static com.intellij.psi.TokenType.BAD_CHARACTER;
+import static com.intellij.psi.TokenType.WHITE_SPACE;
+import static com.intellij.json.JsonElementTypes.*;
+
+
+/**
+ * This class is a scanner generated by
+ * JFlex 1.7.0
+ * from the specification file _Json5Lexer.flex
+ */
+public class _Json5Lexer implements FlexLexer {
+
+ /** This character denotes the end of file */
+ public static final int YYEOF = -1;
+
+ /** initial size of the lookahead buffer */
+ private static final int ZZ_BUFFERSIZE = 16384;
+
+ /** lexical states */
+ public static final int YYINITIAL = 0;
+
+ /**
+ * ZZ_LEXSTATE[l] is the state in the DFA for the lexical state l
+ * ZZ_LEXSTATE[l+1] is the state in the DFA for the lexical state l
+ * at the beginning of a line
+ * l is of the form l = 2*k, k a non negative integer
+ */
+ private static final int ZZ_LEXSTATE[] = {
+ 0, 0
+ };
+
+ /**
+ * Translates characters to character classes
+ * Chosen bits are [12, 6, 3]
+ * Total runtime size is 13376 bytes
+ */
+ public static int ZZ_CMAP(int ch) {
+ return ZZ_CMAP_A[(ZZ_CMAP_Y[(ZZ_CMAP_Z[ch>>9]<<6)|((ch>>3)&0x3f)]<<3)|(ch&0x7)];
+ }
+
+ /* The ZZ_CMAP_Z table has 2176 entries */
+ static final char ZZ_CMAP_Z[] = zzUnpackCMap(
+ "\1\0\1\1\1\2\1\3\1\4\1\5\1\6\1\7\1\10\1\11\1\12\1\13\1\14\1\15\1\16\1\17\1"+
+ "\20\5\21\1\22\1\23\1\24\1\21\14\25\1\26\50\25\1\27\2\25\1\30\1\31\1\32\1\33"+
+ "\25\25\1\34\20\21\1\35\1\36\1\37\1\40\1\41\1\42\1\43\1\21\1\44\1\45\1\46\1"+
+ "\21\1\47\2\21\1\50\4\21\1\25\1\51\1\52\5\21\2\25\1\53\31\21\1\25\1\54\1\21"+
+ "\1\55\40\21\1\56\17\21\1\57\1\60\1\61\1\62\13\21\1\63\10\21\123\25\1\64\7"+
+ "\25\1\65\1\66\37\21\1\25\1\66\u0582\21\1\67\u017f\21");
+
+ /* The ZZ_CMAP_Y table has 3584 entries */
+ static final char ZZ_CMAP_Y[] = zzUnpackCMap(
+ "\1\0\1\1\1\0\1\2\1\3\1\4\1\5\1\6\1\7\1\10\1\0\1\11\1\12\1\13\1\14\1\15\1\16"+
+ "\3\0\1\17\1\20\1\21\1\22\2\0\1\23\3\0\1\23\71\0\1\24\1\0\1\25\1\26\1\27\1"+
+ "\30\2\26\16\0\1\31\1\32\1\33\1\34\2\0\1\35\11\0\1\36\21\0\1\35\1\37\23\0\1"+
+ "\26\1\40\3\0\1\23\1\41\1\40\4\0\1\42\1\40\4\0\1\36\1\43\1\26\3\0\2\44\1\26"+
+ "\1\27\1\45\1\0\1\44\11\0\1\24\14\0\1\46\1\36\1\0\1\47\1\0\1\50\1\26\1\42\7"+
+ "\0\1\51\14\0\1\25\1\26\6\0\1\52\1\22\5\0\1\52\2\26\3\0\1\2\10\26\1\47\1\27"+
+ "\6\26\1\53\2\0\1\23\14\0\1\54\1\0\2\40\1\55\1\50\1\56\2\0\1\47\1\57\1\60\1"+
+ "\50\1\61\1\42\1\62\1\54\1\0\1\2\1\45\1\55\1\63\1\56\2\0\1\47\1\64\1\65\1\63"+
+ "\1\66\1\41\1\67\1\70\1\0\1\52\1\26\1\55\1\36\1\35\2\0\1\47\1\71\1\60\1\36"+
+ "\1\72\1\73\1\26\1\54\1\0\1\41\1\26\1\55\1\50\1\56\2\0\1\47\1\71\1\60\1\50"+
+ "\1\66\1\70\1\62\1\54\1\0\1\41\1\26\1\74\1\75\1\76\1\77\1\100\1\75\1\0\1\24"+
+ "\1\75\1\76\1\101\1\26\1\70\1\0\1\26\1\41\1\55\1\31\1\47\2\0\1\47\1\46\1\102"+
+ "\1\31\1\76\1\103\1\25\1\54\1\0\2\26\1\74\1\31\1\47\2\0\1\47\1\46\1\60\1\31"+
+ "\1\76\1\103\1\33\1\54\1\0\1\104\1\26\1\74\1\31\1\47\4\0\1\51\1\31\1\105\1"+
+ "\42\1\26\1\54\1\0\1\26\1\37\1\74\1\0\1\23\1\37\2\0\1\35\1\106\1\23\1\107\1"+
+ "\110\1\0\2\26\1\111\1\26\1\40\6\0\1\63\1\0\1\23\1\0\1\25\4\26\1\112\1\113"+
+ "\1\53\1\40\1\114\1\74\1\0\1\72\1\110\1\52\1\0\1\60\4\26\1\73\2\26\1\25\1\0"+
+ "\1\25\1\115\1\116\1\0\1\40\3\0\1\27\1\40\1\0\1\31\2\0\1\40\3\0\1\27\1\33\7"+
+ "\26\11\0\1\25\11\0\1\52\4\0\1\36\1\21\5\0\1\117\51\0\1\76\1\23\1\76\5\0\1"+
+ "\76\4\0\1\76\1\23\1\76\1\0\1\23\7\0\1\76\10\0\1\51\4\26\2\0\2\26\12\0\1\27"+
+ "\1\26\1\40\114\0\1\50\2\0\1\120\2\0\1\44\11\0\1\75\1\73\1\26\1\0\1\31\1\27"+
+ "\1\26\2\0\1\27\1\26\2\0\1\2\1\26\1\0\1\31\1\121\1\26\12\0\1\122\1\123\1\0"+
+ "\1\25\3\26\1\123\1\0\1\25\13\0\1\26\5\0\1\44\10\0\1\52\1\26\3\0\1\27\1\0\1"+
+ "\2\1\0\1\2\1\70\4\0\1\52\1\27\1\26\5\0\1\2\3\0\1\25\1\0\1\25\4\26\3\0\1\2"+
+ "\7\0\1\23\3\0\1\50\1\0\1\25\1\0\1\25\1\42\13\26\11\0\1\2\1\0\1\25\1\26\1\124"+
+ "\1\2\1\26\16\0\1\2\1\26\7\0\1\26\1\0\1\102\5\0\1\52\12\26\1\117\3\0\1\23\1"+
+ "\26\34\0\1\23\2\26\1\53\42\0\2\52\4\0\2\52\1\0\1\125\3\0\1\52\6\0\1\31\1\110"+
+ "\1\126\1\27\1\54\1\2\1\0\1\27\1\126\1\27\1\127\1\130\3\26\1\131\1\26\1\42"+
+ "\1\73\1\26\1\132\1\133\1\27\1\37\1\41\1\42\2\26\1\0\1\27\3\0\1\44\2\26\1\0"+
+ "\1\27\1\134\1\0\1\73\1\26\1\107\1\37\1\106\1\135\1\30\1\136\1\0\1\60\1\137"+
+ "\1\140\2\26\5\0\1\73\116\26\5\0\1\23\5\0\1\23\20\0\1\27\1\124\1\2\1\26\4\0"+
+ "\1\36\1\21\7\0\1\42\1\26\1\42\2\0\1\23\1\26\10\23\4\0\5\26\1\42\72\26\1\141"+
+ "\3\26\1\40\1\0\1\135\1\27\1\40\11\0\1\23\1\142\1\40\12\0\1\117\1\137\4\0\1"+
+ "\52\1\40\12\0\1\23\2\26\3\0\1\44\6\26\170\0\1\52\11\26\71\0\1\27\6\26\21\0"+
+ "\1\27\10\26\5\0\1\52\41\0\1\27\3\0\1\2\2\26\6\0\1\53\1\36\3\0\1\42\12\0\1"+
+ "\25\3\26\1\42\1\0\1\37\14\0\1\61\1\2\1\26\1\0\1\44\11\26\6\0\2\26\1\73\6\0"+
+ "\1\2\1\26\10\0\1\27\1\26\1\0\1\25\3\0\1\45\5\0\1\52\4\0\1\2\1\26\3\0\1\27"+
+ "\10\0\1\73\1\42\1\0\1\25\4\26\6\0\1\23\1\26\1\0\1\52\1\0\1\25\2\0\1\23\1\111"+
+ "\10\0\1\44\2\26\1\123\2\0\1\143\1\26\3\144\1\26\2\23\22\26\5\0\1\145\1\0\1"+
+ "\25\64\0\1\2\1\26\2\0\1\23\1\124\5\0\1\2\40\26\55\0\1\52\15\0\1\25\4\26\1"+
+ "\23\1\26\1\124\1\137\1\0\1\47\1\23\1\110\1\146\15\0\1\25\3\26\1\124\54\0\1"+
+ "\52\2\26\10\0\1\37\6\0\5\26\1\0\1\27\2\0\2\26\1\23\1\26\1\100\2\26\1\137\3"+
+ "\26\1\41\1\31\20\0\1\50\1\132\1\26\1\0\1\25\1\40\2\0\1\63\1\40\2\0\1\44\1"+
+ "\70\12\0\1\23\3\37\1\147\1\150\2\26\1\151\1\0\1\46\2\0\1\23\2\0\1\152\1\0"+
+ "\1\52\1\0\1\52\4\26\17\0\1\44\10\26\6\0\1\27\20\26\1\21\20\26\3\0\1\27\6\0"+
+ "\1\73\5\26\3\0\1\23\2\26\3\0\1\44\6\26\3\0\1\52\4\0\1\2\1\0\1\135\5\26\23"+
+ "\0\1\52\1\0\1\25\52\26\1\52\1\47\4\0\1\36\1\153\2\0\1\52\25\26\2\0\1\52\1"+
+ "\26\3\0\1\25\10\26\7\0\1\70\10\26\1\154\1\53\1\46\1\40\2\0\1\2\1\63\4\26\3"+
+ "\0\1\27\20\26\6\0\1\52\1\26\2\0\1\52\1\26\2\0\1\44\21\26\11\0\1\73\66\26\10"+
+ "\0\1\23\3\26\1\70\1\0\2\26\7\0\1\155\2\26\3\0\1\73\1\0\1\25\6\0\1\31\1\0\10"+
+ "\26\10\0\1\27\1\26\1\0\1\25\24\26\7\0\1\26\1\0\1\25\46\26\55\0\1\23\22\26"+
+ "\14\0\1\44\63\26\5\0\1\23\72\26\7\0\1\73\130\26\10\0\1\27\1\26\5\0\1\23\1"+
+ "\26\1\42\2\0\14\26\1\25\153\26\1\137\1\102\2\0\1\51\1\2\3\26\1\32\22\26\1"+
+ "\147\67\26\12\0\1\31\10\0\1\31\1\156\1\157\1\0\1\160\1\46\7\0\1\36\1\51\2"+
+ "\31\3\0\1\161\1\110\1\37\1\47\51\0\1\52\3\0\1\47\2\0\1\117\3\0\1\117\2\0\1"+
+ "\31\3\0\1\31\2\0\1\23\3\0\1\23\3\0\1\47\3\0\1\47\2\0\1\117\1\54\6\0\1\46\3"+
+ "\0\1\112\1\40\1\117\1\162\1\107\1\163\1\112\1\125\1\112\2\117\1\67\1\0\1\35"+
+ "\1\0\1\2\1\55\1\35\1\0\1\2\50\26\32\0\1\23\5\26\106\0\1\27\1\26\33\0\1\52"+
+ "\74\26\1\41\3\26\14\0\20\26\36\0\2\26");
+
+ /* The ZZ_CMAP_A table has 928 entries */
+ static final char ZZ_CMAP_A[] = zzUnpackCMap(
+ "\11\35\1\12\1\2\1\1\1\7\1\3\6\35\4\0\1\12\1\35\1\13\1\0\1\35\2\0\1\15\2\35"+
+ "\1\11\1\16\1\42\1\17\1\22\1\6\1\20\11\21\1\43\1\0\3\35\1\0\1\35\4\5\1\23\1"+
+ "\5\2\35\1\25\4\35\1\33\1\35\1\24\2\35\1\40\1\14\1\41\2\35\1\0\1\34\3\5\1\46"+
+ "\1\27\2\35\1\30\2\35\1\47\1\35\1\26\3\35\1\44\1\50\1\31\1\45\2\35\1\24\1\32"+
+ "\1\35\1\36\1\0\1\37\7\35\1\10\2\35\1\4\1\0\4\35\4\0\1\35\2\0\1\35\7\0\1\35"+
+ "\4\0\1\35\5\0\7\35\1\0\2\35\4\0\4\35\16\0\5\35\7\0\1\35\1\0\1\35\1\0\5\35"+
+ "\1\0\2\35\2\0\4\35\10\0\1\35\1\0\3\35\1\0\1\35\1\0\4\35\1\0\13\35\1\0\1\35"+
+ "\2\0\6\35\1\0\7\35\1\0\1\35\15\0\1\35\1\0\2\35\1\0\2\35\1\0\4\35\10\0\1\35"+
+ "\4\0\4\35\1\0\4\35\1\0\13\35\2\0\4\35\2\0\11\35\6\0\10\35\2\0\2\35\1\0\3\35"+
+ "\1\0\4\35\2\0\6\35\1\0\1\35\3\0\4\35\2\0\5\35\2\0\4\35\5\0\2\35\1\0\4\35\4"+
+ "\0\2\35\1\0\2\35\1\0\2\35\1\0\2\35\2\0\1\35\1\0\3\35\2\0\3\35\3\0\4\35\1\0"+
+ "\1\35\7\0\3\35\1\0\2\35\1\0\5\35\1\0\3\35\2\0\1\35\11\0\2\35\1\0\6\35\3\0"+
+ "\3\35\1\0\4\35\3\0\2\35\1\0\1\35\1\0\2\35\3\0\2\35\3\0\1\35\6\0\3\35\3\0\3"+
+ "\35\5\0\2\35\2\0\2\35\5\0\1\35\1\0\5\35\1\0\4\35\1\0\1\35\4\0\1\35\4\0\6\35"+
+ "\1\0\1\35\3\0\2\35\5\0\2\35\1\0\1\35\2\0\2\35\1\0\1\35\2\0\1\35\3\0\3\35\1"+
+ "\0\1\35\1\0\1\35\5\0\1\35\1\0\1\35\1\0\1\35\4\0\5\35\1\0\4\35\1\4\10\35\1"+
+ "\0\2\35\4\0\4\35\3\0\1\35\3\0\3\35\5\0\5\35\1\0\1\35\1\0\1\35\1\0\1\35\1\0"+
+ "\1\35\2\0\3\35\1\0\2\35\13\4\5\35\2\1\5\35\1\4\4\0\1\35\12\0\1\4\1\0\1\35"+
+ "\3\0\3\35\1\0\5\35\2\0\1\35\1\0\4\35\1\0\1\35\5\0\5\35\4\0\1\35\1\0\1\4\4"+
+ "\0\3\35\1\0\2\35\2\0\3\35\2\0\5\35\2\0\6\35\1\0\3\35\1\0\2\35\2\0\2\35\1\0"+
+ "\2\35\1\0\2\35\2\0\3\35\3\0\2\35\3\0\2\35\2\0\3\35\4\0\3\35\1\0\2\35\1\0\2"+
+ "\35\3\0\1\35\2\0\5\35\1\0\2\35\1\0\3\35\2\0\1\35\4\0\1\35\2\0\2\35\2\0\4\35"+
+ "\1\0\4\35\1\0\1\35\1\0\5\35\1\0\4\35\2\0\1\35\1\0\1\35\5\0\1\35\1\0\1\35\1"+
+ "\0\3\35");
+
+ /**
+ * Translates DFA states to action switch labels.
+ */
+ private static final int [] ZZ_ACTION = zzUnpackAction();
+
+ private static final String ZZ_ACTION_PACKED_0 =
+ "\1\1\1\2\1\3\2\4\1\3\1\5\1\6\6\1"+
+ "\5\4\1\7\1\10\1\11\1\12\1\13\1\14\1\15"+
+ "\1\16\1\5\2\0\1\6\5\1\1\4\2\1\5\4"+
+ "\1\15\1\16\1\4\2\5\2\6\1\1\4\4\1\1"+
+ "\1\0\1\16\1\4\1\17\1\4\1\20\1\16\1\4"+
+ "\1\21\2\4";
+
+ private static int [] zzUnpackAction() {
+ int [] result = new int[68];
+ int offset = 0;
+ offset = zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result);
+ return result;
+ }
+
+ private static int zzUnpackAction(String packed, int offset, int [] result) {
+ int i = 0; /* index in packed string */
+ int j = offset; /* index in unpacked array */
+ int l = packed.length();
+ while (i < l) {
+ int count = packed.charAt(i++);
+ int value = packed.charAt(i++);
+ do result[j++] = value; while (--count > 0);
+ }
+ return j;
+ }
+
+
+ /**
+ * Translates a state to a row index in the transition table
+ */
+ private static final int [] ZZ_ROWMAP = zzUnpackRowMap();
+
+ private static final String ZZ_ROWMAP_PACKED_0 =
+ "\0\0\0\51\0\122\0\173\0\244\0\315\0\366\0\u011f"+
+ "\0\u0148\0\u0171\0\u019a\0\u01c3\0\u01ec\0\u0215\0\u023e\0\u0267"+
+ "\0\u0290\0\u02b9\0\u02e2\0\51\0\51\0\51\0\51\0\51"+
+ "\0\51\0\u030b\0\u0334\0\51\0\u035d\0\u0386\0\51\0\u03af"+
+ "\0\u03d8\0\u0401\0\u042a\0\u0453\0\u047c\0\u04a5\0\u04ce\0\u04f7"+
+ "\0\u0520\0\u0549\0\u0572\0\u059b\0\u05c4\0\u05ed\0\u0616\0\u063f"+
+ "\0\u0668\0\u0691\0\u06ba\0\u047c\0\u06e3\0\u070c\0\u0735\0\u075e"+
+ "\0\173\0\u0787\0\173\0\u07b0\0\173\0\u07d9\0\173\0\51"+
+ "\0\u0802\0\173\0\u082b\0\u0854";
+
+ private static int [] zzUnpackRowMap() {
+ int [] result = new int[68];
+ int offset = 0;
+ offset = zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result);
+ return result;
+ }
+
+ private static int zzUnpackRowMap(String packed, int offset, int [] result) {
+ int i = 0; /* index in packed string */
+ int j = offset; /* index in unpacked array */
+ int l = packed.length();
+ while (i < l) {
+ int high = packed.charAt(i++) << 16;
+ result[j++] = high | packed.charAt(i++);
+ }
+ return j;
+ }
+
+ /**
+ * The transition table of the DFA
+ */
+ private static final int [] ZZ_TRANS = zzUnpackTrans();
+
+ private static final String ZZ_TRANS_PACKED_0 =
+ "\1\2\4\3\1\4\1\5\1\3\1\6\1\4\1\3"+
+ "\1\7\1\2\1\10\1\11\1\12\1\13\1\14\1\15"+
+ "\1\16\1\4\1\17\1\20\1\21\1\4\1\22\1\4"+
+ "\1\23\2\4\1\24\1\25\1\26\1\27\1\30\1\31"+
+ "\2\4\1\16\2\4\52\0\4\3\2\0\2\3\1\0"+
+ "\1\3\43\0\2\4\1\0\2\4\5\0\17\4\6\0"+
+ "\5\4\5\0\1\4\1\32\1\0\1\4\1\33\5\0"+
+ "\17\4\6\0\5\4\1\0\4\3\2\4\1\3\1\6"+
+ "\1\4\1\3\4\0\17\4\6\0\5\4\2\7\2\0"+
+ "\7\7\1\34\1\35\34\7\2\10\2\0\10\10\1\36"+
+ "\1\37\33\10\20\0\1\40\1\41\1\42\1\43\22\0"+
+ "\1\43\7\0\2\4\1\0\2\4\5\0\1\4\1\44"+
+ "\1\14\1\15\1\16\1\4\1\17\5\4\1\23\2\4"+
+ "\6\0\2\4\1\16\2\4\5\0\2\4\1\0\2\4"+
+ "\5\0\1\4\3\15\1\16\1\45\11\4\6\0\2\4"+
+ "\1\16\2\4\5\0\2\4\1\0\2\4\5\0\1\4"+
+ "\2\14\1\15\1\16\12\4\6\0\2\4\1\16\2\4"+
+ "\5\0\2\4\1\0\2\4\5\0\1\4\2\15\1\4"+
+ "\1\16\12\4\6\0\2\4\1\16\2\4\5\0\2\4"+
+ "\1\0\2\4\4\0\1\46\3\47\14\4\6\0\5\4"+
+ "\5\0\2\4\1\0\2\4\5\0\7\4\1\50\7\4"+
+ "\6\0\5\4\5\0\2\4\1\0\2\4\5\0\17\4"+
+ "\6\0\1\4\1\51\3\4\5\0\2\4\1\0\2\4"+
+ "\5\0\15\4\1\52\1\4\6\0\5\4\5\0\2\4"+
+ "\1\0\2\4\5\0\17\4\6\0\1\53\4\4\5\0"+
+ "\2\4\1\0\2\4\5\0\15\4\1\54\1\4\6\0"+
+ "\5\4\1\55\3\0\1\55\2\32\1\0\1\4\1\32"+
+ "\5\55\17\32\6\55\5\32\5\56\2\33\1\56\1\33"+
+ "\1\57\5\56\17\33\6\56\5\33\3\7\1\60\3\7"+
+ "\1\61\2\7\1\61\36\7\3\10\1\62\3\10\1\63"+
+ "\2\10\1\63\36\10\20\0\3\42\1\43\22\0\1\43"+
+ "\22\0\2\41\1\42\1\43\22\0\1\43\22\0\2\42"+
+ "\1\0\1\43\22\0\1\43\20\0\4\46\34\0\2\4"+
+ "\1\0\2\4\5\0\1\4\3\15\1\16\12\4\6\0"+
+ "\2\4\1\16\2\4\5\0\1\64\1\4\1\0\2\4"+
+ "\5\0\1\4\2\64\1\4\1\64\3\4\1\64\4\4"+
+ "\1\64\1\4\6\0\2\4\1\64\2\4\20\0\2\46"+
+ "\34\0\2\4\1\0\2\4\5\0\1\4\2\47\14\4"+
+ "\6\0\5\4\5\0\2\4\1\0\2\4\5\0\10\4"+
+ "\1\65\6\4\6\0\5\4\5\0\2\4\1\0\2\4"+
+ "\5\0\17\4\6\0\3\4\1\66\1\4\5\0\2\4"+
+ "\1\0\2\4\5\0\17\4\6\0\3\4\1\67\1\4"+
+ "\5\0\2\4\1\0\2\4\5\0\17\4\6\0\1\4"+
+ "\1\70\3\4\5\0\2\4\1\0\2\4\5\0\14\4"+
+ "\1\71\2\4\6\0\5\4\1\55\3\0\3\55\2\0"+
+ "\40\55\11\56\1\72\44\56\1\33\1\73\1\56\1\33"+
+ "\1\57\5\56\17\33\6\56\5\33\3\7\1\0\7\7"+
+ "\1\34\1\35\37\7\1\60\3\7\1\61\2\7\1\61"+
+ "\1\34\1\35\34\7\3\10\1\0\10\10\1\36\1\37"+
+ "\36\10\1\62\3\10\1\63\2\10\1\63\1\10\1\36"+
+ "\1\37\33\10\5\0\2\4\1\0\2\4\5\0\11\4"+
+ "\1\74\5\4\6\0\5\4\5\0\2\4\1\0\2\4"+
+ "\5\0\17\4\6\0\3\4\1\75\1\4\5\0\2\4"+
+ "\1\0\2\4\5\0\17\4\6\0\4\4\1\76\5\0"+
+ "\2\4\1\0\2\4\5\0\17\4\6\0\2\4\1\77"+
+ "\2\4\6\56\1\100\2\56\1\72\37\56\5\0\2\4"+
+ "\1\0\2\4\5\0\7\4\1\101\7\4\6\0\5\4"+
+ "\5\0\2\4\1\0\2\4\5\0\17\4\6\0\2\4"+
+ "\1\102\2\4\5\0\2\4\1\0\2\4\5\0\11\4"+
+ "\1\103\5\4\6\0\5\4\5\0\2\4\1\0\2\4"+
+ "\5\0\12\4\1\104\4\4\6\0\5\4\5\0\2\4"+
+ "\1\0\2\4\5\0\13\4\1\71\3\4\6\0\5\4";
+
+ private static int [] zzUnpackTrans() {
+ int [] result = new int[2173];
+ int offset = 0;
+ offset = zzUnpackTrans(ZZ_TRANS_PACKED_0, offset, result);
+ return result;
+ }
+
+ private static int zzUnpackTrans(String packed, int offset, int [] result) {
+ int i = 0; /* index in packed string */
+ int j = offset; /* index in unpacked array */
+ int l = packed.length();
+ while (i < l) {
+ int count = packed.charAt(i++);
+ int value = packed.charAt(i++);
+ value--;
+ do result[j++] = value; while (--count > 0);
+ }
+ return j;
+ }
+
+
+ /* error codes */
+ private static final int ZZ_UNKNOWN_ERROR = 0;
+ private static final int ZZ_NO_MATCH = 1;
+ private static final int ZZ_PUSHBACK_2BIG = 2;
+
+ /* error messages for the codes above */
+ private static final String[] ZZ_ERROR_MSG = {
+ "Unknown internal scanner error",
+ "Error: could not match input",
+ "Error: pushback value was too large"
+ };
+
+ /**
+ * ZZ_ATTRIBUTE[aState] contains the attributes of state aState
+ */
+ private static final int [] ZZ_ATTRIBUTE = zzUnpackAttribute();
+
+ private static final String ZZ_ATTRIBUTE_PACKED_0 =
+ "\1\1\1\11\21\1\6\11\2\1\1\11\2\0\1\11"+
+ "\32\1\1\0\5\1\1\11\4\1";
+
+ private static int [] zzUnpackAttribute() {
+ int [] result = new int[68];
+ int offset = 0;
+ offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result);
+ return result;
+ }
+
+ private static int zzUnpackAttribute(String packed, int offset, int [] result) {
+ int i = 0; /* index in packed string */
+ int j = offset; /* index in unpacked array */
+ int l = packed.length();
+ while (i < l) {
+ int count = packed.charAt(i++);
+ int value = packed.charAt(i++);
+ do result[j++] = value; while (--count > 0);
+ }
+ return j;
+ }
+
+ /** the input device */
+ private java.io.Reader zzReader;
+
+ /** the current state of the DFA */
+ private int zzState;
+
+ /** the current lexical state */
+ private int zzLexicalState = YYINITIAL;
+
+ /** this buffer contains the current text to be matched and is
+ the source of the yytext() string */
+ private CharSequence zzBuffer = "";
+
+ /** the textposition at the last accepting state */
+ private int zzMarkedPos;
+
+ /** the current text position in the buffer */
+ private int zzCurrentPos;
+
+ /** startRead marks the beginning of the yytext() string in the buffer */
+ private int zzStartRead;
+
+ /** endRead marks the last character in the buffer, that has been read
+ from input */
+ private int zzEndRead;
+
+ /**
+ * zzAtBOL == true <=> the scanner is currently at the beginning of a line
+ */
+ private boolean zzAtBOL = true;
+
+ /** zzAtEOF == true <=> the scanner is at the EOF */
+ private boolean zzAtEOF;
+
+ /** denotes if the user-EOF-code has already been executed */
+ private boolean zzEOFDone;
+
+ /* user code: */
+ public _Json5Lexer() {
+ this((java.io.Reader)null);
+ }
+
+
+ /**
+ * Creates a new scanner
+ *
+ * @param in the java.io.Reader to read input from.
+ */
+ public _Json5Lexer(java.io.Reader in) {
+ this.zzReader = in;
+ }
+
+
+ /**
+ * Unpacks the compressed character translation table.
+ *
+ * @param packed the packed character translation table
+ * @return the unpacked character translation table
+ */
+ private static char [] zzUnpackCMap(String packed) {
+ int size = 0;
+ for (int i = 0, length = packed.length(); i < length; i += 2) {
+ size += packed.charAt(i);
+ }
+ char[] map = new char[size];
+ int i = 0; /* index in packed string */
+ int j = 0; /* index in unpacked array */
+ while (i < packed.length()) {
+ int count = packed.charAt(i++);
+ char value = packed.charAt(i++);
+ do map[j++] = value; while (--count > 0);
+ }
+ return map;
+ }
+
+ public final int getTokenStart() {
+ return zzStartRead;
+ }
+
+ public final int getTokenEnd() {
+ return getTokenStart() + yylength();
+ }
+
+ public void reset(CharSequence buffer, int start, int end, int initialState) {
+ zzBuffer = buffer;
+ zzCurrentPos = zzMarkedPos = zzStartRead = start;
+ zzAtEOF = false;
+ zzAtBOL = true;
+ zzEndRead = end;
+ yybegin(initialState);
+ }
+
+ /**
+ * Refills the input buffer.
+ *
+ * @return false, iff there was new input.
+ *
+ * @exception java.io.IOException if any I/O-Error occurs
+ */
+ private boolean zzRefill() throws java.io.IOException {
+ return true;
+ }
+
+
+ /**
+ * Returns the current lexical state.
+ */
+ public final int yystate() {
+ return zzLexicalState;
+ }
+
+
+ /**
+ * Enters a new lexical state
+ *
+ * @param newState the new lexical state
+ */
+ public final void yybegin(int newState) {
+ zzLexicalState = newState;
+ }
+
+
+ /**
+ * Returns the text matched by the current regular expression.
+ */
+ public final CharSequence yytext() {
+ return zzBuffer.subSequence(zzStartRead, zzMarkedPos);
+ }
+
+
+ /**
+ * Returns the character at position pos from the
+ * matched text.
+ *
+ * It is equivalent to yytext().charAt(pos), but faster
+ *
+ * @param pos the position of the character to fetch.
+ * A value from 0 to yylength()-1.
+ *
+ * @return the character at position pos
+ */
+ public final char yycharat(int pos) {
+ return zzBuffer.charAt(zzStartRead+pos);
+ }
+
+
+ /**
+ * Returns the length of the matched text region.
+ */
+ public final int yylength() {
+ return zzMarkedPos-zzStartRead;
+ }
+
+
+ /**
+ * Reports an error that occured while scanning.
+ *
+ * In a wellformed scanner (no or only correct usage of
+ * yypushback(int) and a match-all fallback rule) this method
+ * will only be called with things that "Can't Possibly Happen".
+ * If this method is called, something is seriously wrong
+ * (e.g. a JFlex bug producing a faulty scanner etc.).
+ *
+ * Usual syntax/scanner level error handling should be done
+ * in error fallback rules.
+ *
+ * @param errorCode the code of the errormessage to display
+ */
+ private void zzScanError(int errorCode) {
+ String message;
+ try {
+ message = ZZ_ERROR_MSG[errorCode];
+ }
+ catch (ArrayIndexOutOfBoundsException e) {
+ message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR];
+ }
+
+ throw new Error(message);
+ }
+
+
+ /**
+ * Pushes the specified amount of characters back into the input stream.
+ *
+ * They will be read again by then next call of the scanning method
+ *
+ * @param number the number of characters to be read again.
+ * This number must not be greater than yylength()!
+ */
+ public void yypushback(int number) {
+ if ( number > yylength() )
+ zzScanError(ZZ_PUSHBACK_2BIG);
+
+ zzMarkedPos -= number;
+ }
+
+
+ /**
+ * Resumes scanning until the next regular expression is matched,
+ * the end of input is encountered or an I/O-Error occurs.
+ *
+ * @return the next token
+ * @exception java.io.IOException if any I/O-Error occurs
+ */
+ public IElementType advance() throws java.io.IOException {
+ int zzInput;
+ int zzAction;
+
+ // cached fields:
+ int zzCurrentPosL;
+ int zzMarkedPosL;
+ int zzEndReadL = zzEndRead;
+ CharSequence zzBufferL = zzBuffer;
+
+ int [] zzTransL = ZZ_TRANS;
+ int [] zzRowMapL = ZZ_ROWMAP;
+ int [] zzAttrL = ZZ_ATTRIBUTE;
+
+ while (true) {
+ zzMarkedPosL = zzMarkedPos;
+
+ zzAction = -1;
+
+ zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL;
+
+ zzState = ZZ_LEXSTATE[zzLexicalState];
+
+ // set up zzAction for empty match case:
+ int zzAttributes = zzAttrL[zzState];
+ if ( (zzAttributes & 1) == 1 ) {
+ zzAction = zzState;
+ }
+
+
+ zzForAction: {
+ while (true) {
+
+ if (zzCurrentPosL < zzEndReadL) {
+ zzInput = Character.codePointAt(zzBufferL, zzCurrentPosL/*, zzEndReadL*/);
+ zzCurrentPosL += Character.charCount(zzInput);
+ }
+ else if (zzAtEOF) {
+ zzInput = YYEOF;
+ break zzForAction;
+ }
+ else {
+ // store back cached positions
+ zzCurrentPos = zzCurrentPosL;
+ zzMarkedPos = zzMarkedPosL;
+ boolean eof = zzRefill();
+ // get translated positions and possibly new buffer
+ zzCurrentPosL = zzCurrentPos;
+ zzMarkedPosL = zzMarkedPos;
+ zzBufferL = zzBuffer;
+ zzEndReadL = zzEndRead;
+ if (eof) {
+ zzInput = YYEOF;
+ break zzForAction;
+ }
+ else {
+ zzInput = Character.codePointAt(zzBufferL, zzCurrentPosL/*, zzEndReadL*/);
+ zzCurrentPosL += Character.charCount(zzInput);
+ }
+ }
+ int zzNext = zzTransL[ zzRowMapL[zzState] + ZZ_CMAP(zzInput) ];
+ if (zzNext == -1) break zzForAction;
+ zzState = zzNext;
+
+ zzAttributes = zzAttrL[zzState];
+ if ( (zzAttributes & 1) == 1 ) {
+ zzAction = zzState;
+ zzMarkedPosL = zzCurrentPosL;
+ if ( (zzAttributes & 8) == 8 ) break zzForAction;
+ }
+
+ }
+ }
+
+ // store back cached position
+ zzMarkedPos = zzMarkedPosL;
+
+ if (zzInput == YYEOF && zzStartRead == zzCurrentPos) {
+ zzAtEOF = true;
+ return null;
+ }
+ else {
+ switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) {
+ case 1:
+ { return NUMBER;
+ }
+ // fall through
+ case 18: break;
+ case 2:
+ { return BAD_CHARACTER;
+ }
+ // fall through
+ case 19: break;
+ case 3:
+ { return WHITE_SPACE;
+ }
+ // fall through
+ case 20: break;
+ case 4:
+ { return IDENTIFIER;
+ }
+ // fall through
+ case 21: break;
+ case 5:
+ { return DOUBLE_QUOTED_STRING;
+ }
+ // fall through
+ case 22: break;
+ case 6:
+ { return SINGLE_QUOTED_STRING;
+ }
+ // fall through
+ case 23: break;
+ case 7:
+ { return L_CURLY;
+ }
+ // fall through
+ case 24: break;
+ case 8:
+ { return R_CURLY;
+ }
+ // fall through
+ case 25: break;
+ case 9:
+ { return L_BRACKET;
+ }
+ // fall through
+ case 26: break;
+ case 10:
+ { return R_BRACKET;
+ }
+ // fall through
+ case 27: break;
+ case 11:
+ { return COMMA;
+ }
+ // fall through
+ case 28: break;
+ case 12:
+ { return COLON;
+ }
+ // fall through
+ case 29: break;
+ case 13:
+ { return LINE_COMMENT;
+ }
+ // fall through
+ case 30: break;
+ case 14:
+ { return BLOCK_COMMENT;
+ }
+ // fall through
+ case 31: break;
+ case 15:
+ { return NULL;
+ }
+ // fall through
+ case 32: break;
+ case 16:
+ { return TRUE;
+ }
+ // fall through
+ case 33: break;
+ case 17:
+ { return FALSE;
+ }
+ // fall through
+ case 34: break;
+ default:
+ zzScanError(ZZ_NO_MATCH);
+ }
+ }
+ }
+ }
+
+
+}
diff --git a/json/resources/inspectionDescriptions/Json5StandardCompliance.html b/json/resources/inspectionDescriptions/Json5StandardCompliance.html
new file mode 100644
index 000000000000..8171150e6345
--- /dev/null
+++ b/json/resources/inspectionDescriptions/Json5StandardCompliance.html
@@ -0,0 +1,5 @@
+
+
+This inspection checks that JSON5 files conform to language specification (http://json5.org/).
+
+
\ No newline at end of file
diff --git a/json/src/com/intellij/json/JsonBundle.java b/json/src/com/intellij/json/JsonBundle.java
index 836df2a05225..9ccab90f24f9 100644
--- a/json/src/com/intellij/json/JsonBundle.java
+++ b/json/src/com/intellij/json/JsonBundle.java
@@ -15,7 +15,7 @@ import java.util.ResourceBundle;
public class JsonBundle {
private static Reference ourBundle;
- @NonNls private static final String BUNDLE = "com.intellij.json.JsonBundle";
+ @NonNls public static final String BUNDLE = "com.intellij.json.JsonBundle";
private JsonBundle() {
// empty
diff --git a/json/src/com/intellij/json/JsonBundle.properties b/json/src/com/intellij/json/JsonBundle.properties
index 55803d7ea4ca..bd1cd5e4b5a0 100644
--- a/json/src/com/intellij/json/JsonBundle.properties
+++ b/json/src/com/intellij/json/JsonBundle.properties
@@ -9,8 +9,10 @@ syntax.error.illegal.floating.point.literal=Illegal floating point literal
# Inspections
json.inspection.group=JSON
+json.inspection5.group=JSON/JSON5
inspection.compliance.name=Compliance with JSON standard
+inspection.compliance5.name=Compliance with JSON5 standard
inspection.compliance.msg.comments=JSON standard does not allow comments. Use JSMin or similar tool to remove comments before parsing.
inspection.compliance.msg.single.quoted.strings=JSON standard does not allow single quoted strings
inspection.compliance.msg.bad.token=JSON standard does not allow such tokens
diff --git a/json/src/com/intellij/json/JsonDialectUtil.java b/json/src/com/intellij/json/JsonDialectUtil.java
new file mode 100644
index 000000000000..b2ffe61f0936
--- /dev/null
+++ b/json/src/com/intellij/json/JsonDialectUtil.java
@@ -0,0 +1,20 @@
+// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.json;
+
+import com.intellij.lang.Language;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import org.jetbrains.annotations.NotNull;
+
+public class JsonDialectUtil {
+ public static boolean isStandardJson(@NotNull PsiElement element) {
+ return getLanguage(element) == JsonLanguage.INSTANCE;
+ }
+
+ public static Language getLanguage(@NotNull PsiElement element) {
+ PsiFile file = element.getContainingFile();
+ if (file == null) return JsonLanguage.INSTANCE;
+ Language language = file.getLanguage();
+ return language instanceof JsonLanguage ? language : JsonLanguage.INSTANCE;
+ }
+}
diff --git a/json/src/com/intellij/json/JsonFileType.java b/json/src/com/intellij/json/JsonFileType.java
index c57408538077..6137ceea0e6d 100644
--- a/json/src/com/intellij/json/JsonFileType.java
+++ b/json/src/com/intellij/json/JsonFileType.java
@@ -1,11 +1,12 @@
package com.intellij.json;
import com.intellij.icons.AllIcons;
+import com.intellij.lang.Language;
import com.intellij.openapi.fileTypes.LanguageFileType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import javax.swing.Icon;
+import javax.swing.*;
/**
* @author Mikhail Golubev
@@ -14,6 +15,10 @@ public class JsonFileType extends LanguageFileType{
public static final JsonFileType INSTANCE = new JsonFileType();
public static final String DEFAULT_EXTENSION = "json";
+ protected JsonFileType(Language language) {
+ super(language);
+ }
+
public JsonFileType() {
super(JsonLanguage.INSTANCE);
}
diff --git a/json/src/com/intellij/json/JsonLanguage.java b/json/src/com/intellij/json/JsonLanguage.java
index 7c5e4c4a1662..9d73f86a4389 100644
--- a/json/src/com/intellij/json/JsonLanguage.java
+++ b/json/src/com/intellij/json/JsonLanguage.java
@@ -5,6 +5,10 @@ import com.intellij.lang.Language;
public class JsonLanguage extends Language {
public static final JsonLanguage INSTANCE = new JsonLanguage();
+ protected JsonLanguage(String ID, String... mimeTypes) {
+ super(INSTANCE, ID, mimeTypes);
+ }
+
private JsonLanguage() {
super("JSON", "application/json", "application/vnd.api+json", "application/hal+json");
}
diff --git a/json/src/com/intellij/json/JsonParserDefinition.java b/json/src/com/intellij/json/JsonParserDefinition.java
index 2eca5d3d2119..c7f123c25a66 100644
--- a/json/src/com/intellij/json/JsonParserDefinition.java
+++ b/json/src/com/intellij/json/JsonParserDefinition.java
@@ -74,7 +74,7 @@ public class JsonParserDefinition implements ParserDefinition {
@Override
public PsiFile createFile(FileViewProvider fileViewProvider) {
- return new JsonFileImpl(fileViewProvider);
+ return new JsonFileImpl(fileViewProvider, JsonLanguage.INSTANCE);
}
@Override
diff --git a/json/src/com/intellij/json/codeinsight/JsonLiteralAnnotator.java b/json/src/com/intellij/json/codeinsight/JsonLiteralAnnotator.java
index d2b098ae167d..e2537152a7d6 100644
--- a/json/src/com/intellij/json/codeinsight/JsonLiteralAnnotator.java
+++ b/json/src/com/intellij/json/codeinsight/JsonLiteralAnnotator.java
@@ -19,6 +19,7 @@ import com.intellij.json.JsonBundle;
import com.intellij.json.highlighting.JsonSyntaxHighlighterFactory;
import com.intellij.json.psi.JsonNumberLiteral;
import com.intellij.json.psi.JsonPsiUtil;
+import com.intellij.json.psi.JsonReferenceExpression;
import com.intellij.json.psi.JsonStringLiteral;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.lang.annotation.Annotator;
@@ -29,14 +30,11 @@ import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import java.util.List;
-import java.util.regex.Pattern;
/**
* @author Mikhail Golubev
*/
public class JsonLiteralAnnotator implements Annotator {
- private static final Pattern VALID_ESCAPE = Pattern.compile("\\\\([\"\\\\/bfnrt]|u[0-9a-fA-F]{4})");
- private static final Pattern VALID_NUMBER_LITERAL = Pattern.compile("-?(0|[1-9][0-9]*)(\\.[0-9]+)?([eE][+-]?[0-9]+)?");
private static class Holder {
private static final boolean DEBUG = ApplicationManager.getApplication().isUnitTestMode();
@@ -45,12 +43,14 @@ public class JsonLiteralAnnotator implements Annotator {
@Override
public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) {
final String text = JsonPsiUtil.getElementTextWithoutHostEscaping(element);
- if (element instanceof JsonStringLiteral) {
+ JsonLiteralChecker[] extensions = JsonLiteralChecker.EP_NAME.getExtensions();
+ if (element instanceof JsonReferenceExpression) {
+ highlightPropertyKey(element, holder);
+ }
+ else if (element instanceof JsonStringLiteral) {
final JsonStringLiteral stringLiteral = (JsonStringLiteral)element;
final int elementOffset = element.getTextOffset();
- if (JsonPsiUtil.isPropertyKey(element)) {
- holder.createInfoAnnotation(element, Holder.DEBUG ? "property key" : null).setTextAttributes(JsonSyntaxHighlighterFactory.JSON_PROPERTY_KEY);
- }
+ highlightPropertyKey(element, holder);
final int length = text.length();
// Check that string literal is closed properly
@@ -60,24 +60,31 @@ public class JsonLiteralAnnotator implements Annotator {
// Check escapes
final List> fragments = stringLiteral.getTextFragments();
- for (Pair fragment : fragments) {
- final String fragmentText = fragment.getSecond();
- if (fragmentText.startsWith("\\") && fragmentText.length() > 1 && !VALID_ESCAPE.matcher(fragmentText).matches()) {
- final TextRange fragmentRange = fragment.getFirst();
- if (fragmentText.startsWith("\\u")) {
- holder.createErrorAnnotation(fragmentRange.shiftRight(elementOffset), JsonBundle.message(
- "syntax.error.illegal.unicode.escape.sequence"));
- }
- else {
- holder.createErrorAnnotation(fragmentRange.shiftRight(elementOffset), JsonBundle.message("syntax.error.illegal.escape.sequence"));
+ for (Pair fragment: fragments) {
+ for (JsonLiteralChecker checker: extensions) {
+ if (!checker.isApplicable(element)) continue;
+ String error = checker.getErrorForStringFragment(fragment.getSecond());
+ if (error != null) {
+ final TextRange fragmentRange = fragment.getFirst();
+ holder.createErrorAnnotation(fragmentRange.shiftRight(elementOffset), error);
}
}
}
}
else if (element instanceof JsonNumberLiteral) {
- if (!VALID_NUMBER_LITERAL.matcher(text).matches()) {
- holder.createErrorAnnotation(element, JsonBundle.message("syntax.error.illegal.floating.point.literal"));
+ for (JsonLiteralChecker checker: extensions) {
+ if (!checker.isApplicable(element)) continue;
+ String error = checker.getErrorForNumericLiteral(text);
+ if (error != null) {
+ holder.createErrorAnnotation(element, error);
+ }
}
}
}
+
+ private static void highlightPropertyKey(@NotNull PsiElement element, @NotNull AnnotationHolder holder) {
+ if (JsonPsiUtil.isPropertyKey(element)) {
+ holder.createInfoAnnotation(element, Holder.DEBUG ? "property key" : null).setTextAttributes(JsonSyntaxHighlighterFactory.JSON_PROPERTY_KEY);
+ }
+ }
}
diff --git a/json/src/com/intellij/json/codeinsight/JsonLiteralChecker.java b/json/src/com/intellij/json/codeinsight/JsonLiteralChecker.java
new file mode 100644
index 000000000000..73480ad29bf7
--- /dev/null
+++ b/json/src/com/intellij/json/codeinsight/JsonLiteralChecker.java
@@ -0,0 +1,18 @@
+// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.json.codeinsight;
+
+import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.psi.PsiElement;
+import org.jetbrains.annotations.Nullable;
+
+public interface JsonLiteralChecker {
+ ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.json.jsonLiteralChecker");
+
+ @Nullable
+ String getErrorForNumericLiteral(String literalText);
+
+ @Nullable
+ String getErrorForStringFragment(String fragmentText);
+
+ boolean isApplicable(PsiElement element);
+}
diff --git a/json/src/com/intellij/json/codeinsight/JsonStandardComplianceInspection.java b/json/src/com/intellij/json/codeinsight/JsonStandardComplianceInspection.java
index c12c8df2272d..c1d01cae8a70 100644
--- a/json/src/com/intellij/json/codeinsight/JsonStandardComplianceInspection.java
+++ b/json/src/com/intellij/json/codeinsight/JsonStandardComplianceInspection.java
@@ -19,6 +19,7 @@ import com.intellij.codeHighlighting.HighlightDisplayLevel;
import com.intellij.codeInspection.*;
import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel;
import com.intellij.json.JsonBundle;
+import com.intellij.json.JsonDialectUtil;
import com.intellij.json.JsonElementTypes;
import com.intellij.json.psi.*;
import com.intellij.openapi.diagnostic.Logger;
@@ -66,69 +67,8 @@ public class JsonStandardComplianceInspection extends LocalInspectionTool {
@NotNull
@Override
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
- return new JsonElementVisitor() {
- @Override
- public void visitComment(PsiComment comment) {
- if (myWarnAboutComments) {
- if (JsonStandardComplianceProvider.shouldWarnAboutComment(comment)) {
- holder.registerProblem(comment, JsonBundle.message("inspection.compliance.msg.comments"), ProblemHighlightType.WEAK_WARNING);
- }
- }
- }
-
- @Override
- public void visitStringLiteral(@NotNull JsonStringLiteral stringLiteral) {
- if (JsonPsiUtil.getElementTextWithoutHostEscaping(stringLiteral).startsWith("'")) {
- holder.registerProblem(stringLiteral, JsonBundle.message("inspection.compliance.msg.single.quoted.strings"),
- new AddDoubleQuotesFix());
- }
- // May be illegal property key as well
- super.visitStringLiteral(stringLiteral);
- }
-
- @Override
- public void visitLiteral(@NotNull JsonLiteral literal) {
- if (JsonPsiUtil.isPropertyKey(literal) && !JsonPsiUtil.getElementTextWithoutHostEscaping(literal).startsWith("\"")) {
- holder.registerProblem(literal, JsonBundle.message("inspection.compliance.msg.illegal.property.key"), new AddDoubleQuotesFix());
- }
- super.visitLiteral(literal);
- }
-
- @Override
- public void visitReferenceExpression(@NotNull JsonReferenceExpression reference) {
- holder.registerProblem(reference, JsonBundle.message("inspection.compliance.msg.bad.token"), new AddDoubleQuotesFix());
- // May be illegal property key as well
- super.visitReferenceExpression(reference);
- }
-
- @Override
- public void visitArray(@NotNull JsonArray array) {
- final PsiElement trailingComma = findTrailingComma(array, JsonElementTypes.R_BRACKET);
- if (trailingComma != null) {
- holder.registerProblem(trailingComma, JsonBundle.message("inspection.compliance.msg.trailing.comma"));
- }
- super.visitArray(array);
- }
-
- @Override
- public void visitObject(@NotNull JsonObject object) {
- final PsiElement trailingComma = findTrailingComma(object, JsonElementTypes.R_CURLY);
- if (trailingComma != null) {
- holder.registerProblem(trailingComma, JsonBundle.message("inspection.compliance.msg.trailing.comma"));
- }
- super.visitObject(object);
- }
-
- @Override
- public void visitValue(@NotNull JsonValue value) {
- if (value.getContainingFile() instanceof JsonFile) {
- final JsonFile jsonFile = (JsonFile)value.getContainingFile();
- if (myWarnAboutMultipleTopLevelValues && value.getParent() == jsonFile && value != jsonFile.getTopLevelValue()) {
- holder.registerProblem(value, JsonBundle.message("inspection.compliance.msg.multiple.top.level.values"));
- }
- }
- }
- };
+ if (!JsonDialectUtil.isStandardJson(holder.getFile())) return PsiElementVisitor.EMPTY_VISITOR;
+ return new StandardJsonValidatingElementVisitor(holder);
}
@Nullable
@@ -200,4 +140,87 @@ public class JsonStandardComplianceInspection extends LocalInspectionTool {
return result.toString();
}
}
+
+ protected class StandardJsonValidatingElementVisitor extends JsonElementVisitor {
+ private final ProblemsHolder myHolder;
+
+ public StandardJsonValidatingElementVisitor(ProblemsHolder holder) {myHolder = holder;}
+
+ protected boolean allowComments() { return false; }
+ protected boolean allowSingleQuotes() { return false; }
+ protected boolean allowIdentifierPropertyNames() { return false; }
+ protected boolean allowTrailingCommas() { return false; }
+
+ protected boolean isValidPropertyName(@NotNull PsiElement literal) {
+ return literal instanceof JsonLiteral && JsonPsiUtil.getElementTextWithoutHostEscaping(literal).startsWith("\"");
+ }
+
+ @Override
+ public void visitComment(PsiComment comment) {
+ if (!allowComments() && myWarnAboutComments) {
+ if (JsonStandardComplianceProvider.shouldWarnAboutComment(comment)) {
+ myHolder.registerProblem(comment, JsonBundle.message("inspection.compliance.msg.comments"), ProblemHighlightType.WEAK_WARNING);
+ }
+ }
+ }
+
+ @Override
+ public void visitStringLiteral(@NotNull JsonStringLiteral stringLiteral) {
+ if (!allowSingleQuotes() && JsonPsiUtil.getElementTextWithoutHostEscaping(stringLiteral).startsWith("'")) {
+ myHolder.registerProblem(stringLiteral, JsonBundle.message("inspection.compliance.msg.single.quoted.strings"),
+ new AddDoubleQuotesFix());
+ }
+ // May be illegal property key as well
+ super.visitStringLiteral(stringLiteral);
+ }
+
+ @Override
+ public void visitLiteral(@NotNull JsonLiteral literal) {
+ if (JsonPsiUtil.isPropertyKey(literal) && !isValidPropertyName(literal)) {
+ myHolder.registerProblem(literal, JsonBundle.message("inspection.compliance.msg.illegal.property.key"), new AddDoubleQuotesFix());
+ }
+ super.visitLiteral(literal);
+ }
+
+ @Override
+ public void visitReferenceExpression(@NotNull JsonReferenceExpression reference) {
+ if (!allowIdentifierPropertyNames() || !JsonPsiUtil.isPropertyKey(reference) || !isValidPropertyName(reference)) {
+ myHolder.registerProblem(reference, JsonBundle.message("inspection.compliance.msg.bad.token"), new AddDoubleQuotesFix());
+ }
+ // May be illegal property key as well
+ super.visitReferenceExpression(reference);
+ }
+
+ @Override
+ public void visitArray(@NotNull JsonArray array) {
+ if (!allowTrailingCommas()) {
+ final PsiElement trailingComma = findTrailingComma(array, JsonElementTypes.R_BRACKET);
+ if (trailingComma != null) {
+ myHolder.registerProblem(trailingComma, JsonBundle.message("inspection.compliance.msg.trailing.comma"));
+ }
+ }
+ super.visitArray(array);
+ }
+
+ @Override
+ public void visitObject(@NotNull JsonObject object) {
+ if (!allowTrailingCommas()) {
+ final PsiElement trailingComma = findTrailingComma(object, JsonElementTypes.R_CURLY);
+ if (trailingComma != null) {
+ myHolder.registerProblem(trailingComma, JsonBundle.message("inspection.compliance.msg.trailing.comma"));
+ }
+ }
+ super.visitObject(object);
+ }
+
+ @Override
+ public void visitValue(@NotNull JsonValue value) {
+ if (value.getContainingFile() instanceof JsonFile) {
+ final JsonFile jsonFile = (JsonFile)value.getContainingFile();
+ if (myWarnAboutMultipleTopLevelValues && value.getParent() == jsonFile && value != jsonFile.getTopLevelValue()) {
+ myHolder.registerProblem(value, JsonBundle.message("inspection.compliance.msg.multiple.top.level.values"));
+ }
+ }
+ }
+ }
}
diff --git a/json/src/com/intellij/json/codeinsight/StandardJsonLiteralChecker.java b/json/src/com/intellij/json/codeinsight/StandardJsonLiteralChecker.java
new file mode 100644
index 000000000000..21cf6adbbf3f
--- /dev/null
+++ b/json/src/com/intellij/json/codeinsight/StandardJsonLiteralChecker.java
@@ -0,0 +1,47 @@
+// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.json.codeinsight;
+
+import com.intellij.json.JsonBundle;
+import com.intellij.json.JsonDialectUtil;
+import com.intellij.psi.PsiElement;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.regex.Pattern;
+
+public class StandardJsonLiteralChecker implements JsonLiteralChecker {
+ private static final Pattern VALID_ESCAPE = Pattern.compile("\\\\([\"\\\\/bfnrt]|u[0-9a-fA-F]{4})");
+ private static final Pattern VALID_NUMBER_LITERAL = Pattern.compile("-?(0|[1-9][0-9]*)(\\.[0-9]+)?([eE][+-]?[0-9]+)?");
+
+ @Nullable
+ @Override
+ public String getErrorForNumericLiteral(String literalText) {
+ if (!VALID_NUMBER_LITERAL.matcher(literalText).matches()) {
+ return JsonBundle.message("syntax.error.illegal.floating.point.literal");
+ }
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public String getErrorForStringFragment(String fragmentText) {
+ return getStringError(fragmentText);
+ }
+
+ @Nullable
+ public static String getStringError(String fragmentText) {
+ if (fragmentText.startsWith("\\") && fragmentText.length() > 1 && !VALID_ESCAPE.matcher(fragmentText).matches()) {
+ if (fragmentText.startsWith("\\u")) {
+ return JsonBundle.message("syntax.error.illegal.unicode.escape.sequence");
+ }
+ else {
+ return JsonBundle.message("syntax.error.illegal.escape.sequence");
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public boolean isApplicable(PsiElement element) {
+ return JsonDialectUtil.isStandardJson(element);
+ }
+}
diff --git a/json/src/com/intellij/json/highlighting/JsonSyntaxHighlighterFactory.java b/json/src/com/intellij/json/highlighting/JsonSyntaxHighlighterFactory.java
index 8871f7681299..7095a85b77ca 100644
--- a/json/src/com/intellij/json/highlighting/JsonSyntaxHighlighterFactory.java
+++ b/json/src/com/intellij/json/highlighting/JsonSyntaxHighlighterFactory.java
@@ -54,10 +54,9 @@ public class JsonSyntaxHighlighterFactory extends SyntaxHighlighterFactory {
return new MyHighlighter();
}
- private static class MyHighlighter extends SyntaxHighlighterBase {
- private static final Map ourAttributes = new HashMap<>();
-
- static {
+ private class MyHighlighter extends SyntaxHighlighterBase {
+ private final Map ourAttributes = new HashMap<>();
+ {
fillMap(ourAttributes, JSON_BRACES, JsonElementTypes.L_CURLY, JsonElementTypes.R_CURLY);
fillMap(ourAttributes, JSON_BRACKETS, JsonElementTypes.L_BRACKET, JsonElementTypes.R_BRACKET);
fillMap(ourAttributes, JSON_COMMA, JsonElementTypes.COMMA);
@@ -80,10 +79,10 @@ public class JsonSyntaxHighlighterFactory extends SyntaxHighlighterFactory {
@NotNull
@Override
public Lexer getHighlightingLexer() {
- LayeredLexer layeredLexer = new LayeredLexer(new JsonLexer());
- layeredLexer.registerSelfStoppingLayer(new StringLiteralLexer('\"', JsonElementTypes.DOUBLE_QUOTED_STRING, false, "/", false, false),
+ LayeredLexer layeredLexer = new LayeredLexer(getLexer());
+ layeredLexer.registerSelfStoppingLayer(new StringLiteralLexer('\"', JsonElementTypes.DOUBLE_QUOTED_STRING, isCanEscapeEol(), "/", false, false),
new IElementType[]{JsonElementTypes.DOUBLE_QUOTED_STRING}, IElementType.EMPTY_ARRAY);
- layeredLexer.registerSelfStoppingLayer(new StringLiteralLexer('\'', JsonElementTypes.SINGLE_QUOTED_STRING, false, "/", false, false),
+ layeredLexer.registerSelfStoppingLayer(new StringLiteralLexer('\'', JsonElementTypes.SINGLE_QUOTED_STRING, isCanEscapeEol(), "/", false, false),
new IElementType[]{JsonElementTypes.SINGLE_QUOTED_STRING}, IElementType.EMPTY_ARRAY);
return layeredLexer;
}
@@ -94,4 +93,13 @@ public class JsonSyntaxHighlighterFactory extends SyntaxHighlighterFactory {
return pack(ourAttributes.get(type));
}
}
+
+ @NotNull
+ protected Lexer getLexer() {
+ return new JsonLexer();
+ }
+
+ protected boolean isCanEscapeEol() {
+ return false;
+ }
}
diff --git a/json/src/com/intellij/json/json5/Json5FileType.java b/json/src/com/intellij/json/json5/Json5FileType.java
new file mode 100644
index 000000000000..a2b0d68bbe17
--- /dev/null
+++ b/json/src/com/intellij/json/json5/Json5FileType.java
@@ -0,0 +1,32 @@
+// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.json.json5;
+
+import com.intellij.json.JsonFileType;
+import org.jetbrains.annotations.NotNull;
+
+public class Json5FileType extends JsonFileType {
+ public static final Json5FileType INSTANCE = new Json5FileType();
+ public static final String DEFAULT_EXTENSION = "json5";
+
+ public Json5FileType() {
+ super(Json5Language.INSTANCE);
+ }
+
+ @NotNull
+ @Override
+ public String getName() {
+ return "JSON5";
+ }
+
+ @NotNull
+ @Override
+ public String getDescription() {
+ return "JSON5 files";
+ }
+
+ @NotNull
+ @Override
+ public String getDefaultExtension() {
+ return DEFAULT_EXTENSION;
+ }
+}
diff --git a/json/src/com/intellij/json/json5/Json5FileTypeFactory.java b/json/src/com/intellij/json/json5/Json5FileTypeFactory.java
new file mode 100644
index 000000000000..bf6a0254e0a9
--- /dev/null
+++ b/json/src/com/intellij/json/json5/Json5FileTypeFactory.java
@@ -0,0 +1,13 @@
+// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.json.json5;
+
+import com.intellij.openapi.fileTypes.FileTypeConsumer;
+import com.intellij.openapi.fileTypes.FileTypeFactory;
+import org.jetbrains.annotations.NotNull;
+
+public class Json5FileTypeFactory extends FileTypeFactory {
+ @Override
+ public void createFileTypes(@NotNull FileTypeConsumer consumer) {
+ consumer.consume(Json5FileType.INSTANCE, Json5FileType.DEFAULT_EXTENSION);
+ }
+}
diff --git a/json/src/com/intellij/json/json5/Json5Language.java b/json/src/com/intellij/json/json5/Json5Language.java
new file mode 100644
index 000000000000..3bd1476f9c9c
--- /dev/null
+++ b/json/src/com/intellij/json/json5/Json5Language.java
@@ -0,0 +1,12 @@
+// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.json.json5;
+
+import com.intellij.json.JsonLanguage;
+
+public class Json5Language extends JsonLanguage {
+ public static final Json5Language INSTANCE = new Json5Language();
+
+ protected Json5Language() {
+ super("JSON5", "application/json5");
+ }
+}
diff --git a/json/src/com/intellij/json/json5/Json5Lexer.java b/json/src/com/intellij/json/json5/Json5Lexer.java
new file mode 100644
index 000000000000..0617e3790a03
--- /dev/null
+++ b/json/src/com/intellij/json/json5/Json5Lexer.java
@@ -0,0 +1,10 @@
+// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.json.json5;
+
+import com.intellij.lexer.FlexAdapter;
+
+public class Json5Lexer extends FlexAdapter {
+ public Json5Lexer() {
+ super(new _Json5Lexer());
+ }
+}
diff --git a/json/src/com/intellij/json/json5/Json5ParserDefinition.java b/json/src/com/intellij/json/json5/Json5ParserDefinition.java
new file mode 100644
index 000000000000..d0b146bc0669
--- /dev/null
+++ b/json/src/com/intellij/json/json5/Json5ParserDefinition.java
@@ -0,0 +1,31 @@
+// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.json.json5;
+
+import com.intellij.json.JsonParserDefinition;
+import com.intellij.json.psi.impl.JsonFileImpl;
+import com.intellij.lexer.Lexer;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.FileViewProvider;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.tree.IFileElementType;
+import org.jetbrains.annotations.NotNull;
+
+public class Json5ParserDefinition extends JsonParserDefinition {
+ public static final IFileElementType FILE = new IFileElementType(Json5Language.INSTANCE);
+
+ @NotNull
+ @Override
+ public Lexer createLexer(Project project) {
+ return new Json5Lexer();
+ }
+
+ @Override
+ public PsiFile createFile(FileViewProvider fileViewProvider) {
+ return new JsonFileImpl(fileViewProvider, Json5Language.INSTANCE);
+ }
+
+ @Override
+ public IFileElementType getFileNodeType() {
+ return FILE;
+ }
+}
diff --git a/json/src/com/intellij/json/json5/Json5PsiWalkerFactory.java b/json/src/com/intellij/json/json5/Json5PsiWalkerFactory.java
new file mode 100644
index 000000000000..6ba518b40771
--- /dev/null
+++ b/json/src/com/intellij/json/json5/Json5PsiWalkerFactory.java
@@ -0,0 +1,36 @@
+// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.json.json5;
+
+import com.intellij.codeInsight.completion.CompletionUtil;
+import com.intellij.json.JsonDialectUtil;
+import com.intellij.psi.PsiElement;
+import com.jetbrains.jsonSchema.extension.JsonLikePsiWalker;
+import com.jetbrains.jsonSchema.extension.JsonLikePsiWalkerFactory;
+import com.jetbrains.jsonSchema.impl.JsonOriginalPsiWalker;
+import com.jetbrains.jsonSchema.impl.JsonSchemaObject;
+import org.jetbrains.annotations.NotNull;
+
+public class Json5PsiWalkerFactory implements JsonLikePsiWalkerFactory {
+ @Override
+ public boolean handles(@NotNull PsiElement element) {
+ PsiElement parent = element.getParent();
+ if (parent == null) return false;
+ return JsonDialectUtil.getLanguage(CompletionUtil.getOriginalOrSelf(parent)) == Json5Language.INSTANCE;
+ }
+
+ @NotNull
+ @Override
+ public JsonLikePsiWalker create(@NotNull JsonSchemaObject schemaObject) {
+ return new JsonOriginalPsiWalker() {
+ @Override
+ public boolean isNameQuoted() {
+ return false;
+ }
+
+ @Override
+ public boolean onlyDoubleQuotesForStringLiterals() {
+ return false;
+ }
+ };
+ }
+}
diff --git a/json/src/com/intellij/json/json5/_Json5Lexer.flex b/json/src/com/intellij/json/json5/_Json5Lexer.flex
new file mode 100644
index 000000000000..24df142cea20
--- /dev/null
+++ b/json/src/com/intellij/json/json5/_Json5Lexer.flex
@@ -0,0 +1,64 @@
+package com.intellij.json.json5;
+
+import com.intellij.lexer.FlexLexer;
+import com.intellij.psi.tree.IElementType;
+
+import static com.intellij.psi.TokenType.BAD_CHARACTER;
+import static com.intellij.psi.TokenType.WHITE_SPACE;
+import static com.intellij.json.JsonElementTypes.*;
+
+%%
+
+%{
+ public _Json5Lexer() {
+ this((java.io.Reader)null);
+ }
+%}
+
+%public
+%class _Json5Lexer
+%implements FlexLexer
+%function advance
+%type IElementType
+%unicode
+
+EOL=\R
+WHITE_SPACE=\s+
+HEX_DIGIT=[0-9A-Fa-f]
+
+LINE_COMMENT="//".*
+BLOCK_COMMENT="/"\*([^*]|\*+[^*/])*(\*+"/")?
+LINE_TERMINATOR_SEQUENCE=\R
+CRLF= [\ \t \f]* {LINE_TERMINATOR_SEQUENCE}
+DOUBLE_QUOTED_STRING=\"([^\\\"\r\n]|\\[^\r\n]|\\{CRLF})*\"?
+SINGLE_QUOTED_STRING='([^\\'\r\n]|\\[^\r\n]|\\{CRLF})*'?
+JSON5_NUMBER=(\+|-)?(0|[1-9][0-9]*)?\.?([0-9]+)?([eE][+-]?[0-9]*)?
+HEX_DIGITS=({HEX_DIGIT})+
+HEX_INTEGER_LITERAL=0[Xx]({HEX_DIGITS})
+NUMBER={JSON5_NUMBER}|{HEX_INTEGER_LITERAL}|Infinity|-Infinity|\+Infinity|NaN|-NaN|\+NaN
+IDENTIFIER=[[:jletterdigit:]~!()*\-."/"@\^<>=]+
+
+%%
+ {
+ {WHITE_SPACE} { return WHITE_SPACE; }
+
+ "{" { return L_CURLY; }
+ "}" { return R_CURLY; }
+ "[" { return L_BRACKET; }
+ "]" { return R_BRACKET; }
+ "," { return COMMA; }
+ ":" { return COLON; }
+ "true" { return TRUE; }
+ "false" { return FALSE; }
+ "null" { return NULL; }
+
+ {LINE_COMMENT} { return LINE_COMMENT; }
+ {BLOCK_COMMENT} { return BLOCK_COMMENT; }
+ {DOUBLE_QUOTED_STRING} { return DOUBLE_QUOTED_STRING; }
+ {SINGLE_QUOTED_STRING} { return SINGLE_QUOTED_STRING; }
+ {NUMBER} { return NUMBER; }
+ {IDENTIFIER} { return IDENTIFIER; }
+
+}
+
+[^] { return BAD_CHARACTER; }
diff --git a/json/src/com/intellij/json/json5/codeinsight/Json5JsonLiteralChecker.java b/json/src/com/intellij/json/json5/codeinsight/Json5JsonLiteralChecker.java
new file mode 100644
index 000000000000..629fb0104230
--- /dev/null
+++ b/json/src/com/intellij/json/json5/codeinsight/Json5JsonLiteralChecker.java
@@ -0,0 +1,34 @@
+// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.json.json5.codeinsight;
+
+import com.intellij.json.JsonDialectUtil;
+import com.intellij.json.codeinsight.JsonLiteralChecker;
+import com.intellij.json.codeinsight.StandardJsonLiteralChecker;
+import com.intellij.json.json5.Json5Language;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.PsiElement;
+import org.jetbrains.annotations.Nullable;
+
+public class Json5JsonLiteralChecker implements JsonLiteralChecker {
+ @Nullable
+ @Override
+ public String getErrorForNumericLiteral(String literalText) {
+ return null;
+ }
+
+ @Nullable
+ @Override
+ public String getErrorForStringFragment(String fragmentText) {
+ if (fragmentText.startsWith("\\") && fragmentText.length() > 1 && fragmentText.endsWith("\n")) {
+ if (StringUtil.isEmptyOrSpaces(fragmentText.substring(1, fragmentText.length() - 1))) {
+ return null;
+ }
+ }
+ return StandardJsonLiteralChecker.getStringError(fragmentText);
+ }
+
+ @Override
+ public boolean isApplicable(PsiElement element) {
+ return JsonDialectUtil.getLanguage(element) == Json5Language.INSTANCE;
+ }
+}
diff --git a/json/src/com/intellij/json/json5/codeinsight/Json5StandardComplianceInspection.java b/json/src/com/intellij/json/json5/codeinsight/Json5StandardComplianceInspection.java
new file mode 100644
index 000000000000..cd5b2412ea6e
--- /dev/null
+++ b/json/src/com/intellij/json/json5/codeinsight/Json5StandardComplianceInspection.java
@@ -0,0 +1,66 @@
+// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.json.json5.codeinsight;
+
+import com.intellij.codeInspection.ProblemsHolder;
+import com.intellij.json.JsonBundle;
+import com.intellij.json.JsonDialectUtil;
+import com.intellij.json.codeinsight.JsonStandardComplianceInspection;
+import com.intellij.json.psi.JsonLiteral;
+import com.intellij.json.psi.JsonPsiUtil;
+import com.intellij.json.psi.JsonReferenceExpression;
+import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiElementVisitor;
+import org.jetbrains.annotations.NotNull;
+
+public class Json5StandardComplianceInspection extends JsonStandardComplianceInspection {
+
+ @NotNull
+ public String getDisplayName() {
+ return JsonBundle.message("inspection.compliance5.name");
+ }
+
+ @NotNull
+ @Override
+ public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
+ if (JsonDialectUtil.isStandardJson(holder.getFile())) return PsiElementVisitor.EMPTY_VISITOR;
+ return new StandardJson5ValidatingElementVisitor(holder);
+ }
+
+ private class StandardJson5ValidatingElementVisitor extends StandardJsonValidatingElementVisitor {
+ public StandardJson5ValidatingElementVisitor(ProblemsHolder holder) {
+ super(holder);
+ }
+
+ @Override
+ protected boolean allowComments() {
+ return true;
+ }
+
+ @Override
+ protected boolean allowSingleQuotes() {
+ return true;
+ }
+
+ @Override
+ protected boolean allowIdentifierPropertyNames() {
+ return true;
+ }
+
+ @Override
+ protected boolean allowTrailingCommas() {
+ return true;
+ }
+
+ protected boolean isValidPropertyName(@NotNull PsiElement literal) {
+ if (literal instanceof JsonLiteral) {
+ String textWithoutHostEscaping = JsonPsiUtil.getElementTextWithoutHostEscaping(literal);
+ return textWithoutHostEscaping.startsWith("\"") || textWithoutHostEscaping.startsWith("'");
+ }
+ if (literal instanceof JsonReferenceExpression) {
+ return StringUtil.isJavaIdentifier(literal.getText());
+ }
+ return false;
+ }
+ }
+}
diff --git a/json/src/com/intellij/json/json5/highlighting/Json5SyntaxHighlightingFactory.java b/json/src/com/intellij/json/json5/highlighting/Json5SyntaxHighlightingFactory.java
new file mode 100644
index 000000000000..f20466f59ce9
--- /dev/null
+++ b/json/src/com/intellij/json/json5/highlighting/Json5SyntaxHighlightingFactory.java
@@ -0,0 +1,20 @@
+// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.json.json5.highlighting;
+
+import com.intellij.json.highlighting.JsonSyntaxHighlighterFactory;
+import com.intellij.json.json5.Json5Lexer;
+import com.intellij.lexer.Lexer;
+import org.jetbrains.annotations.NotNull;
+
+public class Json5SyntaxHighlightingFactory extends JsonSyntaxHighlighterFactory {
+ @NotNull
+ @Override
+ protected Lexer getLexer() {
+ return new Json5Lexer();
+ }
+
+ @Override
+ protected boolean isCanEscapeEol() {
+ return true;
+ }
+}
diff --git a/json/src/com/intellij/json/psi/impl/JsonFileImpl.java b/json/src/com/intellij/json/psi/impl/JsonFileImpl.java
index 9105ab4d24d1..8ddcdd2c11bf 100644
--- a/json/src/com/intellij/json/psi/impl/JsonFileImpl.java
+++ b/json/src/com/intellij/json/psi/impl/JsonFileImpl.java
@@ -1,9 +1,9 @@
package com.intellij.json.psi.impl;
import com.intellij.extapi.psi.PsiFileBase;
-import com.intellij.json.JsonLanguage;
import com.intellij.json.psi.JsonFile;
import com.intellij.json.psi.JsonValue;
+import com.intellij.lang.Language;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.psi.FileViewProvider;
import com.intellij.psi.util.PsiTreeUtil;
@@ -14,8 +14,8 @@ import java.util.List;
public class JsonFileImpl extends PsiFileBase implements JsonFile {
- public JsonFileImpl(FileViewProvider fileViewProvider) {
- super(fileViewProvider, JsonLanguage.INSTANCE);
+ public JsonFileImpl(FileViewProvider fileViewProvider, Language language) {
+ super(fileViewProvider, language);
}
@NotNull
diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonOriginalPsiWalker.java b/json/src/com/jetbrains/jsonSchema/impl/JsonOriginalPsiWalker.java
index 4dedbdeeabd0..0ff19e7f6816 100644
--- a/json/src/com/jetbrains/jsonSchema/impl/JsonOriginalPsiWalker.java
+++ b/json/src/com/jetbrains/jsonSchema/impl/JsonOriginalPsiWalker.java
@@ -1,6 +1,8 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.jetbrains.jsonSchema.impl;
+import com.intellij.codeInsight.completion.CompletionUtil;
+import com.intellij.json.JsonDialectUtil;
import com.intellij.json.JsonElementTypes;
import com.intellij.json.psi.*;
import com.intellij.openapi.util.text.StringUtil;
@@ -28,7 +30,9 @@ public class JsonOriginalPsiWalker implements JsonLikePsiWalker {
public static final JsonOriginalPsiWalker INSTANCE = new JsonOriginalPsiWalker();
public boolean handles(@NotNull PsiElement element) {
- return element instanceof JsonElement || element instanceof LeafPsiElement && element.getParent() instanceof JsonElement;
+ PsiElement parent = element.getParent();
+ return parent != null && (element instanceof JsonElement || element instanceof LeafPsiElement && parent instanceof JsonElement)
+ && JsonDialectUtil.isStandardJson(CompletionUtil.getOriginalOrSelf(parent));
}
@Override
@@ -138,7 +142,7 @@ public class JsonOriginalPsiWalker implements JsonLikePsiWalker {
final JsonObject object = PsiTreeUtil.getParentOfType(element, JsonObject.class);
if (object != null) {
return object.getPropertyList().stream()
- .filter(p -> p.getNameElement() instanceof JsonStringLiteral)
+ .filter(p -> !isNameQuoted() || p.getNameElement() instanceof JsonStringLiteral)
.map(p -> StringUtil.unquoteString(p.getName())).collect(Collectors.toSet());
}
return Collections.emptySet();
diff --git a/json/tests/test/com/intellij/json/JsonHighlightingTest.java b/json/tests/test/com/intellij/json/JsonHighlightingTest.java
index 7c5746a63f56..eed398682b71 100644
--- a/json/tests/test/com/intellij/json/JsonHighlightingTest.java
+++ b/json/tests/test/com/intellij/json/JsonHighlightingTest.java
@@ -6,14 +6,11 @@ import com.intellij.json.codeinsight.JsonStandardComplianceInspection;
/**
* @author Mikhail Golubev
*/
-public class JsonHighlightingTest extends JsonTestCase {
+public class JsonHighlightingTest extends JsonHighlightingTestBase {
- private void doTest() {
- doTestHighlighting(true, true, true);
- }
-
- private long doTestHighlighting(boolean checkInfo, boolean checkWeakWarning, boolean checkWarning) {
- return myFixture.testHighlighting(checkWarning, checkInfo, checkWeakWarning, "/highlighting/" + getTestName(false) + ".json");
+ @Override
+ protected String getExtension() {
+ return "json";
}
private void enableStandardComplianceInspection(boolean checkComments, boolean checkTopLevelValues) {
diff --git a/json/tests/test/com/intellij/json/JsonHighlightingTestBase.java b/json/tests/test/com/intellij/json/JsonHighlightingTestBase.java
new file mode 100644
index 000000000000..623f314fa34d
--- /dev/null
+++ b/json/tests/test/com/intellij/json/JsonHighlightingTestBase.java
@@ -0,0 +1,14 @@
+// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.json;
+
+public abstract class JsonHighlightingTestBase extends JsonTestCase {
+ protected void doTest() {
+ doTestHighlighting(true, true, true);
+ }
+
+ protected abstract String getExtension();
+
+ protected void doTestHighlighting(boolean checkInfo, boolean checkWeakWarning, boolean checkWarning) {
+ myFixture.testHighlighting(checkWarning, checkInfo, checkWeakWarning, "/highlighting/" + getTestName(false) + "." + getExtension());
+ }
+}
diff --git a/json/tests/test/com/intellij/json/json5/Json5HighlightingTest.java b/json/tests/test/com/intellij/json/json5/Json5HighlightingTest.java
new file mode 100644
index 000000000000..d4b7ffcb1b57
--- /dev/null
+++ b/json/tests/test/com/intellij/json/json5/Json5HighlightingTest.java
@@ -0,0 +1,18 @@
+// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.json.json5;
+
+import com.intellij.json.JsonHighlightingTestBase;
+import com.intellij.json.json5.codeinsight.Json5StandardComplianceInspection;
+
+public class Json5HighlightingTest extends JsonHighlightingTestBase {
+
+ @Override
+ protected String getExtension() {
+ return "json5";
+ }
+
+ public void testJSON5() {
+ myFixture.enableInspections(new Json5StandardComplianceInspection());
+ doTestHighlighting(false, true, true);
+ }
+}
diff --git a/json/tests/test/com/intellij/json/json5/Json5ParsingTest.java b/json/tests/test/com/intellij/json/json5/Json5ParsingTest.java
new file mode 100644
index 000000000000..a3fe4b9550c7
--- /dev/null
+++ b/json/tests/test/com/intellij/json/json5/Json5ParsingTest.java
@@ -0,0 +1,27 @@
+// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.json.json5;
+
+import com.intellij.json.JsonParserDefinition;
+import com.intellij.testFramework.ParsingTestCase;
+import com.intellij.testFramework.PlatformTestUtil;
+import com.intellij.testFramework.TestDataPath;
+
+@TestDataPath("$CONTENT_ROOT/testData/psi/")
+public class Json5ParsingTest extends ParsingTestCase {
+ public Json5ParsingTest() {
+ super("psi", "json5", new Json5ParserDefinition(), new JsonParserDefinition());
+ }
+
+ @Override
+ protected String getTestDataPath() {
+ return PlatformTestUtil.getCommunityPath() + "/json/tests/testData";
+ }
+
+ private void doTest() {
+ doTest(true);
+ }
+
+ public void testJson5Syntax() {
+ doTest();
+ }
+}
diff --git a/json/tests/test/com/jetbrains/jsonSchema/json5/Json5ByJsonSchemaCompletionTest.java b/json/tests/test/com/jetbrains/jsonSchema/json5/Json5ByJsonSchemaCompletionTest.java
new file mode 100644
index 000000000000..8abd1fd568cb
--- /dev/null
+++ b/json/tests/test/com/jetbrains/jsonSchema/json5/Json5ByJsonSchemaCompletionTest.java
@@ -0,0 +1,14 @@
+// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.jetbrains.jsonSchema.json5;
+
+import com.jetbrains.jsonSchema.impl.JsonBySchemaCompletionBaseTest;
+
+public class Json5ByJsonSchemaCompletionTest extends JsonBySchemaCompletionBaseTest {
+ public void testTopLevel() throws Exception {
+ testBySchema("{\"properties\": {\"prima\": {}, \"proto\": {}, \"primus\": {}}}", "{pri}", "json5", "prima", "primus", "proto");
+ }
+
+ public void testAlreadyInsertedProperty() throws Exception {
+ testBySchema("{\"properties\": {\"prima\": {}, \"proto\": {}, \"primus\": {}}}", "{prima: 1, pri}", "json5", "primus", "proto");
+ }
+}
diff --git a/json/tests/testData/highlighting/JSON5.json5 b/json/tests/testData/highlighting/JSON5.json5
new file mode 100644
index 000000000000..42f324beb4d1
--- /dev/null
+++ b/json/tests/testData/highlighting/JSON5.json5
@@ -0,0 +1,28 @@
+// no errors in this file!
+{
+ foo: 'bar',
+ while: true,
+
+ this: 'is a \
+multi-line string',
+
+ // this is an inline comment
+ here: 'is another', // inline comment
+
+ /* this is a block comment
+ that continues on another line */
+
+ hex: 0xDEADbeef,
+ half: .5,
+ delta: +10,
+ to: Infinity, // and beyond!
+
+ finally: 'a trailing comma',
+ oh: [
+ "we shouldn't forget",
+ 'arrays can have',
+ 'trailing commas too',
+ ],
+
+}
+
diff --git a/json/tests/testData/psi/Json5Syntax.json5 b/json/tests/testData/psi/Json5Syntax.json5
new file mode 100644
index 000000000000..ff1c4a591947
--- /dev/null
+++ b/json/tests/testData/psi/Json5Syntax.json5
@@ -0,0 +1,26 @@
+{
+ foo: 'bar',
+ while: true,
+
+ this: 'is a \
+multi-line string',
+
+ // this is an inline comment
+ here: 'is another', // inline comment
+
+ /* this is a block comment
+ that continues on another line */
+
+ hex: 0xDEADbeef,
+ half: .5,
+ delta: +10,
+ to: Infinity, // and beyond!
+
+ finally: 'a trailing comma',
+ oh: [
+ "we shouldn't forget",
+ 'arrays can have',
+ 'trailing commas too',
+ ],
+}
+
diff --git a/json/tests/testData/psi/Json5Syntax.txt b/json/tests/testData/psi/Json5Syntax.txt
new file mode 100644
index 000000000000..e9c956eb8903
--- /dev/null
+++ b/json/tests/testData/psi/Json5Syntax.txt
@@ -0,0 +1,117 @@
+JsonFile: Json5Syntax.json5
+ JsonObject
+ PsiElement({)('{')
+ PsiWhiteSpace('\n ')
+ JsonProperty
+ JsonReferenceExpression
+ PsiElement(IDENTIFIER)('foo')
+ PsiElement(:)(':')
+ PsiWhiteSpace(' ')
+ JsonStringLiteral
+ PsiElement(SINGLE_QUOTED_STRING)(''bar'')
+ PsiElement(,)(',')
+ PsiWhiteSpace('\n ')
+ JsonProperty
+ JsonReferenceExpression
+ PsiElement(IDENTIFIER)('while')
+ PsiElement(:)(':')
+ PsiWhiteSpace(' ')
+ JsonBooleanLiteral
+ PsiElement(true)('true')
+ PsiElement(,)(',')
+ PsiWhiteSpace('\n\n ')
+ JsonProperty
+ JsonReferenceExpression
+ PsiElement(IDENTIFIER)('this')
+ PsiElement(:)(':')
+ PsiWhiteSpace(' ')
+ JsonStringLiteral
+ PsiElement(SINGLE_QUOTED_STRING)(''is a \\nmulti-line string'')
+ PsiElement(,)(',')
+ PsiWhiteSpace('\n\n ')
+ PsiComment(LINE_COMMENT)('// this is an inline comment')
+ PsiWhiteSpace('\n ')
+ JsonProperty
+ JsonReferenceExpression
+ PsiElement(IDENTIFIER)('here')
+ PsiElement(:)(':')
+ PsiWhiteSpace(' ')
+ JsonStringLiteral
+ PsiElement(SINGLE_QUOTED_STRING)(''is another'')
+ PsiElement(,)(',')
+ PsiWhiteSpace(' ')
+ PsiComment(LINE_COMMENT)('// inline comment')
+ PsiWhiteSpace('\n\n ')
+ PsiComment(BLOCK_COMMENT)('/* this is a block comment\n that continues on another line */')
+ PsiWhiteSpace('\n\n ')
+ JsonProperty
+ JsonReferenceExpression
+ PsiElement(IDENTIFIER)('hex')
+ PsiElement(:)(':')
+ PsiWhiteSpace(' ')
+ JsonNumberLiteral
+ PsiElement(NUMBER)('0xDEADbeef')
+ PsiElement(,)(',')
+ PsiWhiteSpace('\n ')
+ JsonProperty
+ JsonReferenceExpression
+ PsiElement(IDENTIFIER)('half')
+ PsiElement(:)(':')
+ PsiWhiteSpace(' ')
+ JsonNumberLiteral
+ PsiElement(NUMBER)('.5')
+ PsiElement(,)(',')
+ PsiWhiteSpace('\n ')
+ JsonProperty
+ JsonReferenceExpression
+ PsiElement(IDENTIFIER)('delta')
+ PsiElement(:)(':')
+ PsiWhiteSpace(' ')
+ JsonNumberLiteral
+ PsiElement(NUMBER)('+10')
+ PsiElement(,)(',')
+ PsiWhiteSpace('\n ')
+ JsonProperty
+ JsonReferenceExpression
+ PsiElement(IDENTIFIER)('to')
+ PsiElement(:)(':')
+ PsiWhiteSpace(' ')
+ JsonNumberLiteral
+ PsiElement(NUMBER)('Infinity')
+ PsiElement(,)(',')
+ PsiWhiteSpace(' ')
+ PsiComment(LINE_COMMENT)('// and beyond!')
+ PsiWhiteSpace('\n\n ')
+ JsonProperty
+ JsonReferenceExpression
+ PsiElement(IDENTIFIER)('finally')
+ PsiElement(:)(':')
+ PsiWhiteSpace(' ')
+ JsonStringLiteral
+ PsiElement(SINGLE_QUOTED_STRING)(''a trailing comma'')
+ PsiElement(,)(',')
+ PsiWhiteSpace('\n ')
+ JsonProperty
+ JsonReferenceExpression
+ PsiElement(IDENTIFIER)('oh')
+ PsiElement(:)(':')
+ PsiWhiteSpace(' ')
+ JsonArray
+ PsiElement([)('[')
+ PsiWhiteSpace('\n ')
+ JsonStringLiteral
+ PsiElement(DOUBLE_QUOTED_STRING)('"we shouldn't forget"')
+ PsiElement(,)(',')
+ PsiWhiteSpace('\n ')
+ JsonStringLiteral
+ PsiElement(SINGLE_QUOTED_STRING)(''arrays can have'')
+ PsiElement(,)(',')
+ PsiWhiteSpace('\n ')
+ JsonStringLiteral
+ PsiElement(SINGLE_QUOTED_STRING)(''trailing commas too'')
+ PsiElement(,)(',')
+ PsiWhiteSpace('\n ')
+ PsiElement(])(']')
+ PsiElement(,)(',')
+ PsiWhiteSpace('\n')
+ PsiElement(})('}')
\ No newline at end of file
diff --git a/platform/platform-resources/src/META-INF/JsonPlugin.xml b/platform/platform-resources/src/META-INF/JsonPlugin.xml
index f2bf76dcacc0..65a70e5cba6b 100644
--- a/platform/platform-resources/src/META-INF/JsonPlugin.xml
+++ b/platform/platform-resources/src/META-INF/JsonPlugin.xml
@@ -16,9 +16,12 @@
+
+
+
@@ -48,6 +51,9 @@
+
+
+
@@ -56,6 +62,10 @@
bundle="com.intellij.json.JsonBundle" key="inspection.compliance.name" groupKey="json.inspection.group"
enabledByDefault="true" level="ERROR"
implementationClass="com.intellij.json.codeinsight.JsonStandardComplianceInspection"/>
+
+
+
+
+
+
\ No newline at end of file