sass_embedded_host_rust/
embedded.rs1use std::{ffi::OsStr, path::Path};
2
3use atty::Stream;
4
5use crate::{
6  channel::Channel,
7  host::ImporterRegistry,
8  host::{Host, LoggerRegistry},
9  protocol::inbound_message::{
10    compile_request::{Input, StringInput},
11    CompileRequest,
12  },
13  CompileResult, Options, Result, StringOptions,
14};
15#[cfg(feature = "legacy")]
16use crate::{
17  legacy::LEGACY_IMPORTER_PROTOCOL, protocol::inbound_message::compile_request,
18};
19
20#[derive(Debug)]
21pub struct Embedded {
22  channel: Channel,
23}
24
25impl Embedded {
26  pub fn new(exe_path: impl AsRef<OsStr>) -> Self {
27    Self {
28      channel: Channel::new(exe_path),
29    }
30  }
31
32  pub fn compile(
33    &mut self,
34    path: impl AsRef<Path>,
35    options: Options,
36  ) -> Result<CompileResult> {
37    let mut logger_registry = LoggerRegistry::default();
38    let mut importer_registry = ImporterRegistry::default();
39    let importers = importer_registry
40      .register_all(options.importers, options.load_paths)
41      .collect();
42    if let Some(l) = options.logger {
43      logger_registry.register(l);
44    }
45
46    let request = CompileRequest {
47      style: options.style as i32,
48      source_map: options.source_map,
49      alert_color: options
50        .alert_color
51        .unwrap_or_else(|| atty::is(Stream::Stdout)),
52      alert_ascii: options.alert_ascii,
53      verbose: options.verbose,
54      quiet_deps: options.quiet_deps,
55      source_map_include_sources: options.source_map_include_sources,
56      charset: options.charset,
57      importers,
58      input: Some(Input::Path(path.as_ref().to_str().unwrap().to_string())),
59      ..Default::default()
62    };
63
64    let host = Host::new(importer_registry, logger_registry);
65    let conn = self.channel.connect(host);
66    let response = conn.compile_request(request)?;
67    CompileResult::try_from(response)
68  }
69
70  pub fn compile_string(
71    &mut self,
72    source: impl Into<String>,
73    options: StringOptions,
74  ) -> Result<CompileResult> {
75    let mut logger_registry = LoggerRegistry::default();
76    let mut importer_registry = ImporterRegistry::default();
77    let importers = importer_registry
78      .register_all(options.common.importers, options.common.load_paths)
79      .collect();
80    if let Some(l) = options.common.logger {
81      logger_registry.register(l);
82    }
83
84    #[cfg(feature = "legacy")]
85    let importer = if let Some(input_importer) = options.input_importer {
86      Some(importer_registry.register(input_importer))
87    } else if matches!(&options.url, Some(u) if u.to_string() == LEGACY_IMPORTER_PROTOCOL)
88    {
89      Some(compile_request::Importer {
90        importer: Some(compile_request::importer::Importer::Path(
91          std::env::current_dir()
92            .unwrap()
93            .to_str()
94            .unwrap()
95            .to_string(),
96        )),
97      })
98    } else {
99      None
100    };
101
102    #[cfg(feature = "legacy")]
103    let url = options
104      .url
105      .map(|url| url.to_string())
106      .filter(|url| url != LEGACY_IMPORTER_PROTOCOL)
107      .unwrap_or_default();
108
109    #[cfg(not(feature = "legacy"))]
110    let importer = options
111      .input_importer
112      .map(|i| importer_registry.register(i));
113
114    #[cfg(not(feature = "legacy"))]
115    let url = options.url.map(|url| url.to_string()).unwrap_or_default();
116
117    let request = CompileRequest {
118      style: options.common.style as i32,
119      source_map: options.common.source_map,
120      alert_color: options
121        .common
122        .alert_color
123        .unwrap_or_else(|| atty::is(Stream::Stdout)),
124      alert_ascii: options.common.alert_ascii,
125      verbose: options.common.verbose,
126      quiet_deps: options.common.quiet_deps,
127      source_map_include_sources: options.common.source_map_include_sources,
128      charset: options.common.charset,
129      importers,
130      input: Some(Input::String(StringInput {
131        source: source.into(),
132        url,
133        syntax: options.syntax as i32,
134        importer,
135      })),
136      ..Default::default()
139    };
140
141    let host = Host::new(importer_registry, logger_registry);
142    let conn = self.channel.connect(host);
143    let response = conn.compile_request(request)?;
144    CompileResult::try_from(response)
145  }
146
147  pub fn info(&mut self) -> Result<String> {
148    let logger_registry = LoggerRegistry::default();
149    let importer_registry = ImporterRegistry::default();
150    let host = Host::new(importer_registry, logger_registry);
151    let conn = self.channel.connect(host);
152    let response = conn.version_request()?;
153    Ok(format!(
154      "sass-embedded\t#{}",
155      response.implementation_version
156    ))
157  }
158}