ezno_parser/
options.rs

1use super::lexer::LexerOptions;
2
3/// Options to customize parsing
4#[allow(unused)]
5#[derive(Copy, Clone)]
6// TODO: Can be refactored with bit to reduce memory
7#[allow(clippy::struct_excessive_bools)]
8#[cfg_attr(feature = "serde-serialize", derive(serde::Deserialize), serde(default))]
9#[cfg_attr(target_family = "wasm", derive(tsify::Tsify))]
10pub struct ParseOptions {
11	/// Parsing of [JSX](https://facebook.github.io/jsx/) (includes some additions)
12	pub jsx: bool,
13	/// allow type annotations
14	pub type_annotations: bool,
15	/// just definition file
16	pub type_definition_module: bool,
17	/// Allow custom characters in JSX attributes
18	pub special_jsx_attributes: bool,
19	/// Parses decorators on items
20	pub decorators: bool,
21	/// Skip **all** comments from the AST
22	pub comments: Comments,
23	/// See [`crate::extensions::is_expression::IsExpression`]
24	pub is_expressions: bool,
25	/// Allows functions to be prefixed with 'server'
26	pub custom_function_headers: bool,
27	/// TODO temp for seeing how channel performs
28	pub buffer_size: usize,
29	/// Has no effect on WASM. Increase for deeply nested AST structures
30	pub stack_size: Option<usize>,
31	/// Useful for LSP information
32	pub record_keyword_positions: bool,
33	/// For the generator
34	pub interpolation_points: bool,
35	/// Extra
36	pub destructuring_type_annotation: bool,
37	/// Extra
38	pub extra_operators: bool,
39	/// For formatting
40	pub retain_blank_lines: bool,
41	/// For LSP
42	pub partial_syntax: bool,
43	/// JSX with modifications equiv
44	pub top_level_html: bool,
45}
46
47impl ParseOptions {
48	pub(crate) fn get_lex_options(&self) -> LexerOptions {
49		LexerOptions {
50			comments: self.comments,
51			lex_jsx: self.jsx,
52			allow_unsupported_characters_in_jsx_attribute_keys: self.special_jsx_attributes,
53			allow_expressions_in_jsx: true,
54			// allow_expressions_in_jsx: !self.top_level_html,
55			top_level_html: self.top_level_html,
56		}
57	}
58
59	#[must_use]
60	pub fn all_features() -> Self {
61		Self {
62			jsx: true,
63			type_annotations: true,
64			type_definition_module: false,
65			special_jsx_attributes: true,
66			comments: Comments::All,
67			decorators: true,
68			custom_function_headers: true,
69			is_expressions: true,
70			buffer_size: 100,
71			stack_size: None,
72			record_keyword_positions: true,
73			// Only used in the AST-generator
74			interpolation_points: false,
75			partial_syntax: true,
76			destructuring_type_annotation: true,
77			extra_operators: true,
78			retain_blank_lines: true,
79			top_level_html: false,
80		}
81	}
82}
83
84// TODO unsure about some of these defaults, may change in future
85impl Default for ParseOptions {
86	fn default() -> Self {
87		Self {
88			jsx: true,
89			type_annotations: true,
90			type_definition_module: false,
91			special_jsx_attributes: false,
92			comments: Comments::All,
93			decorators: true,
94			custom_function_headers: false,
95			is_expressions: false,
96			buffer_size: 100,
97			stack_size: None,
98			record_keyword_positions: false,
99			interpolation_points: false,
100			partial_syntax: false,
101			destructuring_type_annotation: false,
102			extra_operators: false,
103			retain_blank_lines: false,
104			top_level_html: false,
105		}
106	}
107}
108
109/// Settings for serializing `ASTNodes`
110// TODO: Can be refactored with bit to reduce memory
111#[allow(clippy::struct_excessive_bools)]
112#[cfg_attr(feature = "serde-serialize", derive(serde::Deserialize), serde(default))]
113#[cfg_attr(target_family = "wasm", derive(tsify::Tsify))]
114pub struct ToStringOptions {
115	/// Does not include whitespace minification
116	pub pretty: bool,
117	/// Blocks have trailing semicolons. Has no effect if pretty == false
118	pub trailing_semicolon: bool,
119	/// Single statements get put on the same line as their parent statement
120	pub single_statement_on_new_line: bool,
121	/// Include type annotations (and additional TypeScript) syntax
122	pub include_type_annotations: bool,
123	/// TODO unsure about this
124	pub include_decorators: bool,
125	pub comments: Comments,
126	pub indent_with: String,
127	/// If false, panics if sees JSX
128	pub expect_jsx: bool,
129	/// For partial AST, marker nodes may exist. This allows pretty printing on invalid source
130	/// but should be `false` for builds
131	///
132	/// if `false` and a marker node is found, printing will panic
133	pub expect_markers: bool,
134	/// has no effect under !pretty
135	pub max_line_length: u8,
136}
137
138impl Default for ToStringOptions {
139	fn default() -> Self {
140		ToStringOptions {
141			pretty: true,
142			include_type_annotations: false,
143			single_statement_on_new_line: true,
144			include_decorators: false,
145			comments: Comments::All,
146			expect_jsx: false,
147			trailing_semicolon: false,
148			expect_markers: false,
149			indent_with: "\t".to_owned(),
150			max_line_length: u8::MAX,
151		}
152	}
153}
154
155impl ToStringOptions {
156	#[must_use]
157	pub fn minified() -> Self {
158		ToStringOptions {
159			pretty: false,
160			comments: Comments::None,
161			indent_with: String::new(),
162			..Default::default()
163		}
164	}
165
166	/// With TypeScript type syntax
167	#[must_use]
168	pub fn typescript() -> Self {
169		ToStringOptions { include_type_annotations: true, ..Default::default() }
170	}
171
172	/// Whether to include comment in source
173	pub(crate) fn should_add_comment(&self, content: &str) -> bool {
174		self.comments.should_add_comment(content)
175	}
176
177	pub(crate) fn add_indent<T: source_map::ToString>(&self, indent: u8, buf: &mut T) {
178		if self.pretty {
179			(0..indent).for_each(|_| buf.push_str(&self.indent_with));
180		}
181	}
182
183	/// Adds whitespace **conditionally** (based on pretty setting)
184	pub(crate) fn push_gap_optionally<T: source_map::ToString>(&self, buf: &mut T) {
185		if self.pretty {
186			buf.push(' ');
187		}
188	}
189
190	pub(crate) fn enforce_limit_length_limit(&self) -> bool {
191		self.pretty && self.max_line_length != u8::MAX
192	}
193}
194
195#[derive(Debug, Default, Clone, Copy)]
196#[cfg_attr(feature = "serde-serialize", derive(serde::Deserialize))]
197#[cfg_attr(target_family = "wasm", derive(tsify::Tsify))]
198pub enum Comments {
199	#[default]
200	All,
201	/// Only multiline comments starting with `/**`
202	JustDocumentation,
203	None,
204}
205
206impl Comments {
207	/// Whether to include comment in source
208	pub(crate) fn should_add_comment(self, content: &str) -> bool {
209		match self {
210			Comments::All => true,
211			Comments::None => false,
212			Comments::JustDocumentation => {
213				content.starts_with('*') || content.trim_start().starts_with('@')
214			}
215		}
216	}
217}