Skip to content

Commit dcf835e

Browse files
committed
feat: compile path
1 parent 9a5a763 commit dcf835e

File tree

10 files changed

+136
-226
lines changed

10 files changed

+136
-226
lines changed

examples/compile_path.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
fn main() {}

src/api.rs

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ use url::Url;
66
pub use crate::{
77
error::Result,
88
pb::{
9-
outbound_message::compile_response::CompileFailure, OutputStyle,
10-
SourceSpan, Syntax,
9+
outbound_message::compile_response::{CompileFailure, CompileSuccess},
10+
OutputStyle, SourceSpan, Syntax,
1111
},
1212
};
1313

@@ -39,26 +39,14 @@ pub struct Options {
3939
}
4040

4141
/// https://sass-lang.com/documentation/js-api/modules#StringOptions
42-
#[derive(Debug)]
4342
pub enum StringOptions {
44-
WithImporter(StringOptionsWithImporter),
45-
WithoutImporter(StringOptionsWithoutImporter),
46-
}
47-
48-
impl StringOptions {
49-
pub fn get_options_mut(&mut self) -> &mut Options {
50-
match self {
51-
StringOptions::WithImporter(o) => &mut o.base.base,
52-
StringOptions::WithoutImporter(o) => &mut o.base,
53-
}
54-
}
43+
WithoutImporter(WithoutImporter),
44+
WithImporter(WithImporter),
5545
}
5646

