Repository: babel/babel
File: packages/babel-parser/src/parser/expression.ts (TypeScript)

Code before:
      this.raise(Errors.ImportCallNotNewExpression, callee);
    }
  }

  // Parse template expression.

  parseTemplateElement(isTagged: boolean): N.TemplateElement {
    const { start, startLoc, end, value } = this.state;
    const elemStart = start + 1;
    const elem = this.startNodeAt<N.TemplateElement>(
      createPositionWithColumnOffset(startLoc, 1),
    );
    if (value === null) {
      if (!isTagged) {
        this.raise(
          Errors.InvalidEscapeSequenceTemplate,
          // FIXME: Adding 1 is probably wrong.
          createPositionWithColumnOffset(
            this.state.firstInvalidTemplateEscapePos,
            1,
          ),
        );
      }
    }

    const isTail = this.match(tt.templateTail);
    const endOffset = isTail ? -1 : -2;
    const elemEnd = end + endOffset;
    elem.value = {
      raw: this.input
        .slice(
          this.state.offsetToSourcePos(elemStart),
          this.state.offsetToSourcePos(elemEnd),
        )
        .replace(/\r\n?/g, "\n"),
      cooked: value === null ? null : value.slice(1, endOffset),
    };
    elem.tail = isTail;
    this.next();
    const finishedNode = this.finishNode(elem, "TemplateElement");
    this.resetEndLocation(
      finishedNode,
      createPositionWithColumnOffset(this.state.lastTokEndLoc, endOffset),
    );
    return finishedNode;
  }

  // https://tc39.es/ecma262/#prod-TemplateLiteral
  parseTemplate(this: Parser, isTagged: boolean): N.TemplateLiteral {
    const node = this.startNode<N.TemplateLiteral>();
    let curElt = this.parseTemplateElement(isTagged);

Review comment (suggestion):
I would prefer to have a `this.sliceInput(elemStart, elemEnd)` method, which handles this internally.

Code after:
    );
    if (value === null) {
      if (!isTagged) {
        this.raise(
          Errors.InvalidEscapeSequenceTemplate,
          // FIXME: Adding 1 is probably wrong.
          createPositionWithColumnOffset(
            this.state.firstInvalidTemplateEscapePos,
            1,
          ),
        );
      }
    }

    const isTail = this.match(tt.templateTail);
    const endOffset = isTail ? -1 : -2;
    const elemEnd = end + endOffset;
    elem.value = {
      raw: this.input.slice(elemStart, elemEnd).replace(/\r\n?/g, "\n"),
      cooked: value === null ? null : value.slice(1, endOffset),
    };
    elem.tail = isTail;
    this.next();
    const finishedNode = this.finishNode(elem, "TemplateElement");
    this.resetEndLocation(
      finishedNode,
      createPositionWithColumnOffset(this.state.lastTokEndLoc, endOffset),
    );
    return finishedNode;
  }

  // https://tc39.es/ecma262/#prod-TemplateLiteral
  parseTemplate(this: Parser, isTagged: boolean): N.TemplateLiteral {
    const node = this.startNode<N.TemplateLiteral>();
    let curElt = this.parseTemplateElement(isTagged);
    const quasis = [curElt];
    const substitutions = [];
    while (!curElt.tail) {
      substitutions.push(this.parseTemplateSubstitution());
      this.readTemplateContinuation();
      quasis.push((curElt = this.parseTemplateElement(isTagged)));
    }
    // Type cast from (N.Expression[] | N.TsType[]). parseTemplateSubstitution
    // returns consistent results.
    node.expressions = substitutions as N.Expression[] | N.TsType[];
    node.quasis = quasis;
    return this.finishNode(node, "TemplateLiteral");
  }

  // This is overwritten by the TypeScript plugin to parse template types
  parseTemplateSubstitution(this: Parser): N.Expression | N.TsType {