@ -1,150 +1,6 @@
/** @import { Parser } from '../index.js' */
import * as e from '../../../errors.js' ;
/ * *
* @ param { number } num
* @ returns { number } Infinity if { @ link num } is negative , else { @ link num } .
* /
function infinity _if _negative ( num ) {
if ( num < 0 ) {
return Infinity ;
}
return num ;
}
/ * *
* @ param { string } string The string to search .
* @ param { number } search _start _index The index to start searching at .
* @ param { "'" | '"' | '`' } string _start _char The character that started this string .
* @ returns { number } The index of the end of this string expression , or ` Infinity ` if not found .
* /
function find _string _end ( string , search _start _index , string _start _char ) {
let string _to _search ;
if ( string _start _char === '`' ) {
string _to _search = string ;
} else {
// we could slice at the search start index, but this way the index remains valid
string _to _search = string . slice (
0 ,
infinity _if _negative ( string . indexOf ( '\n' , search _start _index ) )
) ;
}
return find _unescaped _char ( string _to _search , search _start _index , string _start _char ) ;
}
/ * *
* @ param { string } string The string to search .
* @ param { number } search _start _index The index to start searching at .
* @ returns { number } The index of the end of this regex expression , or ` Infinity ` if not found .
* /
function find _regex _end ( string , search _start _index ) {
const slash = find _unescaped _char ( string , search _start _index , '/' ) ;
const eol = find _unescaped _char ( string , search _start _index , '\n' ) ;
return slash < eol ? slash : Infinity ;
}
/ * *
*
* @ param { string } string The string to search .
* @ param { number } search _start _index The index to begin the search at .
* @ param { string } char The character to search for .
* @ returns { number } The index of the first unescaped instance of { @ link char } , or ` Infinity ` if not found .
* /
function find _unescaped _char ( string , search _start _index , char ) {
let i = search _start _index ;
while ( true ) {
const found _index = string . indexOf ( char , i ) ;
if ( found _index === - 1 ) {
return Infinity ;
}
if ( count _leading _backslashes ( string , found _index - 1 ) % 2 === 0 ) {
return found _index ;
}
i = found _index + 1 ;
}
}
/ * *
* Count consecutive leading backslashes before { @ link search _start _index } .
*
* @ example
* ` ` ` js
* count _leading _backslashes ( '\\\\\\foo' , 2 ) ; // 3 (the backslashes have to be escaped in the string literal, there are three in reality)
* ` ` `
*
* @ param { string } string The string to search .
* @ param { number } search _start _index The index to begin the search at .
* /
function count _leading _backslashes ( string , search _start _index ) {
let i = search _start _index ;
let count = 0 ;
while ( string [ i ] === '\\' ) {
count ++ ;
i -- ;
}
return count ;
}
/ * *
* Finds the corresponding closing bracket , ignoring brackets found inside comments , strings , or regex expressions .
* @ param { string } template The string to search .
* @ param { number } index The index to begin the search at .
* @ param { string } open The opening bracket ( ex : ` '{' ` will search for ` '}' ` ) .
* @ returns { number | undefined } The index of the closing bracket , or undefined if not found .
* /
export function find _matching _bracket ( template , index , open ) {
const close = default _brackets [ open ] ;
let brackets = 1 ;
let i = index ;
while ( brackets > 0 && i < template . length ) {
const char = template [ i ] ;
switch ( char ) {
case "'" :
case '"' :
case '`' :
i = find _string _end ( template , i + 1 , char ) + 1 ;
continue ;
case '/' : {
const next _char = template [ i + 1 ] ;
if ( ! next _char ) {
// `/` is the last character; advance past it so we don't loop forever
i ++ ;
continue ;
}
if ( next _char === '/' ) {
i = infinity _if _negative ( template . indexOf ( '\n' , i + 1 ) ) + '\n' . length ;
continue ;
}
if ( next _char === '*' ) {
i = infinity _if _negative ( template . indexOf ( '*/' , i + 1 ) ) + '*/' . length ;
continue ;
}
const end = find _regex _end ( template , i + 1 ) + '/' . length ;
if ( end === Infinity ) {
i ++ ;
} else {
i = end ;
}
continue ;
}
default : {
const char = template [ i ] ;
if ( char === open ) {
brackets ++ ;
} else if ( char === close ) {
brackets -- ;
}
if ( brackets === 0 ) {
return i ;
}
i ++ ;
}
}
}
return undefined ;
}
/** @type {Record<string, string>} */
const default _brackets = {
'{' : '}' ,