ezno_parser/
property_key.rs

1use crate::{
2	derive_ASTNode,
3	visiting::{Chain, VisitOptions, Visitable},
4	Quoted, TSXToken,
5};
6use get_field_by_type::GetFieldByType;
7use source_map::Span;
8use std::fmt::Debug;
9use temporary_annex::Annex;
10use tokenizer_lib::{sized_tokens::TokenReaderWithTokenEnds, Token, TokenReader};
11
12use crate::{
13	errors::parse_lexing_error, number::NumberRepresentation, tokens::token_as_identifier, ASTNode,
14	Expression, ParseOptions, ParseResult,
15};
16
17pub trait PropertyKeyKind: Debug + PartialEq + Eq + Clone + Sized + Send + Sync + 'static {
18	fn parse_identifier(
19		first: Token<TSXToken, crate::TokenStart>,
20		reader: &mut impl TokenReader<TSXToken, crate::TokenStart>,
21	) -> ParseResult<(String, Span, Self)>;
22
23	fn is_private(&self) -> bool;
24
25	/// TODO temp
26	fn new_public() -> Self;
27}
28
29#[derive(Debug, Clone, PartialEq, Eq)]
30#[apply(derive_ASTNode)]
31pub struct AlwaysPublic;
32
33// #[cfg_attr(target_family = "wasm", wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section))]
34#[allow(dead_code)]
35// const TYPES_ALWAYS_PUBLIC: &str = r"
36// 	export type AlwaysPublic = false;
37// ";
38
39impl PropertyKeyKind for AlwaysPublic {
40	fn parse_identifier(
41		first: Token<TSXToken, crate::TokenStart>,
42		_reader: &mut impl TokenReader<TSXToken, crate::TokenStart>,
43	) -> ParseResult<(String, Span, Self)> {
44		token_as_identifier(first, "property key")
45			.map(|(name, position)| (name, position, Self::new_public()))
46	}
47
48	fn is_private(&self) -> bool {
49		false
50	}
51
52	fn new_public() -> Self {
53		AlwaysPublic
54	}
55}
56
57#[derive(Debug, Clone, PartialEq, Eq)]
58#[apply(derive_ASTNode)]
59pub enum PublicOrPrivate {
60	Public,
61	Private,
62}
63
64// #[cfg_attr(target_family = "wasm", wasm_bindgen::prelude::wasm_bindgen(typescript_custom_section))]
65#[allow(dead_code)]
66// const TYPES_PUBLIC_OR_PRIVATE: &str = r"
67// 	export type PublicOrPrivate = boolean;
68// ";
69
70impl PropertyKeyKind for PublicOrPrivate {
71	fn parse_identifier(
72		first: Token<TSXToken, crate::TokenStart>,
73		reader: &mut impl TokenReader<TSXToken, crate::TokenStart>,
74	) -> ParseResult<(String, Span, Self)> {
75		if matches!(first.0, TSXToken::HashTag) {
76			token_as_identifier(reader.next().ok_or_else(parse_lexing_error)?, "property key")
77				.map(|(name, position)| (name, position, Self::Private))
78		} else {
79			token_as_identifier(first, "property key")
80				.map(|(name, position)| (name, position, Self::Public))
81		}
82	}
83
84	fn is_private(&self) -> bool {
85		matches!(self, Self::Private)
86	}
87
88	fn new_public() -> Self {
89		Self::Public
90	}
91}
92
93/// A key for a member in a class or object literal
94#[apply(derive_ASTNode)]
95#[derive(Debug, PartialEq, Eq, Clone, get_field_by_type::GetFieldByType)]
96#[get_field_by_type_target(Span)]
97pub enum PropertyKey<T: PropertyKeyKind> {
98	Identifier(String, Span, T),
99	StringLiteral(String, Quoted, Span),
100	NumberLiteral(NumberRepresentation, Span),
101	/// Includes anything in the `[...]` maybe a symbol
102	Computed(Box<Expression>, Span),
103}
104
105impl<U: PropertyKeyKind> PropertyKey<U> {
106	pub fn is_private(&self) -> bool {
107		match self {
108			PropertyKey::Identifier(_, _, p) => U::is_private(p),
109			_ => false,
110		}
111	}
112}
113
114impl<U: PropertyKeyKind> PartialEq<str> for PropertyKey<U> {
115	fn eq(&self, other: &str) -> bool {
116		match self {
117			PropertyKey::Identifier(name, _, _) | PropertyKey::StringLiteral(name, _, _) => {
118				name == other
119			}
120			PropertyKey::NumberLiteral(_, _) | PropertyKey::Computed(_, _) => false,
121		}
122	}
123}
124
125impl<U: PropertyKeyKind> ASTNode for PropertyKey<U> {
126	fn get_position(&self) -> Span {
127		*self.get()
128	}
129
130	fn from_reader(
131		reader: &mut impl TokenReader<TSXToken, crate::TokenStart>,
132		state: &mut crate::ParsingState,
133		options: &ParseOptions,
134	) -> ParseResult<Self> {
135		match reader.next().ok_or_else(parse_lexing_error)? {
136			Token(TSXToken::StringLiteral(content, quoted), start) => {
137				let position = start.with_length(content.len() + 2);
138				Ok(Self::StringLiteral(content, quoted, position))
139			}
140			Token(TSXToken::NumberLiteral(value), start) => {
141				let position = start.with_length(value.len());
142				match value.parse::<NumberRepresentation>() {
143					Ok(number) => Ok(Self::NumberLiteral(number, position)),
144					Err(_) => {
145						// TODO this should never happen
146						Err(crate::ParseError::new(
147							crate::ParseErrors::InvalidNumberLiteral,
148							position,
149						))
150					}
151				}
152			}
153			Token(TSXToken::OpenBracket, start) => {
154				let expression = Expression::from_reader(reader, state, options)?;
155				let end = reader.expect_next_get_end(TSXToken::CloseBracket)?;
156				Ok(Self::Computed(Box::new(expression), start.union(end)))
157			}
158			token => {
159				if token.0.is_comment() {
160					// TODO could add marker?
161					Self::from_reader(reader, state, options)
162				} else {
163					let (name, position, private) = U::parse_identifier(token, reader)?;
164					Ok(Self::Identifier(name, position, private))
165				}
166			}
167		}
168	}
169
170	fn to_string_from_buffer<T: source_map::ToString>(
171		&self,
172		buf: &mut T,
173		options: &crate::ToStringOptions,
174		local: crate::LocalToStringInformation,
175	) {
176		match self {
177			Self::Identifier(ident, _pos, _) => buf.push_str(ident.as_str()),
178			Self::NumberLiteral(number, _) => buf.push_str(&number.to_string()),
179			Self::StringLiteral(string, quoted, _) => {
180				buf.push(quoted.as_char());
181				buf.push_str(string.as_str());
182				buf.push(quoted.as_char());
183			}
184			Self::Computed(expression, _) => {
185				buf.push('[');
186				expression.to_string_from_buffer(buf, options, local);
187				buf.push(']');
188			}
189		}
190	}
191}
192
193// TODO visit expression?
194impl Visitable for PropertyKey<PublicOrPrivate> {
195	fn visit<TData>(
196		&self,
197		visitors: &mut (impl crate::VisitorReceiver<TData> + ?Sized),
198		data: &mut TData,
199		_options: &VisitOptions,
200		chain: &mut Annex<Chain>,
201	) {
202		visitors.visit_variable(
203			&crate::visiting::ImmutableVariableOrProperty::ClassPropertyKey(self),
204			data,
205			chain,
206		);
207	}
208
209	fn visit_mut<TData>(
210		&mut self,
211		visitors: &mut (impl crate::VisitorMutReceiver<TData> + ?Sized),
212		data: &mut TData,
213		_options: &VisitOptions,
214		chain: &mut Annex<Chain>,
215	) {
216		visitors.visit_variable_mut(
217			&mut crate::visiting::MutableVariableOrProperty::ClassPropertyKey(self),
218			data,
219			chain,
220		);
221	}
222}
223
224impl Visitable for PropertyKey<AlwaysPublic> {
225	fn visit<TData>(
226		&self,
227		visitors: &mut (impl crate::VisitorReceiver<TData> + ?Sized),
228		data: &mut TData,
229		_options: &VisitOptions,
230		chain: &mut Annex<Chain>,
231	) {
232		visitors.visit_variable(
233			&crate::visiting::ImmutableVariableOrProperty::ObjectPropertyKey(self),
234			data,
235			chain,
236		);
237	}
238
239	fn visit_mut<TData>(
240		&mut self,
241		visitors: &mut (impl crate::VisitorMutReceiver<TData> + ?Sized),
242		data: &mut TData,
243		_options: &VisitOptions,
244		chain: &mut Annex<Chain>,
245	) {
246		visitors.visit_variable_mut(
247			&mut crate::visiting::MutableVariableOrProperty::ObjectPropertyKey(self),
248			data,
249			chain,
250		);
251	}
252}