@@ -4,6 +4,7 @@ use sqlparser::dialect::{
44 GenericDialect , HiveDialect , MsSqlDialect , MySqlDialect , OracleDialect , PostgreSqlDialect ,
55 RedshiftSqlDialect , SQLiteDialect , SnowflakeDialect ,
66} ;
7+ use sqlparser:: ast:: comments:: { Comment as SqlComment , CommentWithSpan } ;
78use sqlparser:: parser:: Parser ;
89use wasm_bindgen:: prelude:: * ;
910
@@ -163,6 +164,69 @@ pub fn get_supported_dialects() -> JsValue {
163164 serde_wasm_bindgen:: to_value ( & dialects) . unwrap ( )
164165}
165166
167+ /// A serializable source comment
168+ #[ derive( Serialize ) ]
169+ #[ serde( rename_all = "camelCase" ) ]
170+ pub struct SerializedComment {
171+ pub comment_type : String ,
172+ pub content : String ,
173+ #[ serde( skip_serializing_if = "Option::is_none" ) ]
174+ pub prefix : Option < String > ,
175+ pub start_line : u64 ,
176+ pub start_column : u64 ,
177+ pub end_line : u64 ,
178+ pub end_column : u64 ,
179+ }
180+
181+ impl From < & CommentWithSpan > for SerializedComment {
182+ fn from ( c : & CommentWithSpan ) -> Self {
183+ let ( comment_type, content, prefix) = match & c. comment {
184+ SqlComment :: SingleLine { content, prefix } => {
185+ ( "singleLine" . to_string ( ) , content. clone ( ) , Some ( prefix. clone ( ) ) )
186+ }
187+ SqlComment :: MultiLine ( content) => {
188+ ( "multiLine" . to_string ( ) , content. clone ( ) , None )
189+ }
190+ } ;
191+ SerializedComment {
192+ comment_type, content, prefix,
193+ start_line : c. span . start . line ,
194+ start_column : c. span . start . column ,
195+ end_line : c. span . end . line ,
196+ end_column : c. span . end . column ,
197+ }
198+ }
199+ }
200+
201+ /// Parse SQL and return both AST and source comments
202+ #[ wasm_bindgen]
203+ pub fn parse_sql_with_comments ( dialect : & str , sql : & str ) -> Result < JsValue , JsValue > {
204+ let dialect_impl = get_dialect ( dialect) ;
205+ let ( statements, comments) =
206+ Parser :: parse_sql_with_comments ( dialect_impl. as_ref ( ) , sql) . map_err ( |e| {
207+ let error = ParseError {
208+ message : e. to_string ( ) ,
209+ line : None ,
210+ column : None ,
211+ } ;
212+ serde_wasm_bindgen:: to_value ( & error) . unwrap_or ( JsValue :: from_str ( & e. to_string ( ) ) )
213+ } ) ?;
214+
215+ let comments_vec: Vec < CommentWithSpan > = comments. into ( ) ;
216+ let serialized_comments: Vec < SerializedComment > =
217+ comments_vec. iter ( ) . map ( SerializedComment :: from) . collect ( ) ;
218+
219+ // Build JS object manually to avoid double-serialization
220+ let obj = js_sys:: Object :: new ( ) ;
221+ let stmts_val = serde_wasm_bindgen:: to_value ( & statements)
222+ . map_err ( |e| JsValue :: from_str ( & format ! ( "Serialization error: {}" , e) ) ) ?;
223+ let comments_val = serde_wasm_bindgen:: to_value ( & serialized_comments)
224+ . map_err ( |e| JsValue :: from_str ( & format ! ( "Serialization error: {}" , e) ) ) ?;
225+ js_sys:: Reflect :: set ( & obj, & "statements" . into ( ) , & stmts_val) . unwrap ( ) ;
226+ js_sys:: Reflect :: set ( & obj, & "comments" . into ( ) , & comments_val) . unwrap ( ) ;
227+ Ok ( obj. into ( ) )
228+ }
229+
166230/// Validate SQL syntax without returning the full AST
167231#[ wasm_bindgen]
168232pub fn validate_sql ( dialect : & str , sql : & str ) -> Result < bool , JsValue > {
0 commit comments