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
unsafe-mutation-docs
Rich Harris 5 days ago committed by GitHub
parent 8201d7ad8b
commit 08a9d123e8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -3,7 +3,6 @@
import { isIdentifierStart, isIdentifierChar } from 'acorn'; import { isIdentifierStart, isIdentifierChar } from 'acorn';
import fragment from './state/fragment.js'; import fragment from './state/fragment.js';
import { regex_whitespace } from '../patterns.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 * as e from '../../errors.js';
import { create_fragment } from './utils/create.js'; import { create_fragment } from './utils/create.js';
import read_options from './read/options.js'; import read_options from './read/options.js';
@ -230,13 +229,13 @@ export class Parser {
let i = this.index; 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; if (!isIdentifierStart(code, true)) return null;
i += code <= 0xffff ? 1 : 2; i += code <= 0xffff ? 1 : 2;
while (i < this.template.length) { 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; if (!isIdentifierChar(code, true)) break;
i += code <= 0xffff ? 1 : 2; i += code <= 0xffff ? 1 : 2;

@ -1,15 +1,7 @@
/** @import { Location } from 'locate-character' */ /** @import { Location } from 'locate-character' */
/** @import { Pattern } from 'estree' */ /** @import { Pattern } from 'estree' */
/** @import { Parser } from '../index.js' */ /** @import { Parser } from '../index.js' */
// @ts-expect-error acorn type definitions are borked in the release we use import { is_bracket_open, is_bracket_close, get_bracket_close } from '../utils/bracket.js';
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 { parse_expression_at } from '../acorn.js'; import { parse_expression_at } from '../acorn.js';
import { regex_not_newline_characters } from '../../patterns.js'; import { regex_not_newline_characters } from '../../patterns.js';
import * as e from '../../../errors.js'; import * as e from '../../../errors.js';
@ -23,9 +15,9 @@ export default function read_pattern(parser) {
const start = parser.index; const start = parser.index;
let i = parser.index; let i = parser.index;
const code = full_char_code_at(parser.template, i); const name = parser.read_identifier();
if (isIdentifierStart(code, true)) {
const name = /** @type {string} */ (parser.read_identifier()); if (name !== null) {
const annotation = read_type_annotation(parser); const annotation = read_type_annotation(parser);
return { 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); e.expected_pattern(i);
} }
const bracket_stack = [code]; /** @type {string[]} */
i += code <= 0xffff ? 1 : 2; const bracket_stack = [];
while (i < parser.template.length) { while (i < parser.template.length) {
const code = full_char_code_at(parser.template, i); const char = parser.template[i];
if (is_bracket_open(code)) {
bracket_stack.push(code); if (is_bracket_open(char)) {
} else if (is_bracket_close(code)) { bracket_stack.push(char);
const popped = /** @type {number} */ (bracket_stack.pop()); } else if (is_bracket_close(char)) {
if (!is_bracket_pair(popped, code)) { const popped = /** @type {string} */ (bracket_stack.pop());
e.expected_token(i, String.fromCharCode(/** @type {number} */ (get_bracket_close(popped)))); const expected = /** @type {string} */ (get_bracket_close(popped));
if (char !== expected) {
e.expected_token(i, expected);
} }
if (bracket_stack.length === 0) { if (bracket_stack.length === 0) {
i += code <= 0xffff ? 1 : 2; i += 1;
break; break;
} }
} }
i += code <= 0xffff ? 1 : 2; i += 1;
} }
parser.index = i; parser.index = i;

@ -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); /** @param {string} char */
const SQUARE_BRACKET_CLOSE = ']'.charCodeAt(0); export function is_bracket_open(char) {
const CURLY_BRACKET_OPEN = '{'.charCodeAt(0); return char === SQUARE_BRACKET_OPEN || char === CURLY_BRACKET_OPEN;
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 {number} code */ /** @param {string} char */
export function is_bracket_close(code) { export function is_bracket_close(char) {
return code === SQUARE_BRACKET_CLOSE || code === CURLY_BRACKET_CLOSE; return char === SQUARE_BRACKET_CLOSE || char === CURLY_BRACKET_CLOSE;
} }
/** /** @param {string} open */
* @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 */
export function get_bracket_close(open) { export function get_bracket_close(open) {
if (open === SQUARE_BRACKET_OPEN) { if (open === SQUARE_BRACKET_OPEN) {
return SQUARE_BRACKET_CLOSE; return SQUARE_BRACKET_CLOSE;
} }
if (open === CURLY_BRACKET_OPEN) { if (open === CURLY_BRACKET_OPEN) {
return CURLY_BRACKET_CLOSE; return CURLY_BRACKET_CLOSE;
} }
if (open === PARENTHESES_OPEN) { if (open === PARENTHESES_OPEN) {
return PARENTHESES_CLOSE; 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. * @returns {number | undefined} The index of the closing bracket, or undefined if not found.
*/ */
export function find_matching_bracket(template, index, open) { export function find_matching_bracket(template, index, open) {
const open_code = full_char_code_at(open, 0); const close = get_bracket_close(open);
const close_code = get_bracket_close(open_code);
let brackets = 1; let brackets = 1;
let i = index; let i = index;
while (brackets > 0 && i < template.length) { while (brackets > 0 && i < template.length) {
@ -159,10 +147,10 @@ export function find_matching_bracket(template, index, open) {
continue; continue;
} }
default: { default: {
const code = full_char_code_at(template, i); const char = template[i];
if (code === open_code) { if (char === open) {
brackets++; brackets++;
} else if (code === close_code) { } else if (char === close) {
brackets--; brackets--;
} }
if (brackets === 0) { if (brackets === 0) {

@ -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;
}
Loading…
Cancel
Save