Skip to main content

svelte_compiler/
api.rs

1use std::collections::BTreeMap;
2use std::fmt;
3use std::future::Future;
4use std::pin::Pin;
5use std::sync::Arc;
6
7use crate::ast::common::Span;
8use crate::ast::{CssAst, Document};
9use crate::error::SourcePosition;
10use crate::{CompileError, LineColumn};
11use camino::Utf8Path;
12use camino::Utf8PathBuf;
13use lightningcss::stylesheet::ParserOptions as LightningParserOptions;
14use serde::{Deserialize, Deserializer, Serialize, Serializer};
15
16mod runes_mode;
17pub(crate) mod scan;
18pub(crate) mod validation;
19pub(crate) use runes_mode::*;
20pub(crate) use scan::*;
21pub(crate) use svelte_syntax::{
22    ElementKind, SvelteElementKind, classify_element_name, is_custom_element_name,
23    is_valid_component_name, is_valid_element_name, is_void_element_name,
24};
25
26/// Current Svelte compiler version string.
27pub static VERSION: &str = "5.53.9";
28
29macro_rules! impl_enum_text_traits {
30    ($ty:ty { $($text:literal => $variant:path),+ $(,)? }) => {
31        impl $ty {
32            #[must_use]
33            pub const fn as_str(self) -> &'static str {
34                match self {
35                    $($variant => $text),+
36                }
37            }
38        }
39
40        impl fmt::Display for $ty {
41            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42                f.write_str(self.as_str())
43            }
44        }
45
46        impl std::str::FromStr for $ty {
47            type Err = ();
48
49            fn from_str(value: &str) -> Result<Self, Self::Err> {
50                match value {
51                    $($text => Ok($variant),)+
52                    _ => Err(()),
53                }
54            }
55        }
56    };
57}
58
59#[derive(Clone, Copy)]
60/// Input passed to a custom CSS hash callback.
61pub struct CssHashInput<'a> {
62    pub name: &'a str,
63    pub filename: &'a str,
64    pub css: &'a str,
65    pub hash: fn(&str) -> String,
66}
67
68impl fmt::Debug for CssHashInput<'_> {
69    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70        f.debug_struct("CssHashInput")
71            .field("name", &self.name)
72            .field("filename", &self.filename)
73            .field("css", &self.css)
74            .finish_non_exhaustive()
75    }
76}
77
78#[derive(Clone)]
79/// Callback used to filter warnings during compilation.
80pub struct WarningFilterCallback(Arc<dyn Fn(&Warning) -> bool + 'static>);
81
82impl WarningFilterCallback {
83    #[must_use]
84    pub fn new<F>(callback: F) -> Self
85    where
86        F: Fn(&Warning) -> bool + 'static,
87    {
88        Self(Arc::new(callback))
89    }
90
91    pub(crate) fn call(&self, warning: &Warning) -> bool {
92        (self.0)(warning)
93    }
94}
95
96impl fmt::Debug for WarningFilterCallback {
97    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98        f.write_str("WarningFilterCallback(..)")
99    }
100}
101
102#[derive(Clone)]
103/// Callback used to override Svelte's generated CSS hash.
104pub struct CssHashGetterCallback(Arc<dyn for<'a> Fn(CssHashInput<'a>) -> Arc<str> + 'static>);
105
106impl CssHashGetterCallback {
107    #[must_use]
108    pub fn new<F, S>(callback: F) -> Self
109    where
110        F: for<'a> Fn(CssHashInput<'a>) -> S + 'static,
111        S: Into<Arc<str>>,
112    {
113        Self(Arc::new(move |input| callback(input).into()))
114    }
115
116    pub(crate) fn call(&self, input: CssHashInput<'_>) -> Arc<str> {
117        (self.0)(input)
118    }
119}
120
121impl fmt::Debug for CssHashGetterCallback {
122    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123        f.write_str("CssHashGetterCallback(..)")
124    }
125}
126
127#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
128#[serde(rename_all = "kebab-case")]
129/// Selects which public AST representation `parse` returns.
130pub enum ParseMode {
131    #[default]
132    Legacy,
133    Modern,
134}
135
136impl_enum_text_traits!(ParseMode {
137    "legacy" => ParseMode::Legacy,
138    "modern" => ParseMode::Modern,
139});
140
141#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
142#[serde(default)]
143/// Options for parsing a component without compiling it.
144pub struct ParseOptions {
145    /// Optional source filename used in diagnostics.
146    pub filename: Option<Utf8PathBuf>,
147    /// Optional project root used by path-sensitive tooling.
148    pub root_dir: Option<Utf8PathBuf>,
149    /// Compatibility flag matching Svelte's JavaScript API.
150    pub modern: Option<bool>,
151    /// Preferred AST shape when `modern` is not set.
152    pub mode: ParseMode,
153    /// Return a best-effort AST for malformed input when possible.
154    pub loose: bool,
155}
156
157impl ParseOptions {
158    #[must_use]
159    pub fn effective_mode(&self) -> ParseMode {
160        match self.modern {
161            Some(true) => ParseMode::Modern,
162            Some(false) => ParseMode::Legacy,
163            None => self.mode,
164        }
165    }
166}
167
168#[derive(Debug, Clone, Serialize, Deserialize, Default)]
169#[serde(default)]
170/// Options for converting a parsed AST back into Svelte source.
171pub struct PrintOptions {
172    /// Keep whitespace-only text nodes instead of collapsing them where possible.
173    pub preserve_whitespace: bool,
174}
175
176#[derive(Clone, Copy, Debug)]
177/// Selects which modern AST node should be printed.
178pub enum ModernPrintTarget<'a> {
179    Root {
180        source: &'a str,
181        root: &'a crate::ast::modern::Root,
182    },
183    Fragment {
184        source: &'a str,
185        fragment: &'a crate::ast::modern::Fragment,
186    },
187    Node {
188        source: &'a str,
189        node: &'a crate::ast::modern::Node,
190    },
191    Script {
192        source: &'a str,
193        script: &'a crate::ast::modern::Script,
194    },
195    Css {
196        source: &'a str,
197        stylesheet: &'a crate::ast::modern::Css,
198    },
199    CssNode {
200        source: &'a str,
201        node: &'a crate::ast::modern::CssNode,
202    },
203    Attribute {
204        source: &'a str,
205        attribute: &'a crate::ast::modern::Attribute,
206    },
207    Options {
208        source: &'a str,
209        options: &'a crate::ast::modern::Options,
210    },
211    Comment {
212        source: &'a str,
213        comment: &'a crate::ast::modern::Comment,
214    },
215}
216
217impl<'a> ModernPrintTarget<'a> {
218    pub const fn root(source: &'a str, root: &'a crate::ast::modern::Root) -> Self {
219        Self::Root { source, root }
220    }
221
222    pub const fn fragment(source: &'a str, fragment: &'a crate::ast::modern::Fragment) -> Self {
223        Self::Fragment { source, fragment }
224    }
225
226    pub const fn node(source: &'a str, node: &'a crate::ast::modern::Node) -> Self {
227        Self::Node { source, node }
228    }
229
230    pub const fn script(source: &'a str, script: &'a crate::ast::modern::Script) -> Self {
231        Self::Script { source, script }
232    }
233
234    pub const fn css(source: &'a str, stylesheet: &'a crate::ast::modern::Css) -> Self {
235        Self::Css { source, stylesheet }
236    }
237
238    pub const fn css_node(source: &'a str, node: &'a crate::ast::modern::CssNode) -> Self {
239        Self::CssNode { source, node }
240    }
241
242    pub const fn attribute(source: &'a str, attribute: &'a crate::ast::modern::Attribute) -> Self {
243        Self::Attribute { source, attribute }
244    }
245
246    pub const fn options(source: &'a str, options: &'a crate::ast::modern::Options) -> Self {
247        Self::Options { source, options }
248    }
249
250    pub const fn comment(source: &'a str, comment: &'a crate::ast::modern::Comment) -> Self {
251        Self::Comment { source, comment }
252    }
253
254    pub(crate) const fn source(self) -> &'a str {
255        match self {
256            Self::Root { source, .. }
257            | Self::Fragment { source, .. }
258            | Self::Node { source, .. }
259            | Self::Script { source, .. }
260            | Self::Css { source, .. }
261            | Self::CssNode { source, .. }
262            | Self::Attribute { source, .. }
263            | Self::Options { source, .. }
264            | Self::Comment { source, .. } => source,
265        }
266    }
267
268    pub(crate) fn raw_slice(self) -> Option<&'a str> {
269        let source = self.source();
270        let (start, end) = match self {
271            Self::Root { root, .. } => (root.start, root.end),
272            Self::Fragment { fragment, .. } => {
273                let first = fragment.nodes.first()?;
274                let last = fragment.nodes.last()?;
275                (first.start(), last.end())
276            }
277            Self::Node { node, .. } => (node.start(), node.end()),
278            Self::Script { script, .. } => (script.start, script.end),
279            Self::Css { stylesheet, .. } => (stylesheet.start, stylesheet.end),
280            Self::CssNode { node, .. } => match node {
281                crate::ast::modern::CssNode::Rule(rule) => (rule.start, rule.end),
282                crate::ast::modern::CssNode::Atrule(atrule) => (atrule.start, atrule.end),
283            },
284            Self::Attribute { attribute, .. } => match attribute {
285                crate::ast::modern::Attribute::Attribute(attribute) => {
286                    (attribute.start, attribute.end)
287                }
288                crate::ast::modern::Attribute::SpreadAttribute(attribute) => {
289                    (attribute.start, attribute.end)
290                }
291                crate::ast::modern::Attribute::BindDirective(attribute)
292                | crate::ast::modern::Attribute::OnDirective(attribute)
293                | crate::ast::modern::Attribute::ClassDirective(attribute)
294                | crate::ast::modern::Attribute::LetDirective(attribute)
295                | crate::ast::modern::Attribute::AnimateDirective(attribute)
296                | crate::ast::modern::Attribute::UseDirective(attribute) => {
297                    (attribute.start, attribute.end)
298                }
299                crate::ast::modern::Attribute::StyleDirective(attribute) => {
300                    (attribute.start, attribute.end)
301                }
302                crate::ast::modern::Attribute::TransitionDirective(attribute) => {
303                    (attribute.start, attribute.end)
304                }
305                crate::ast::modern::Attribute::AttachTag(attribute) => {
306                    (attribute.start, attribute.end)
307                }
308            },
309            Self::Options { options, .. } => (options.start, options.end),
310            Self::Comment { comment, .. } => (comment.start, comment.end),
311        };
312
313        source.get(start..end)
314    }
315}
316
317#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
318#[serde(rename_all = "lowercase")]
319pub enum Namespace {
320    #[default]
321    Html,
322    Svg,
323    Mathml,
324}
325
326impl_enum_text_traits!(Namespace {
327    "html" => Namespace::Html,
328    "svg" => Namespace::Svg,
329    "mathml" => Namespace::Mathml,
330});
331
332#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
333#[serde(rename_all = "lowercase")]
334pub enum CssOutputMode {
335    Injected,
336    #[default]
337    External,
338}
339
340impl_enum_text_traits!(CssOutputMode {
341    "injected" => CssOutputMode::Injected,
342    "external" => CssOutputMode::External,
343});
344
345#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
346pub enum CompatibilityComponentApi {
347    V4,
348    #[default]
349    V5,
350}
351
352impl_enum_text_traits!(CompatibilityComponentApi {
353    "4" => CompatibilityComponentApi::V4,
354    "5" => CompatibilityComponentApi::V5,
355});
356
357impl Serialize for CompatibilityComponentApi {
358    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
359    where
360        S: Serializer,
361    {
362        serializer.serialize_u8(match self {
363            Self::V4 => 4,
364            Self::V5 => 5,
365        })
366    }
367}
368
369impl<'de> Deserialize<'de> for CompatibilityComponentApi {
370    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
371    where
372        D: Deserializer<'de>,
373    {
374        #[derive(Deserialize)]
375        #[serde(untagged)]
376        enum CompatibilityComponentApiRepr {
377            Number(u8),
378            String(Arc<str>),
379        }
380
381        match CompatibilityComponentApiRepr::deserialize(deserializer)? {
382            CompatibilityComponentApiRepr::Number(4) => Ok(Self::V4),
383            CompatibilityComponentApiRepr::Number(5) => Ok(Self::V5),
384            CompatibilityComponentApiRepr::Number(other) => Err(serde::de::Error::invalid_value(
385                serde::de::Unexpected::Unsigned(u64::from(other)),
386                &"4 or 5",
387            )),
388            CompatibilityComponentApiRepr::String(value) => value.parse().map_err(|_| {
389                serde::de::Error::invalid_value(
390                    serde::de::Unexpected::Str(value.as_ref()),
391                    &"\"4\" or \"5\"",
392                )
393            }),
394        }
395    }
396}
397
398#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
399pub struct CompatibilityOptions {
400    #[serde(alias = "componentApi")]
401    pub component_api: Option<CompatibilityComponentApi>,
402}
403
404#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
405#[serde(rename_all = "kebab-case")]
406pub enum GenerateTarget {
407    None,
408    #[default]
409    Client,
410    Server,
411}
412
413impl_enum_text_traits!(GenerateTarget {
414    "none" => GenerateTarget::None,
415    "client" => GenerateTarget::Client,
416    "server" => GenerateTarget::Server,
417});
418
419#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
420#[serde(rename_all = "lowercase")]
421pub enum FragmentStrategy {
422    #[default]
423    Html,
424    Tree,
425}
426
427impl_enum_text_traits!(FragmentStrategy {
428    "html" => FragmentStrategy::Html,
429    "tree" => FragmentStrategy::Tree,
430});
431
432#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
433#[serde(rename_all = "lowercase")]
434pub enum ErrorMode {
435    #[default]
436    Error,
437    Warn,
438}
439
440impl_enum_text_traits!(ErrorMode {
441    "error" => ErrorMode::Error,
442    "warn" => ErrorMode::Warn,
443});
444
445#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
446#[serde(default)]
447/// Experimental compiler switches.
448pub struct ExperimentalOptions {
449    pub r#async: bool,
450}
451
452#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
453/// Sourcemap configuration accepted by the compiler.
454pub struct SourceMap {
455    pub version: u32,
456    pub file: Option<Arc<str>>,
457    #[serde(alias = "sourceRoot")]
458    pub source_root: Option<Arc<str>>,
459    pub sources: Box<[Arc<str>]>,
460    #[serde(alias = "sourcesContent")]
461    pub sources_content: Option<Box<[Option<Arc<str>>]>>,
462    pub names: Box<[Arc<str>]>,
463    pub mappings: Arc<str>,
464}
465
466#[derive(Debug, Clone, Serialize, Deserialize)]
467#[serde(default)]
468/// Options for compiling a `.svelte` component or rune-enabled module.
469pub struct CompileOptions {
470    pub name: Option<Arc<str>>,
471    pub filename: Option<Utf8PathBuf>,
472    #[serde(alias = "rootDir")]
473    pub root_dir: Option<Utf8PathBuf>,
474    pub generate: GenerateTarget,
475    pub fragments: FragmentStrategy,
476    pub dev: bool,
477    pub hmr: bool,
478    #[serde(alias = "customElement")]
479    pub custom_element: bool,
480    pub accessors: bool,
481    pub namespace: Namespace,
482    pub immutable: bool,
483    pub css: CssOutputMode,
484    #[serde(alias = "warningFilterIgnoreCodes")]
485    pub warning_filter_ignore_codes: Box<[Arc<str>]>,
486    #[serde(skip, default)]
487    pub warning_filter: Option<WarningFilterCallback>,
488    pub runes: Option<bool>,
489    #[serde(alias = "errorMode")]
490    pub error_mode: ErrorMode,
491    pub sourcemap: Option<SourceMap>,
492    #[serde(alias = "outputFilename")]
493    pub output_filename: Option<Utf8PathBuf>,
494    #[serde(alias = "cssOutputFilename")]
495    pub css_output_filename: Option<Utf8PathBuf>,
496    #[serde(alias = "cssHash")]
497    pub css_hash: Option<Arc<str>>,
498    #[serde(skip, default)]
499    pub css_hash_getter: Option<CssHashGetterCallback>,
500    #[serde(alias = "preserveComments")]
501    pub preserve_comments: bool,
502    #[serde(alias = "preserveWhitespace")]
503    pub preserve_whitespace: bool,
504    #[serde(alias = "discloseVersion")]
505    pub disclose_version: bool,
506    pub compatibility: Option<CompatibilityOptions>,
507    #[serde(alias = "modernAst")]
508    pub modern_ast: bool,
509    pub experimental: ExperimentalOptions,
510}
511
512impl Default for CompileOptions {
513    fn default() -> Self {
514        Self {
515            name: None,
516            filename: None,
517            root_dir: None,
518            generate: GenerateTarget::default(),
519            fragments: FragmentStrategy::default(),
520            dev: false,
521            hmr: false,
522            custom_element: false,
523            accessors: false,
524            namespace: Namespace::default(),
525            immutable: false,
526            css: CssOutputMode::default(),
527            warning_filter_ignore_codes: Box::default(),
528            warning_filter: None,
529            runes: None,
530            error_mode: ErrorMode::default(),
531            sourcemap: None,
532            output_filename: None,
533            css_output_filename: None,
534            css_hash: None,
535            css_hash_getter: None,
536            preserve_comments: false,
537            preserve_whitespace: false,
538            disclose_version: true,
539            compatibility: None,
540            modern_ast: false,
541            experimental: ExperimentalOptions::default(),
542        }
543    }
544}
545
546#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
547/// Warning emitted during analysis or code generation.
548pub struct Warning {
549    pub code: Arc<str>,
550    pub message: Arc<str>,
551    pub filename: Option<Utf8PathBuf>,
552    pub start: Option<LineColumn>,
553    pub end: Option<LineColumn>,
554    pub frame: Option<Arc<str>>,
555    pub position: Option<[usize; 2]>,
556}
557
558#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
559/// Generated output artifact such as JavaScript or CSS.
560pub struct OutputArtifact {
561    pub code: Arc<str>,
562    pub map: Option<SourceMap>,
563    pub has_global: Option<bool>,
564}
565
566#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
567/// Extra metadata produced during compilation.
568pub struct CompileMetadata {
569    pub runes: bool,
570}
571
572#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
573/// Result of compiling a component or module.
574pub struct CompileResult {
575    pub js: OutputArtifact,
576    pub css: Option<OutputArtifact>,
577    pub warnings: Box<[Warning]>,
578    pub metadata: CompileMetadata,
579    pub ast: Option<Document>,
580}
581
582#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
583/// Result of printing a Svelte AST node.
584pub struct PrintedOutput {
585    pub code: Arc<str>,
586    pub map: SourceMap,
587}
588
589#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
590#[serde(untagged)]
591/// Attribute values passed to preprocessors.
592pub enum PreprocessAttributeValue {
593    String(Arc<str>),
594    Bool(bool),
595}
596
597impl Default for PreprocessAttributeValue {
598    fn default() -> Self {
599        Self::Bool(true)
600    }
601}
602
603#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
604/// One parsed attribute passed to a tag preprocessor.
605pub struct PreprocessAttribute {
606    pub name: Arc<str>,
607    pub value: PreprocessAttributeValue,
608}
609
610pub type PreprocessAttributes = BTreeMap<Arc<str>, PreprocessAttributeValue>;
611
612#[derive(Debug, Clone, Copy)]
613/// Input passed to a markup preprocessor.
614pub struct PreprocessMarkup<'a> {
615    pub content: &'a str,
616    pub filename: Option<&'a Utf8Path>,
617}
618
619#[derive(Debug, Clone, Copy)]
620/// Input passed to a script or style preprocessor.
621pub struct PreprocessTag<'a> {
622    pub content: &'a str,
623    pub attributes: &'a PreprocessAttributes,
624    pub markup: &'a str,
625    pub filename: Option<&'a Utf8Path>,
626}
627
628#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
629/// Output returned by one preprocessor step.
630pub struct PreprocessOutput {
631    pub code: Arc<str>,
632    pub dependencies: Box<[Utf8PathBuf]>,
633    pub map: Option<SourceMap>,
634    pub attributes: Option<Box<[PreprocessAttribute]>>,
635}
636
637pub type MarkupPreprocessor = Arc<
638    dyn for<'a> Fn(PreprocessMarkup<'a>) -> Result<Option<PreprocessOutput>, CompileError>
639        + Send
640        + Sync
641        + 'static,
642>;
643
644pub type TagPreprocessor = Arc<
645    dyn for<'a> Fn(PreprocessTag<'a>) -> Result<Option<PreprocessOutput>, CompileError>
646        + Send
647        + Sync
648        + 'static,
649>;
650
651pub type AsyncMarkupPreprocessor = Arc<
652    dyn for<'a> Fn(
653            PreprocessMarkup<'a>,
654        ) -> Pin<
655            Box<dyn Future<Output = Result<Option<PreprocessOutput>, CompileError>> + Send + 'a>,
656        > + Send
657        + Sync
658        + 'static,
659>;
660
661pub type AsyncTagPreprocessor = Arc<
662    dyn for<'a> Fn(
663            PreprocessTag<'a>,
664        ) -> Pin<
665            Box<dyn Future<Output = Result<Option<PreprocessOutput>, CompileError>> + Send + 'a>,
666        > + Send
667        + Sync
668        + 'static,
669>;
670
671#[derive(Clone, Default)]
672/// Collection of preprocessors applied in source order.
673pub struct PreprocessorGroup {
674    pub name: Option<Arc<str>>,
675    pub markup: Option<MarkupPreprocessor>,
676    pub script: Option<TagPreprocessor>,
677    pub style: Option<TagPreprocessor>,
678    pub markup_async: Option<AsyncMarkupPreprocessor>,
679    pub script_async: Option<AsyncTagPreprocessor>,
680    pub style_async: Option<AsyncTagPreprocessor>,
681}
682
683impl fmt::Debug for PreprocessorGroup {
684    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
685        f.debug_struct("PreprocessorGroup")
686            .field("name", &self.name)
687            .field("markup", &self.markup.is_some())
688            .field("script", &self.script.is_some())
689            .field("style", &self.style.is_some())
690            .field("markup_async", &self.markup_async.is_some())
691            .field("script_async", &self.script_async.is_some())
692            .field("style_async", &self.style_async.is_some())
693            .finish()
694    }
695}
696
697impl PreprocessorGroup {
698    #[must_use]
699    pub fn new() -> Self {
700        Self::default()
701    }
702}
703
704#[derive(Debug, Clone, Serialize, Deserialize, Default)]
705#[serde(default)]
706/// Options for running preprocessors over component source code.
707pub struct PreprocessOptions {
708    pub filename: Option<Utf8PathBuf>,
709    #[serde(skip, default)]
710    pub groups: Box<[PreprocessorGroup]>,
711}
712
713#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
714/// Final result of a preprocessing run.
715pub struct PreprocessResult {
716    pub code: Arc<str>,
717    pub dependencies: Box<[Utf8PathBuf]>,
718    pub map: Option<SourceMap>,
719}
720
721#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
722#[serde(default)]
723/// Options for best-effort code migration.
724pub struct MigrateOptions {
725    pub filename: Option<Utf8PathBuf>,
726    pub use_ts: bool,
727}
728
729#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)]
730/// Result of a migration run.
731pub struct MigrateResult {
732    pub code: Arc<str>,
733}
734
735#[derive(Debug, Default)]
736/// Convenience object that mirrors the free compiler functions.
737pub struct Compiler;
738
739impl Compiler {
740    #[must_use]
741    pub fn new() -> Self {
742        Self
743    }
744
745    pub fn parse(&self, source: &str, options: ParseOptions) -> Result<Document, CompileError> {
746        crate::compiler::phases::parse::parse_component(source, options)
747    }
748
749    pub fn print(
750        &self,
751        ast: &Document,
752        options: PrintOptions,
753    ) -> Result<PrintedOutput, CompileError> {
754        crate::compiler::phases::transform::print_component(ast, options)
755    }
756
757    pub fn print_modern(
758        &self,
759        ast: ModernPrintTarget<'_>,
760        options: PrintOptions,
761    ) -> Result<PrintedOutput, CompileError> {
762        crate::compiler::phases::transform::print_modern_target(ast, options)
763    }
764
765    pub fn compile(
766        &self,
767        source: &str,
768        options: CompileOptions,
769    ) -> Result<CompileResult, CompileError> {
770        crate::compiler::phases::transform::compile_component(source, options)
771    }
772
773    pub fn compile_module(
774        &self,
775        source: &str,
776        options: CompileOptions,
777    ) -> Result<CompileResult, CompileError> {
778        crate::compiler::phases::transform::compile_module(source, options)
779    }
780
781    pub fn parse_css(&self, source: &str) -> Result<CssAst, CompileError> {
782        crate::compiler::phases::parse::parse_css(source)
783    }
784
785    pub fn preprocess(
786        &self,
787        source: &str,
788        options: PreprocessOptions,
789    ) -> Result<PreprocessResult, CompileError> {
790        crate::compiler::phases::preprocess::preprocess(source, options)
791    }
792
793    pub async fn preprocess_async(
794        &self,
795        source: &str,
796        options: PreprocessOptions,
797    ) -> Result<PreprocessResult, CompileError> {
798        crate::compiler::phases::preprocess::preprocess_async(source, options).await
799    }
800
801    pub fn migrate(
802        &self,
803        source: &str,
804        options: MigrateOptions,
805    ) -> Result<MigrateResult, CompileError> {
806        crate::compiler::phases::migrate::migrate(source, options)
807    }
808}