Repository: swc-project/swc
File: crates/swc_ecma_parser/src/lexer/state.rs (Rust)

Code before:
    /// resolve the jsx entity, which requires a dedicate string allocation.
    fn scan_jsx_token_with_jsx_entity(&mut self) -> LexResult<Token> {
        let mut value = String::new();
        let mut chunk_start = self.input.cur_pos();

        while let Some(byte) = self.input.cur_as_char() {
            match byte {
                '>' => {
                    self.bump(1);
                    self.emit_error(
                        self.input().cur_pos(),
                        SyntaxError::UnexpectedTokenWithSuggestions {
                            candidate_list: vec!["`{'>'}`", "`&gt;`"],
                        },
                    );
                }
                '}' => {
                    self.bump(1);
                    self.emit_error(
                        self.input().cur_pos(),
                        SyntaxError::UnexpectedTokenWithSuggestions {
                            candidate_list: vec!["`{'}'}`", "`&rbrace;`"],
                        },
                    );
                }
                '&' => {
                    // Push the string before the `&` to the result
                    let s = unsafe {
                        // Safety: We already checked for the range
                        self.input_slice_str(chunk_start, self.cur_pos())
                    };
                    value.push_str(s);

                    // Read the jsx entity and update the start of chunk
                    if let Ok(jsx_entity) = self.read_jsx_entity() {
                        value.push(jsx_entity.0);
                        chunk_start = self.input.cur_pos();
                    }
                }
                '<' | '{' => break,
                c => {
                    self.bump(c.len_utf8());
                }
            }
        }

        let s = unsafe {
            // Safety: start and end are valid position because we got them from
            // `self.input`
            self.input_slice_str(chunk_start, self.cur_pos())
        };

Review comment (bug):
The error position is incorrect. The code bumps past the '}' character before reporting the error, which means the error will be reported at the position AFTER the '}' instead of AT the '}'. This is inconsistent with the fast path implementation (lines 438-446) where the error is correctly reported at the position of the matched byte. The error reporting should happen before bumping, or the error position should be calculated as the position before the bump.

Code after:
    /// resolve the jsx entity, which requires a dedicated string allocation.
    fn scan_jsx_token_with_jsx_entity(&mut self) -> LexResult<Token> {
        let mut value = String::new();
        let mut chunk_start = self.input.cur_pos();

        while let Some(ch) = self.input.cur_as_char() {
            match ch {
                '>' => {
                    let error_pos = self.input().cur_pos();
                    self.bump(1);
                    self.emit_error(
                        error_pos,
                        SyntaxError::UnexpectedTokenWithSuggestions {
                            candidate_list: vec!["`{'>'}`", "`&gt;`"],
                        },
                    );
                }
                '}' => {
                    let error_pos = self.input().cur_pos();
                    self.bump(1);
                    self.emit_error(
                        error_pos,
                        SyntaxError::UnexpectedTokenWithSuggestions {
                            candidate_list: vec!["`{'}'}`", "`&rbrace;`"],
                        },
                    );
                }
                '&' => {
                    // Push the string before the `&` to the result
                    let s = unsafe {
                        // Safety: We already checked for the range
                        self.input_slice_str(chunk_start, self.cur_pos())
                    };
                    value.push_str(s);

                    // Read the jsx entity and update the start of chunk
                    if let Ok(jsx_entity) = self.read_jsx_entity() {
                        value.push(jsx_entity.0);
                        chunk_start = self.input.cur_pos();
                    }
                }
                '<' | '{' => break,
                c => {
                    self.bump(c.len_utf8());
                }
            }
        }

        let s = unsafe {
            // Safety: start and end are valid position because we got them from
            // `self.input`