@@ -30,7 +30,8 @@ use wasm_bindgen::prelude::*;
3030#[ wasm_bindgen]
3131pub fn transform ( config_val : JsValue ) -> Result < JsValue , JsValue > {
3232 let config: Config = from_value ( config_val) . map_err ( JsValue :: from) ?;
33- let res = compile ( config) . unwrap ( ) ;
33+ let code = unsafe { std:: str:: from_utf8_unchecked ( & config. code ) } ;
34+ let res = compile ( code, & config) . unwrap ( ) ;
3435 let serializer = Serializer :: new ( ) . serialize_maps_as_objects ( true ) ;
3536 res. serialize ( & serializer) . map_err ( JsValue :: from)
3637}
@@ -65,8 +66,38 @@ struct TransformResult {
6566fn transform ( ctx : CallContext ) -> napi:: Result < JsUnknown > {
6667 let opts = ctx. get :: < JsObject > ( 0 ) ?;
6768 let config: Config = ctx. env . from_js_value ( opts) ?;
68- let res = compile ( config) . unwrap ( ) ;
69- ctx. env . to_js_value ( & res)
69+ let code = unsafe { std:: str:: from_utf8_unchecked ( & config. code ) } ;
70+ let res = {
71+ compile ( code, & config)
72+ } ;
73+
74+ match res {
75+ Ok ( res) => ctx. env . to_js_value ( & res) ,
76+ Err ( err) => {
77+ match & err {
78+ CompileError :: ParseError ( e) => {
79+ // Generate an error with location information.
80+ let syntax_error = ctx. env . get_global ( ) ?
81+ . get_named_property :: < napi:: JsFunction > ( "SyntaxError" ) ?;
82+ let reason = ctx. env . create_string_from_std ( err. reason ( ) ) ?;
83+ let line = ctx. env . create_int32 ( ( e. location . line + 1 ) as i32 ) ?;
84+ let col = ctx. env . create_int32 ( e. location . column as i32 ) ?;
85+ let mut obj = syntax_error. new ( & [ reason] ) ?;
86+ let filename = ctx. env . create_string_from_std ( config. filename ) ?;
87+ obj. set_named_property ( "fileName" , filename) ?;
88+ let source = ctx. env . create_string ( code) ?;
89+ obj. set_named_property ( "source" , source) ?;
90+ let mut loc = ctx. env . create_object ( ) ?;
91+ loc. set_named_property ( "line" , line) ?;
92+ loc. set_named_property ( "column" , col) ?;
93+ obj. set_named_property ( "loc" , loc) ?;
94+ ctx. env . throw ( obj) ?;
95+ Ok ( ctx. env . get_undefined ( ) ?. into_unknown ( ) )
96+ }
97+ _ => Err ( err. into ( ) )
98+ }
99+ }
100+ }
70101}
71102
72103#[ cfg( not( target_arch = "wasm32" ) ) ]
@@ -89,16 +120,15 @@ struct Config {
89120 pub source_map : Option < bool >
90121}
91122
92- fn compile ( config : Config ) -> Result < TransformResult , ( ) > {
93- let code = unsafe { std:: str:: from_utf8_unchecked ( & config. code ) } ;
94- let mut stylesheet = StyleSheet :: parse ( config. filename , code) ;
123+ fn compile < ' i > ( code : & ' i str , config : & Config ) -> Result < TransformResult , CompileError < ' i > > {
124+ let mut stylesheet = StyleSheet :: parse ( config. filename . clone ( ) , & code) ?;
95125 stylesheet. minify ( config. targets ) ; // TODO: should this be conditional?
96- let ( res, source_map) = stylesheet. to_css ( config. minify . unwrap_or ( false ) , config. source_map . unwrap_or ( false ) ) . map_err ( |_| ( ) ) ?;
126+ let ( res, source_map) = stylesheet. to_css ( config. minify . unwrap_or ( false ) , config. source_map . unwrap_or ( false ) ) ?;
97127
98128 let map = if let Some ( mut source_map) = source_map {
99- source_map. set_source_content ( 0 , code) . map_err ( |_| ( ) ) ?;
129+ source_map. set_source_content ( 0 , code) ?;
100130 let mut vlq_output: Vec < u8 > = Vec :: new ( ) ;
101- source_map. write_vlq ( & mut vlq_output) . map_err ( |_| ( ) ) ?;
131+ source_map. write_vlq ( & mut vlq_output) ?;
102132
103133 let sm = SourceMapJson {
104134 version : 3 ,
@@ -119,27 +149,84 @@ fn compile(config: Config) -> Result<TransformResult, ()> {
119149 } )
120150}
121151
152+ enum CompileError < ' i > {
153+ ParseError ( cssparser:: ParseError < ' i , ( ) > ) ,
154+ PrinterError ,
155+ SourceMapError ( parcel_sourcemap:: SourceMapError )
156+ }
157+
158+ impl < ' i > CompileError < ' i > {
159+ fn reason ( & self ) -> String {
160+ match self {
161+ CompileError :: ParseError ( e) => {
162+ match & e. kind {
163+ cssparser:: ParseErrorKind :: Basic ( b) => {
164+ use cssparser:: BasicParseErrorKind :: * ;
165+ match b {
166+ AtRuleBodyInvalid => "Invalid at rule body" . into ( ) ,
167+ EndOfInput => "Unexpected end of input" . into ( ) ,
168+ AtRuleInvalid ( name) => format ! ( "Unknown at rule: @{}" , name) ,
169+ QualifiedRuleInvalid => "Invalid qualified rule" . into ( ) ,
170+ UnexpectedToken ( token) => format ! ( "Unexpected token {:?}" , token)
171+ }
172+ } ,
173+ _ => "Unknown error" . into ( )
174+ }
175+ }
176+ CompileError :: PrinterError => "Printer error" . into ( ) ,
177+ _ => "Unknown error" . into ( )
178+ }
179+ }
180+ }
181+
182+ impl < ' i > From < cssparser:: ParseError < ' i , ( ) > > for CompileError < ' i > {
183+ fn from ( e : cssparser:: ParseError < ' i , ( ) > ) -> CompileError < ' i > {
184+ CompileError :: ParseError ( e)
185+ }
186+ }
187+
188+ impl < ' i > From < std:: fmt:: Error > for CompileError < ' i > {
189+ fn from ( _: std:: fmt:: Error ) -> CompileError < ' i > {
190+ CompileError :: PrinterError
191+ }
192+ }
193+
194+ impl < ' i > From < parcel_sourcemap:: SourceMapError > for CompileError < ' i > {
195+ fn from ( e : parcel_sourcemap:: SourceMapError ) -> CompileError < ' i > {
196+ CompileError :: SourceMapError ( e)
197+ }
198+ }
199+
200+ impl < ' i > From < CompileError < ' i > > for napi:: Error {
201+ fn from ( e : CompileError ) -> napi:: Error {
202+ match e {
203+ CompileError :: SourceMapError ( e) => e. into ( ) ,
204+ _ => napi:: Error :: new ( napi:: Status :: GenericFailure , e. reason ( ) )
205+ }
206+ }
207+ }
208+
122209#[ cfg( test) ]
123210mod tests {
124211 use super :: * ;
125212 use indoc:: indoc;
126213
127214 fn test ( source : & str , expected : & str ) {
128- let mut stylesheet = StyleSheet :: parse ( "test.css" . into ( ) , source) ;
215+ let mut stylesheet = StyleSheet :: parse ( "test.css" . into ( ) , source) . unwrap ( ) ;
129216 stylesheet. minify ( None ) ;
130217 let ( res, _) = stylesheet. to_css ( false , false ) . unwrap ( ) ;
131218 assert_eq ! ( res, expected) ;
132219 }
133220
134221 fn minify_test ( source : & str , expected : & str ) {
135- let mut stylesheet = StyleSheet :: parse ( "test.css" . into ( ) , source) ;
222+ let mut stylesheet = StyleSheet :: parse ( "test.css" . into ( ) , source) . unwrap ( ) ;
136223 stylesheet. minify ( None ) ;
137224 let ( res, _) = stylesheet. to_css ( true , false ) . unwrap ( ) ;
138225 assert_eq ! ( res, expected) ;
139226 }
140227
141228 fn prefix_test ( source : & str , expected : & str , targets : Browsers ) {
142- let mut stylesheet = StyleSheet :: parse ( "test.css" . into ( ) , source) ;
229+ let mut stylesheet = StyleSheet :: parse ( "test.css" . into ( ) , source) . unwrap ( ) ;
143230 stylesheet. minify ( Some ( targets) ) ;
144231 let ( res, _) = stylesheet. to_css ( false , false ) . unwrap ( ) ;
145232 assert_eq ! ( res, expected) ;
0 commit comments