From 08a9d123e81725189e727b18b1f99662ec2a48c8 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 7 Jan 2025 09:01:44 +0000 Subject: [PATCH] chore: use codePointAt instead of implementing it ourselves (#14923) seems to be some sort of codePointAt polyfill from ancient times before that was available on String.prototype --- .../src/compiler/phases/1-parse/index.js | 5 +- .../compiler/phases/1-parse/read/context.js | 44 ++++++++-------- .../compiler/phases/1-parse/utils/bracket.js | 50 +++++++------------ .../phases/1-parse/utils/full_char_code_at.js | 15 ------ 4 files changed, 41 insertions(+), 73 deletions(-) delete mode 100644 packages/svelte/src/compiler/phases/1-parse/utils/full_char_code_at.js diff --git a/packages/svelte/src/compiler/phases/1-parse/index.js b/packages/svelte/src/compiler/phases/1-parse/index.js index 390919f5cd..6cc5b58aa6 100644 --- a/packages/svelte/src/compiler/phases/1-parse/index.js +++ b/packages/svelte/src/compiler/phases/1-parse/index.js @@ -3,7 +3,6 @@ import { isIdentifierStart, isIdentifierChar } from 'acorn'; import fragment from './state/fragment.js'; import { regex_whitespace } from '../patterns.js'; -import full_char_code_at from './utils/full_char_code_at.js'; import * as e from '../../errors.js'; import { create_fragment } from './utils/create.js'; import read_options from './read/options.js'; @@ -230,13 +229,13 @@ export class Parser { let i = this.index; - const code = full_char_code_at(this.template, i); + const code = /** @type {number} */ (this.template.codePointAt(i)); if (!isIdentifierStart(code, true)) return null; i += code <= 0xffff ? 1 : 2; while (i < this.template.length) { - const code = full_char_code_at(this.template, i); + const code = /** @type {number} */ (this.template.codePointAt(i)); if (!isIdentifierChar(code, true)) break; i += code <= 0xffff ? 1 : 2; diff --git a/packages/svelte/src/compiler/phases/1-parse/read/context.js b/packages/svelte/src/compiler/phases/1-parse/read/context.js index e408b5024f..e206701500 100644 --- a/packages/svelte/src/compiler/phases/1-parse/read/context.js +++ b/packages/svelte/src/compiler/phases/1-parse/read/context.js @@ -1,15 +1,7 @@ /** @import { Location } from 'locate-character' */ /** @import { Pattern } from 'estree' */ /** @import { Parser } from '../index.js' */ -// @ts-expect-error acorn type definitions are borked in the release we use -import { isIdentifierStart } from 'acorn'; -import full_char_code_at from '../utils/full_char_code_at.js'; -import { - is_bracket_open, - is_bracket_close, - is_bracket_pair, - get_bracket_close -} from '../utils/bracket.js'; +import { is_bracket_open, is_bracket_close, get_bracket_close } from '../utils/bracket.js'; import { parse_expression_at } from '../acorn.js'; import { regex_not_newline_characters } from '../../patterns.js'; import * as e from '../../../errors.js'; @@ -23,9 +15,9 @@ export default function read_pattern(parser) { const start = parser.index; let i = parser.index; - const code = full_char_code_at(parser.template, i); - if (isIdentifierStart(code, true)) { - const name = /** @type {string} */ (parser.read_identifier()); + const name = parser.read_identifier(); + + if (name !== null) { const annotation = read_type_annotation(parser); return { @@ -41,28 +33,32 @@ export default function read_pattern(parser) { }; } - if (!is_bracket_open(code)) { + if (!is_bracket_open(parser.template[i])) { e.expected_pattern(i); } - const bracket_stack = [code]; - i += code <= 0xffff ? 1 : 2; + /** @type {string[]} */ + const bracket_stack = []; while (i < parser.template.length) { - const code = full_char_code_at(parser.template, i); - if (is_bracket_open(code)) { - bracket_stack.push(code); - } else if (is_bracket_close(code)) { - const popped = /** @type {number} */ (bracket_stack.pop()); - if (!is_bracket_pair(popped, code)) { - e.expected_token(i, String.fromCharCode(/** @type {number} */ (get_bracket_close(popped)))); + const char = parser.template[i]; + + if (is_bracket_open(char)) { + bracket_stack.push(char); + } else if (is_bracket_close(char)) { + const popped = /** @type {string} */ (bracket_stack.pop()); + const expected = /** @type {string} */ (get_bracket_close(popped)); + + if (char !== expected) { + e.expected_token(i, expected); } + if (bracket_stack.length === 0) { - i += code <= 0xffff ? 1 : 2; + i += 1; break; } } - i += code <= 0xffff ? 1 : 2; + i += 1; } parser.index = i; diff --git a/packages/svelte/src/compiler/phases/1-parse/utils/bracket.js b/packages/svelte/src/compiler/phases/1-parse/utils/bracket.js index e7576af955..b7c8cb43cd 100644 --- a/packages/svelte/src/compiler/phases/1-parse/utils/bracket.js +++ b/packages/svelte/src/compiler/phases/1-parse/utils/bracket.js @@ -1,41 +1,30 @@ -import full_char_code_at from './full_char_code_at.js'; +const SQUARE_BRACKET_OPEN = '['; +const SQUARE_BRACKET_CLOSE = ']'; +const CURLY_BRACKET_OPEN = '{'; +const CURLY_BRACKET_CLOSE = '}'; +const PARENTHESES_OPEN = '('; +const PARENTHESES_CLOSE = ')'; -const SQUARE_BRACKET_OPEN = '['.charCodeAt(0); -const SQUARE_BRACKET_CLOSE = ']'.charCodeAt(0); -const CURLY_BRACKET_OPEN = '{'.charCodeAt(0); -const CURLY_BRACKET_CLOSE = '}'.charCodeAt(0); -const PARENTHESES_OPEN = '('.charCodeAt(0); -const PARENTHESES_CLOSE = ')'.charCodeAt(0); - -/** @param {number} code */ -export function is_bracket_open(code) { - return code === SQUARE_BRACKET_OPEN || code === CURLY_BRACKET_OPEN; +/** @param {string} char */ +export function is_bracket_open(char) { + return char === SQUARE_BRACKET_OPEN || char === CURLY_BRACKET_OPEN; } -/** @param {number} code */ -export function is_bracket_close(code) { - return code === SQUARE_BRACKET_CLOSE || code === CURLY_BRACKET_CLOSE; +/** @param {string} char */ +export function is_bracket_close(char) { + return char === SQUARE_BRACKET_CLOSE || char === CURLY_BRACKET_CLOSE; } -/** - * @param {number} open - * @param {number} close - */ -export function is_bracket_pair(open, close) { - return ( - (open === SQUARE_BRACKET_OPEN && close === SQUARE_BRACKET_CLOSE) || - (open === CURLY_BRACKET_OPEN && close === CURLY_BRACKET_CLOSE) - ); -} - -/** @param {number} open */ +/** @param {string} open */ export function get_bracket_close(open) { if (open === SQUARE_BRACKET_OPEN) { return SQUARE_BRACKET_CLOSE; } + if (open === CURLY_BRACKET_OPEN) { return CURLY_BRACKET_CLOSE; } + if (open === PARENTHESES_OPEN) { return PARENTHESES_CLOSE; } @@ -132,8 +121,7 @@ function count_leading_backslashes(string, search_start_index) { * @returns {number | undefined} The index of the closing bracket, or undefined if not found. */ export function find_matching_bracket(template, index, open) { - const open_code = full_char_code_at(open, 0); - const close_code = get_bracket_close(open_code); + const close = get_bracket_close(open); let brackets = 1; let i = index; while (brackets > 0 && i < template.length) { @@ -159,10 +147,10 @@ export function find_matching_bracket(template, index, open) { continue; } default: { - const code = full_char_code_at(template, i); - if (code === open_code) { + const char = template[i]; + if (char === open) { brackets++; - } else if (code === close_code) { + } else if (char === close) { brackets--; } if (brackets === 0) { diff --git a/packages/svelte/src/compiler/phases/1-parse/utils/full_char_code_at.js b/packages/svelte/src/compiler/phases/1-parse/utils/full_char_code_at.js deleted file mode 100644 index 90e6b8def3..0000000000 --- a/packages/svelte/src/compiler/phases/1-parse/utils/full_char_code_at.js +++ /dev/null @@ -1,15 +0,0 @@ -// Adapted from https://github.com/acornjs/acorn/blob/6584815dca7440e00de841d1dad152302fdd7ca5/src/tokenize.js -// Reproduced under MIT License https://github.com/acornjs/acorn/blob/master/LICENSE - -/** - * @param {string} str - * @param {number} i - * @returns {number} - */ -export default function full_char_code_at(str, i) { - const code = str.charCodeAt(i); - if (code <= 0xd7ff || code >= 0xe000) return code; - - const next = str.charCodeAt(i + 1); - return (code << 10) + next - 0x35fdc00; -}