UNPKG

8.91 kBJavaScriptView Raw
1"use strict";Object.defineProperty(exports, "__esModule", {value: true});
2
3
4
5
6
7
8
9
10
11var _index = require('../../tokenizer/index');
12var _types = require('../../tokenizer/types');
13var _base = require('../../traverser/base');
14var _expression = require('../../traverser/expression');
15var _util = require('../../traverser/util');
16var _charcodes = require('../../util/charcodes');
17var _identifier = require('../../util/identifier');
18var _typescript = require('../typescript');
19
20// Reads inline JSX contents token.
21function jsxReadToken() {
22 for (;;) {
23 if (_base.state.pos >= _base.input.length) {
24 _util.unexpected.call(void 0, "Unterminated JSX contents");
25 return;
26 }
27
28 const ch = _base.input.charCodeAt(_base.state.pos);
29
30 switch (ch) {
31 case _charcodes.charCodes.lessThan:
32 case _charcodes.charCodes.leftCurlyBrace:
33 if (_base.state.pos === _base.state.start) {
34 if (ch === _charcodes.charCodes.lessThan) {
35 _base.state.pos++;
36 _index.finishToken.call(void 0, _types.TokenType.jsxTagStart);
37 return;
38 }
39 _index.getTokenFromCode.call(void 0, ch);
40 return;
41 }
42 _index.finishToken.call(void 0, _types.TokenType.jsxText);
43 return;
44
45 default:
46 _base.state.pos++;
47 }
48 }
49}
50
51function jsxReadString(quote) {
52 _base.state.pos++;
53 for (;;) {
54 if (_base.state.pos >= _base.input.length) {
55 _util.unexpected.call(void 0, "Unterminated string constant");
56 return;
57 }
58
59 const ch = _base.input.charCodeAt(_base.state.pos);
60 if (ch === quote) {
61 _base.state.pos++;
62 break;
63 }
64 _base.state.pos++;
65 }
66 _index.finishToken.call(void 0, _types.TokenType.string);
67}
68
69// Read a JSX identifier (valid tag or attribute name).
70//
71// Optimized version since JSX identifiers can't contain
72// escape characters and so can be read as single slice.
73// Also assumes that first character was already checked
74// by isIdentifierStart in readToken.
75
76function jsxReadWord() {
77 let ch;
78 do {
79 if (_base.state.pos > _base.input.length) {
80 _util.unexpected.call(void 0, "Unexpectedly reached the end of input.");
81 return;
82 }
83 ch = _base.input.charCodeAt(++_base.state.pos);
84 } while (_identifier.IS_IDENTIFIER_CHAR[ch] || ch === _charcodes.charCodes.dash);
85 _index.finishToken.call(void 0, _types.TokenType.jsxName);
86}
87
88// Parse next token as JSX identifier
89function jsxParseIdentifier() {
90 nextJSXTagToken();
91}
92
93// Parse namespaced identifier.
94function jsxParseNamespacedName(identifierRole) {
95 jsxParseIdentifier();
96 if (!_index.eat.call(void 0, _types.TokenType.colon)) {
97 // Plain identifier, so this is an access.
98 _base.state.tokens[_base.state.tokens.length - 1].identifierRole = identifierRole;
99 return;
100 }
101 // Process the second half of the namespaced name.
102 jsxParseIdentifier();
103}
104
105// Parses element name in any form - namespaced, member
106// or single identifier.
107function jsxParseElementName() {
108 jsxParseNamespacedName(_index.IdentifierRole.Access);
109 while (_index.match.call(void 0, _types.TokenType.dot)) {
110 nextJSXTagToken();
111 jsxParseIdentifier();
112 }
113}
114
115// Parses any type of JSX attribute value.
116function jsxParseAttributeValue() {
117 switch (_base.state.type) {
118 case _types.TokenType.braceL:
119 jsxParseExpressionContainer();
120 nextJSXTagToken();
121 return;
122
123 case _types.TokenType.jsxTagStart:
124 jsxParseElement();
125 nextJSXTagToken();
126 return;
127
128 case _types.TokenType.string:
129 nextJSXTagToken();
130 return;
131
132 default:
133 _util.unexpected.call(void 0, "JSX value should be either an expression or a quoted JSX text");
134 }
135}
136
137function jsxParseEmptyExpression() {
138 // Do nothing.
139}
140
141// Parse JSX spread child
142function jsxParseSpreadChild() {
143 _util.expect.call(void 0, _types.TokenType.braceL);
144 _util.expect.call(void 0, _types.TokenType.ellipsis);
145 _expression.parseExpression.call(void 0, );
146 _util.expect.call(void 0, _types.TokenType.braceR);
147}
148
149// Parses JSX expression enclosed into curly brackets.
150// Does not parse the last token.
151function jsxParseExpressionContainer() {
152 _index.next.call(void 0, );
153 if (_index.match.call(void 0, _types.TokenType.braceR)) {
154 jsxParseEmptyExpression();
155 } else {
156 _expression.parseExpression.call(void 0, );
157 }
158}
159
160// Parses following JSX attribute name-value pair.
161function jsxParseAttribute() {
162 if (_index.eat.call(void 0, _types.TokenType.braceL)) {
163 _util.expect.call(void 0, _types.TokenType.ellipsis);
164 _expression.parseMaybeAssign.call(void 0, );
165 // }
166 nextJSXTagToken();
167 return;
168 }
169 jsxParseNamespacedName(_index.IdentifierRole.ObjectKey);
170 if (_index.match.call(void 0, _types.TokenType.eq)) {
171 nextJSXTagToken();
172 jsxParseAttributeValue();
173 }
174}
175
176// Parses JSX opening tag starting after "<".
177// Returns true if the tag was self-closing.
178// Does not parse the last token.
179function jsxParseOpeningElement() {
180 if (_index.match.call(void 0, _types.TokenType.jsxTagEnd)) {
181 // This is an open-fragment.
182 return false;
183 }
184 jsxParseElementName();
185 if (_base.isTypeScriptEnabled) {
186 _typescript.tsTryParseJSXTypeArgument.call(void 0, );
187 }
188 while (!_index.match.call(void 0, _types.TokenType.slash) && !_index.match.call(void 0, _types.TokenType.jsxTagEnd) && !_base.state.error) {
189 jsxParseAttribute();
190 }
191 const isSelfClosing = _index.match.call(void 0, _types.TokenType.slash);
192 if (isSelfClosing) {
193 // /
194 nextJSXTagToken();
195 }
196 return isSelfClosing;
197}
198
199// Parses JSX closing tag starting after "</".
200// Does not parse the last token.
201function jsxParseClosingElement() {
202 if (_index.match.call(void 0, _types.TokenType.jsxTagEnd)) {
203 // Fragment syntax, so we immediately have a tag end.
204 return;
205 }
206 jsxParseElementName();
207}
208
209// Parses entire JSX element, including its opening tag
210// (starting after "<"), attributes, contents and closing tag.
211// Does not parse the last token.
212function jsxParseElementAt() {
213 const isSelfClosing = jsxParseOpeningElement();
214 if (!isSelfClosing) {
215 nextJSXExprToken();
216 while (true) {
217 switch (_base.state.type) {
218 case _types.TokenType.jsxTagStart:
219 nextJSXTagToken();
220 if (_index.match.call(void 0, _types.TokenType.slash)) {
221 nextJSXTagToken();
222 jsxParseClosingElement();
223 return;
224 }
225 jsxParseElementAt();
226 nextJSXExprToken();
227 break;
228
229 case _types.TokenType.jsxText:
230 nextJSXExprToken();
231 break;
232
233 case _types.TokenType.braceL:
234 if (_index.lookaheadType.call(void 0, ) === _types.TokenType.ellipsis) {
235 jsxParseSpreadChild();
236 } else {
237 jsxParseExpressionContainer();
238 nextJSXExprToken();
239 }
240
241 break;
242
243 // istanbul ignore next - should never happen
244 default:
245 _util.unexpected.call(void 0, );
246 return;
247 }
248 }
249 }
250}
251
252// Parses entire JSX element from current position.
253// Does not parse the last token.
254 function jsxParseElement() {
255 nextJSXTagToken();
256 jsxParseElementAt();
257} exports.jsxParseElement = jsxParseElement;
258
259// ==================================
260// Overrides
261// ==================================
262
263 function nextJSXTagToken() {
264 _base.state.tokens.push(new (0, _index.Token)());
265 _index.skipSpace.call(void 0, );
266 _base.state.start = _base.state.pos;
267 const code = _base.input.charCodeAt(_base.state.pos);
268
269 if (_identifier.IS_IDENTIFIER_START[code]) {
270 jsxReadWord();
271 } else if (code === _charcodes.charCodes.quotationMark || code === _charcodes.charCodes.apostrophe) {
272 jsxReadString(code);
273 } else {
274 // The following tokens are just one character each.
275 ++_base.state.pos;
276 switch (code) {
277 case _charcodes.charCodes.greaterThan:
278 _index.finishToken.call(void 0, _types.TokenType.jsxTagEnd);
279 break;
280 case _charcodes.charCodes.lessThan:
281 _index.finishToken.call(void 0, _types.TokenType.jsxTagStart);
282 break;
283 case _charcodes.charCodes.slash:
284 _index.finishToken.call(void 0, _types.TokenType.slash);
285 break;
286 case _charcodes.charCodes.equalsTo:
287 _index.finishToken.call(void 0, _types.TokenType.eq);
288 break;
289 case _charcodes.charCodes.leftCurlyBrace:
290 _index.finishToken.call(void 0, _types.TokenType.braceL);
291 break;
292 case _charcodes.charCodes.dot:
293 _index.finishToken.call(void 0, _types.TokenType.dot);
294 break;
295 case _charcodes.charCodes.colon:
296 _index.finishToken.call(void 0, _types.TokenType.colon);
297 break;
298 default:
299 _util.unexpected.call(void 0, );
300 }
301 }
302} exports.nextJSXTagToken = nextJSXTagToken;
303
304function nextJSXExprToken() {
305 _base.state.tokens.push(new (0, _index.Token)());
306 _base.state.start = _base.state.pos;
307 jsxReadToken();
308}