use crate::TSXToken;
use source_map::Span;
use std::fmt::Debug;
use tokenizer_lib::{sized_tokens::TokenReaderWithTokenEnds, Token, TokenReader};
use crate::{
errors::parse_lexing_error, tokens::token_as_identifier, ASTNode, Expression,
NumberRepresentation, ParseOptions, ParseResult,
};
pub trait PropertyKeyKind: Debug + PartialEq + Eq + Clone {
type Private: Debug + Sync + Send + Clone + PartialEq;
fn parse_ident(
first: Token<TSXToken, crate::TokenStart>,
reader: &mut impl TokenReader<TSXToken, crate::TokenStart>,
) -> ParseResult<(String, Span, Self::Private)>;
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AlwaysPublic;
impl PropertyKeyKind for AlwaysPublic {
type Private = ();
fn parse_ident(
first: Token<TSXToken, crate::TokenStart>,
_reader: &mut impl TokenReader<TSXToken, crate::TokenStart>,
) -> ParseResult<(String, Span, Self::Private)> {
token_as_identifier(first, "property key").map(|(name, position)| (name, position, ()))
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PublicOrPrivate;
impl PropertyKeyKind for PublicOrPrivate {
type Private = bool;
fn parse_ident(
first: Token<TSXToken, crate::TokenStart>,
reader: &mut impl TokenReader<TSXToken, crate::TokenStart>,
) -> ParseResult<(String, Span, Self::Private)> {
if matches!(first.0, TSXToken::HashTag) {
token_as_identifier(reader.next().ok_or_else(parse_lexing_error)?, "property key")
.map(|(name, position)| (name, position, true))
} else {
token_as_identifier(first, "property key")
.map(|(name, position)| (name, position, false))
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
#[cfg_attr(feature = "self-rust-tokenize", derive(self_rust_tokenize::SelfRustTokenize))]
#[cfg_attr(feature = "serde-serialize", derive(serde::Serialize))]
pub enum PropertyKey<T: PropertyKeyKind> {
Ident(String, Span, T::Private),
StringLiteral(String, Span),
NumberLiteral(NumberRepresentation, Span),
Computed(Box<Expression>, Span),
}
impl<U: PropertyKeyKind> PropertyKey<U> {
pub fn get_position(&self) -> &Span {
match self {
PropertyKey::Ident(_, pos, _)
| PropertyKey::StringLiteral(_, pos)
| PropertyKey::NumberLiteral(_, pos)
| PropertyKey::Computed(_, pos) => pos,
}
}
}
impl<U: PropertyKeyKind> PartialEq<str> for PropertyKey<U> {
fn eq(&self, other: &str) -> bool {
match self {
PropertyKey::Ident(name, _, _) | PropertyKey::StringLiteral(name, _) => name == other,
PropertyKey::NumberLiteral(_, _) | PropertyKey::Computed(_, _) => false,
}
}
}
impl<U: PropertyKeyKind + 'static> ASTNode for PropertyKey<U> {
fn get_position(&self) -> &Span {
match self {
PropertyKey::Ident(_, pos, _)
| PropertyKey::StringLiteral(_, pos)
| PropertyKey::NumberLiteral(_, pos)
| PropertyKey::Computed(_, pos) => pos,
}
}
fn from_reader(
reader: &mut impl TokenReader<TSXToken, crate::TokenStart>,
state: &mut crate::ParsingState,
settings: &ParseOptions,
) -> ParseResult<Self> {
match reader.next().ok_or_else(parse_lexing_error)? {
Token(TSXToken::DoubleQuotedStringLiteral(content), start)
| Token(TSXToken::SingleQuotedStringLiteral(content), start) => {
let position = start.with_length(content.len() + 2);
Ok(Self::StringLiteral(content, position))
}
Token(TSXToken::NumberLiteral(value), start) => {
let position = start.with_length(value.len());
Ok(Self::NumberLiteral(value.parse().unwrap(), position))
}
Token(TSXToken::OpenBracket, start) => {
let expression = Expression::from_reader(reader, state, settings)?;
let end = reader.expect_next_get_end(TSXToken::CloseBracket)?;
Ok(Self::Computed(Box::new(expression), start.union(end)))
}
token => {
let (name, position, private) = U::parse_ident(token, reader)?;
Ok(Self::Ident(name, position, private))
}
}
}
fn to_string_from_buffer<T: source_map::ToString>(
&self,
buf: &mut T,
settings: &crate::ToStringOptions,
depth: u8,
) {
match self {
Self::Ident(ident, _pos, _) => buf.push_str(ident.as_str()),
Self::NumberLiteral(number, _) => buf.push_str(&number.to_string()),
Self::StringLiteral(string, _) => {
buf.push('"');
buf.push_str(string.as_str());
buf.push('"');
}
Self::Computed(expression, _) => {
buf.push('[');
expression.to_string_from_buffer(buf, settings, depth);
buf.push(']');
}
}
}
}