5747
/// https://sass-lang.com/documentation/js-api/interfaces/StringOptionsWithoutImporter
5848
#[derive(Debug, Default)]
59-
pub struct StringOptionsWithoutImporter {
60-
/// extends [Options]
61-
pub base: Options,
49+
pub struct WithoutImporter {
6250
/// https://sass-lang.com/documentation/js-api/interfaces/StringOptionsWithoutImporter#syntax
6351
pub syntax: Syntax,
6452
/// https://sass-lang.com/documentation/js-api/interfaces/StringOptionsWithoutImporter#url
@@ -67,11 +55,11 @@ pub struct StringOptionsWithoutImporter {
6755

6856
/// https://sass-lang.com/documentation/js-api/interfaces/StringOptionsWithImporter
6957
#[derive(Debug)]
70-
pub struct StringOptionsWithImporter {
71-
/// extends [StringOptionsWithoutImporter]
72-
pub base: StringOptionsWithoutImporter,
58+
pub struct WithImporter {
7359
/// https://sass-lang.com/documentation/js-api/interfaces/StringOptionsWithImporter#importer
7460
pub importer: SassImporter,
61+
/// https://sass-lang.com/documentation/js-api/interfaces/StringOptionsWithoutImporter#syntax
62+
pub syntax: Syntax,
7563
/// https://sass-lang.com/documentation/js-api/interfaces/StringOptionsWithImporter#url
7664
pub url: Url,
7765
}
@@ -93,7 +81,7 @@ pub trait Importer: Debug {
9381
) -> Result<Option<Url>>;
9482

9583
/// https://sass-lang.com/documentation/js-api/interfaces/Importer#load
96-
async fn load(&self, canonicalUrl: &Url) -> Result<Option<ImporterResult>>;
84+
async fn load(&self, canonical_url: &Url) -> Result<Option<ImporterResult>>;
9785
}
9886

9987
pub struct ImporterOptions {
@@ -162,6 +150,12 @@ impl Display for Exception {
162150
}
163151
}
164152

153+
impl From<CompileFailure> for Exception {
154+
fn from(failure: CompileFailure) -> Self {
155+
Self::new(failure)
156+
}
157+
}
158+
165159
/// https://sass-lang.com/documentation/js-api/interfaces/ImporterResult
166160
pub struct ImporterResult {
167161
/// https://sass-lang.com/documentation/js-api/interfaces/ImporterResult#contents
@@ -183,6 +177,20 @@ pub struct CompileResult {
183177
pub source_map: Option<String>,
184178
}
185179

180+
impl From<CompileSuccess> for CompileResult {
181+
fn from(s: CompileSuccess) -> Self {
182+
Self {
183+
css: s.css,
184+
loaded_urls: s.loaded_urls,
185+
source_map: if s.source_map.is_empty() {
186+
None
187+
} else {
188+
Some(s.source_map)
189+
},
190+
}
191+
}
192+
}
193+
186194
pub type SassLogger = Box<dyn Logger>;
187195

188196
/// https://sass-lang.com/documentation/js-api/interfaces/Logger

src/compile.rs

Lines changed: 51 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,63 @@
11
use crate::{
2-
api::{CompileResult, Exception, Result, StringOptions},
2+
api::{CompileResult, Exception, Options, Result, StringOptions},
33
compiler::Embedded,
44
compiler_path,
55
importer_registry::ImporterRegistry,
66
logger_registry::LoggerRegistry,
77
pb::{inbound_message::CompileRequest, outbound_message::compile_response},
8+
Error,
89
};
910

11+
pub async fn compile(
12+
path: String,
13+
mut options: Options,
14+
) -> Result<CompileResult> {
15+
let mut importers =
16+
ImporterRegistry::new(options.importers.take(), options.load_paths.take());
17+
let logger = LoggerRegistry::new(options.logger.take());
18+
19+
let request = CompileRequest::with_path(path, &mut importers, &options);
20+
let embedded = Embedded::new(compiler_path::compiler_path().unwrap());
21+
let response = embedded.compile(request, &importers, &logger).await?;
22+
23+
let res = response.result.ok_or_else(|| {
24+
Error::Compile(
25+
"OutboundMessage.CompileResponse.result is not set".to_string(),
26+
)
27+
})?;
28+
match res {
29+
compile_response::Result::Success(success) => Ok(success.into()),
30+
compile_response::Result::Failure(failure) => {
31+
Err(Exception::new(failure).into())
32+
}
33+
}
34+
}
35+
1036
pub async fn compile_string(
1137
source: String,
12-
mut options: StringOptions,
38+
mut options: Options,
39+
string_options: StringOptions,
1340
) -> Result<CompileResult> {
14-
let base = options.get_options_mut();
1541
let mut importers =
16-
ImporterRegistry::new(base.importers.take(), base.load_paths.take());
17-
let logger = LoggerRegistry::new(base.logger.take());
18-
19-
let request = CompileRequest::with_string(source, &mut importers, options);
20-
let mut embedded = Embedded::new(compiler_path::compiler_path().unwrap());
21-
let response = embedded
22-
.send_compile_request(request, importers, logger)
23-
.await?;
24-
match response.result.unwrap() {
25-
compile_response::Result::Success(success) => {
26-
let css = success.css;
27-
let source_map = success.source_map;
28-
let loaded_urls = success.loaded_urls;
29-
Ok(CompileResult {
30-
css,
31-
source_map: Some(source_map),
32-
loaded_urls,
33-
})
34-
}
42+
ImporterRegistry::new(options.importers.take(), options.load_paths.take());
43+
let logger = LoggerRegistry::new(options.logger.take());
44+
45+
let request = CompileRequest::with_string(
46+
source,
47+
&mut importers,
48+
&options,
49+
string_options,
50+
);
51+
let embedded = Embedded::new(compiler_path::compiler_path().unwrap());
52+
let response = embedded.compile(request, &importers, &logger).await?;
53+
54+
let res = response.result.ok_or_else(|| {
55+
Error::Compile(
56+
"OutboundMessage.CompileResponse.result is not set".to_string(),
57+
)
58+
})?;
59+
match res {
60+
compile_response::Result::Success(success) => Ok(success.into()),
3561
compile_response::Result::Failure(failure) => {
3662
Err(Exception::new(failure).into())
3763
}
@@ -40,15 +66,16 @@ pub async fn compile_string(
4066

4167
#[cfg(test)]
4268
mod tests {
43-
use crate::api::StringOptionsWithoutImporter;
69+
use crate::api::WithoutImporter;
4470

4571
use super::*;
4672

4773
#[tokio::test]
4874
async fn test_compile_string() {
4975
let res = compile_string(
5076
".foo {a: b}".to_string(),
51-
StringOptions::WithoutImporter(StringOptionsWithoutImporter::default()),
77+
Options::default(),
78+
StringOptions::WithoutImporter(WithoutImporter::default()),
5279
)
5380
.await
5481
.unwrap();

src/compiler.rs

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::{ffi::OsStr, process::Stdio};
22

3-
use futures::{future, pin_mut, StreamExt, TryStreamExt};
3+
use futures::{future, pin_mut, stream, StreamExt, TryStreamExt};
44
use prost::Message;
55
use tokio::{
66
io::BufReader,
@@ -11,48 +11,61 @@ use tokio_util::io::ReaderStream;
1111
use crate::{
1212
dispatcher::Dispatcher,
1313
importer_registry::ImporterRegistry,
14+
logger_registry::LoggerRegistry,
15+
packet_transformer::PacketTransformer,
1416
pb::{
1517
inbound_message::CompileRequest, outbound_message::CompileResponse,
1618
OutboundMessage,
1719
},
18-
Error, Result, logger_registry::LoggerRegistry,
20+
Error, Result,
1921
};
2022

2123
pub struct Embedded {
22-
stdout: Option<ChildStdout>,
23-
stdin: Option<ChildStdin>,
24+
stdout: ChildStdout,
25+
stdin: ChildStdin,
2426
}
2527

2628
impl Embedded {
2729
pub fn new(program: impl AsRef<OsStr>) -> Self {
28-
let mut child = Command::new(program)
30+
let child = Command::new(program)
2931
.stdin(Stdio::piped())
3032
.stdout(Stdio::piped())
3133
.stderr(Stdio::piped())
3234
.spawn()
3335
.unwrap();
3436

3537
Self {
36-
stdout: child.stdout.take(),
37-
stdin: child.stdin.take(),
38+
stdout: child.stdout.unwrap(),
39+
stdin: child.stdin.unwrap(),
3840
}
3941
}
4042

41-
pub async fn send_compile_request(
42-
&mut self,
43+
pub async fn compile(
44+
self,
4345
request: CompileRequest,
44-
importers: ImporterRegistry,
45-
logger: LoggerRegistry,
46+
importers: &ImporterRegistry,
47+
logger: &LoggerRegistry,
4648
) -> Result<CompileResponse> {
47-
let stdin = self.stdin.take().unwrap();
48-
let mut dispatcher = Dispatcher::new(stdin, importers, logger);
49+
let stdin = self.stdin;
50+
let mut dispatcher = Dispatcher::new(stdin, &importers, &logger);
4951
dispatcher.send_compile_request(request).await?;
5052

51-
let stdout = self.stdout.take().unwrap();
53+
let stdout = self.stdout;
54+
let mut pt = PacketTransformer::default();
55+
// TODO: refactor these shits
5256
let reader = ReaderStream::new(BufReader::new(stdout))
5357
.map_err(|io_err| Error::from(io_err))
58+
.flat_map(|res| match res {
59+
Ok(buf) => stream::iter(
60+
pt.decode(buf.to_vec())
61+
.into_iter()
62+
.map(|b| Ok(b))
63+
.collect::<Vec<Result<Vec<u8>>>>(),
64+
),
65+
Err(e) => stream::iter(vec![Err(e)]),
66+
})
5467
.and_then(|buf| {
55-
let outbound = OutboundMessage::decode_length_delimited(buf).unwrap();
68+
let outbound = OutboundMessage::decode(buf.as_ref()).unwrap();
5669
future::ok(outbound.message.unwrap())
5770
})
5871
.try_filter_map(|m| async {

0 commit comments

Comments
 (0)