Parses the parameters of a `for` loop block.
( block: html.Block, errors: ParseError[], bindingParser: BindingParser, )
| 366 | |
| 367 | /** Parses the parameters of a `for` loop block. */ |
| 368 | function parseForLoopParameters( |
| 369 | block: html.Block, |
| 370 | errors: ParseError[], |
| 371 | bindingParser: BindingParser, |
| 372 | ) { |
| 373 | if (block.parameters.length === 0) { |
| 374 | errors.push(new ParseError(block.startSourceSpan, '@for loop does not have an expression')); |
| 375 | return null; |
| 376 | } |
| 377 | |
| 378 | const [expressionParam, ...secondaryParams] = block.parameters; |
| 379 | const match = stripOptionalParentheses(expressionParam, errors)?.match( |
| 380 | FOR_LOOP_EXPRESSION_PATTERN, |
| 381 | ); |
| 382 | |
| 383 | if (!match || match[2].trim().length === 0) { |
| 384 | errors.push( |
| 385 | new ParseError( |
| 386 | expressionParam.sourceSpan, |
| 387 | 'Cannot parse expression. @for loop expression must match the pattern "<identifier> of <expression>"', |
| 388 | ), |
| 389 | ); |
| 390 | return null; |
| 391 | } |
| 392 | |
| 393 | const [, itemName, rawExpression] = match; |
| 394 | if (ALLOWED_FOR_LOOP_LET_VARIABLES.has(itemName)) { |
| 395 | errors.push( |
| 396 | new ParseError( |
| 397 | expressionParam.sourceSpan, |
| 398 | `@for loop item name cannot be one of ${Array.from(ALLOWED_FOR_LOOP_LET_VARIABLES).join( |
| 399 | ', ', |
| 400 | )}.`, |
| 401 | ), |
| 402 | ); |
| 403 | } |
| 404 | |
| 405 | // `expressionParam.expression` contains the variable declaration and the expression of the |
| 406 | // for...of statement, i.e. 'user of users' The variable of a ForOfStatement is _only_ the "const |
| 407 | // user" part and does not include "of x". |
| 408 | const variableName = expressionParam.expression.split(' ')[0]; |
| 409 | const variableSpan = new ParseSourceSpan( |
| 410 | expressionParam.sourceSpan.start, |
| 411 | expressionParam.sourceSpan.start.moveBy(variableName.length), |
| 412 | ); |
| 413 | const result = { |
| 414 | itemName: new t.Variable(itemName, '$implicit', variableSpan, variableSpan), |
| 415 | trackBy: null as {expression: ASTWithSource; keywordSpan: ParseSourceSpan} | null, |
| 416 | expression: parseBlockParameterToBinding(expressionParam, bindingParser, rawExpression), |
| 417 | context: Array.from(ALLOWED_FOR_LOOP_LET_VARIABLES, (variableName) => { |
| 418 | // Give ambiently-available context variables empty spans at the end of |
| 419 | // the start of the `for` block, since they are not explicitly defined. |
| 420 | const emptySpanAfterForBlockStart = new ParseSourceSpan( |
| 421 | block.startSourceSpan.end, |
| 422 | block.startSourceSpan.end, |
| 423 | ); |
| 424 | return new t.Variable( |
| 425 | variableName, |
no test coverage detected
searching dependent graphs…