sass_embedded/
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::{
10 self,
11 inbound_message::{
12 compile_request::{Input, StringInput},
13 CompileRequest,
14 },
15 },
16 CompileResult, Options, Result, StringOptions,
17};
18#[cfg(feature = "legacy")]
19use crate::{
20 legacy::LEGACY_IMPORTER_PROTOCOL, protocol::inbound_message::compile_request,
21};
22
23#[derive(Debug)]
25pub struct Embedded {
26 channel: Channel,
27}
28
29impl Embedded {
30 pub fn new(exe_path: impl AsRef<OsStr>) -> Result<Self> {
36 Ok(Self {
37 channel: Channel::new(exe_path)?,
38 })
39 }
40
41 pub fn compile(
53 &mut self,
54 path: impl AsRef<Path>,
55 options: Options,
56 ) -> Result<CompileResult> {
57 let mut logger_registry = LoggerRegistry::default();
58 let mut importer_registry = ImporterRegistry::default();
59 let importers = importer_registry
60 .register_all(options.importers, options.load_paths)
61 .collect();
62 if let Some(l) = options.logger {
63 logger_registry.register(l);
64 }
65
66 let request = CompileRequest {
67 style: protocol::OutputStyle::from(options.style) as i32,
68 source_map: options.source_map,
69 alert_color: options
70 .alert_color
71 .unwrap_or_else(|| atty::is(Stream::Stdout)),
72 alert_ascii: options.alert_ascii,
73 verbose: options.verbose,
74 quiet_deps: options.quiet_deps,
75 source_map_include_sources: options.source_map_include_sources,
76 charset: options.charset,
77 importers,
78 input: Some(Input::Path(path.as_ref().to_str().unwrap().to_string())),
79 ..Default::default()
82 };
83
84 let host = Host::new(importer_registry, logger_registry);
85 let conn = self.channel.connect(host)?;
86 let response = conn
87 .compile_request(request)
88 .map_err(|e| Box::new(e.into()))?;
89 CompileResult::try_from(response)
90 }
91
92 pub fn compile_string(
104 &mut self,
105 source: impl Into<String>,
106 options: StringOptions,
107 ) -> Result<CompileResult> {
108 let mut logger_registry = LoggerRegistry::default();
109 let mut importer_registry = ImporterRegistry::default();
110 let importers = importer_registry
111 .register_all(options.common.importers, options.common.load_paths)
112 .collect();
113 if let Some(l) = options.common.logger {
114 logger_registry.register(l);
115 }
116
117 #[cfg(feature = "legacy")]
118 let importer = if let Some(input_importer) = options.input_importer {
119 Some(importer_registry.register(input_importer))
120 } else if matches!(&options.url, Some(u) if u.to_string() == LEGACY_IMPORTER_PROTOCOL)
121 {
122 Some(compile_request::Importer {
123 importer: Some(compile_request::importer::Importer::Path(
124 std::env::current_dir()
125 .unwrap()
126 .to_str()
127 .unwrap()
128 .to_string(),
129 )),
130 })
131 } else {
132 None
133 };
134
135 #[cfg(feature = "legacy")]
136 let url = options
137 .url
138 .map(|url| url.to_string())
139 .filter(|url| url != LEGACY_IMPORTER_PROTOCOL)
140 .unwrap_or_default();
141
142 #[cfg(not(feature = "legacy"))]
143 let importer = options
144 .input_importer
145 .map(|i| importer_registry.register(i));
146
147 #[cfg(not(feature = "legacy"))]
148 let url = options.url.map(|url| url.to_string()).unwrap_or_default();
149
150 let request = CompileRequest {
151 style: protocol::OutputStyle::from(options.common.style) as i32,
152 source_map: options.common.source_map,
153 alert_color: options
154 .common
155 .alert_color
156 .unwrap_or_else(|| atty::is(Stream::Stdout)),
157 alert_ascii: options.common.alert_ascii,
158 verbose: options.common.verbose,
159 quiet_deps: options.common.quiet_deps,
160 source_map_include_sources: options.common.source_map_include_sources,
161 charset: options.common.charset,
162 importers,
163 input: Some(Input::String(StringInput {
164 source: source.into(),
165 url,
166 syntax: protocol::Syntax::from(options.syntax) as i32,
167 importer,
168 })),
169 ..Default::default()
172 };
173
174 let host = Host::new(importer_registry, logger_registry);
175 let conn = self.channel.connect(host)?;
176 let response = conn
177 .compile_request(request)
178 .map_err(|e| Box::new(e.into()))?;
179 CompileResult::try_from(response)
180 }
181
182 pub fn info(&mut self) -> Result<String> {
184 let logger_registry = LoggerRegistry::default();
185 let importer_registry = ImporterRegistry::default();
186 let host = Host::new(importer_registry, logger_registry);
187 let conn = self.channel.connect(host)?;
188 let response = conn.version_request().map_err(|e| Box::new(e.into()))?;
189 Ok(format!(
190 "sass-embedded\t#{}",
191 response.implementation_version
192 ))
193 }
194}