|
40 | 40 | import com.semmle.js.ast.jsx.JSXNamespacedName; |
41 | 41 | import com.semmle.js.ast.jsx.JSXOpeningElement; |
42 | 42 | import com.semmle.js.ast.jsx.JSXSpreadAttribute; |
| 43 | +import com.semmle.util.data.Either; |
43 | 44 |
|
44 | 45 | /** |
45 | 46 | * Java port of <a href="https://github.com/RReverser/acorn-jsx">Acorn-JSX</a> as of version |
@@ -92,37 +93,47 @@ private Token jsx_readToken() { |
92 | 93 | for (;;) { |
93 | 94 | if (this.pos >= this.input.length()) |
94 | 95 | this.raise(this.start, "Unterminated JSX contents"); |
95 | | - int ch = this.charAt(this.pos); |
| 96 | + Either<Integer, Token> chunk = jsx_readChunk(out, chunkStart, this.charAt(this.pos)); |
| 97 | + if (chunk.isRight()) |
| 98 | + return chunk.getRight(); |
| 99 | + chunkStart = chunk.getLeft(); |
| 100 | + } |
| 101 | + } |
96 | 102 |
|
97 | | - switch (ch) { |
98 | | - case 60: // '<' |
99 | | - case 123: // '{' |
100 | | - if (this.pos == this.start) { |
101 | | - if (ch == 60 && this.exprAllowed) { |
102 | | - ++this.pos; |
103 | | - return this.finishToken(jsxTagStart); |
104 | | - } |
105 | | - return this.getTokenFromCode(ch); |
| 103 | + /** |
| 104 | + * Reads a chunk of inline JSX content, returning either the start of the next chunk |
| 105 | + * or the completed content token. |
| 106 | + */ |
| 107 | + protected Either<Integer, Token> jsx_readChunk(StringBuilder out, int chunkStart, int ch) { |
| 108 | + switch (ch) { |
| 109 | + case 60: // '<' |
| 110 | + case 123: // '{' |
| 111 | + if (this.pos == this.start) { |
| 112 | + if (ch == 60 && this.exprAllowed) { |
| 113 | + ++this.pos; |
| 114 | + return Either.right(this.finishToken(jsxTagStart)); |
106 | 115 | } |
107 | | - out.append(inputSubstring(chunkStart, this.pos)); |
108 | | - return this.finishToken(jsxText, out.toString()); |
| 116 | + return Either.right(this.getTokenFromCode(ch)); |
| 117 | + } |
| 118 | + out.append(inputSubstring(chunkStart, this.pos)); |
| 119 | + return Either.right(this.finishToken(jsxText, out.toString())); |
109 | 120 |
|
110 | | - case 38: // '&' |
| 121 | + case 38: // '&' |
| 122 | + out.append(inputSubstring(chunkStart, this.pos)); |
| 123 | + out.append(this.jsx_readEntity()); |
| 124 | + chunkStart = this.pos; |
| 125 | + break; |
| 126 | + |
| 127 | + default: |
| 128 | + if (isNewLine(ch)) { |
111 | 129 | out.append(inputSubstring(chunkStart, this.pos)); |
112 | | - out.append(this.jsx_readEntity()); |
| 130 | + out.append(this.jsx_readNewLine(true)); |
113 | 131 | chunkStart = this.pos; |
114 | | - break; |
115 | | - |
116 | | - default: |
117 | | - if (isNewLine(ch)) { |
118 | | - out.append(inputSubstring(chunkStart, this.pos)); |
119 | | - out.append(this.jsx_readNewLine(true)); |
120 | | - chunkStart = this.pos; |
121 | | - } else { |
122 | | - ++this.pos; |
123 | | - } |
| 132 | + } else { |
| 133 | + ++this.pos; |
124 | 134 | } |
125 | 135 | } |
| 136 | + return Either.left(chunkStart); |
126 | 137 | } |
127 | 138 |
|
128 | 139 | private String jsx_readNewLine(boolean normalizeCRLF) { |
|
0 commit comments