profile
viewpoint

Ask questionsUsing swc for embedded-js parsing

Hello: I'm trying to build a parser for embedded JS, where the JS code exists within some other text. Currently, I'm using it as suggested in the source code:

let cm = Arc::new(SourceMap::new(FilePathMapping::empty()));
let fm = cm.new_source_file(
    FileName::Custom(fname),
    source,
);

However, I am unable to get the error reporting, and the generated source map to reflect the actual lines where the source is. Is there a way to get that done? If this functionality is not available, I would be willing to help with adding this functionality.

PS: Kudos on the elegant design of the parser; especially appreciate the Fold trait.

swc-project/swc

Answer questions rmanoka

@kdy1 I checked out TRACK_DIAGNOSTICS; unfortunately, it does not seem to solve my issue. In the crate, it is only called during emit_db which means it will anyway print the error messages (with incorrect line numbers when used with embedded-js use case described above).

One hack that works is to take the DiagnosticBuilder returned by the parser in case of error; then manually modify each of the primary_spans. Here is a snippet to do so:

let cm = Arc::new(SourceMap::new(FilePathMapping::empty()));
let handler = Handler::with_tty_emitter(ColorConfig::Auto, true, false, Some(cm.clone()));      
let session = Session { handler: &handler };
       
// The real file (with embedded js code)                                                            
let true_fm = cm.new_source_file(                           
    FileName::Custom("true.js".into()),                     
    "Some other text\nfunction foo {}".into(),              
);

// The byte offset where js code begins (provided by outer parser)
let byte_offset = BytePos(16);                              

// The js source                                                            
let fm = cm.new_source_file(                                
    FileName::Custom("test.js".into()),                     
    "function foo {}".into(),                               
);                                                          
                                                            
let mut parser = Parser::new(                               
    session,                                                
    Syntax::Es(Default::default()),                         
    SourceFileInput::from(&*fm),                            
    None, // Disable comments                               
);                                                          
                                                            
let module = parser                                         
    .parse_module()                                         
    .map_err(|mut e| {                                      
        let m_span = &e.span;                               
        let mut out_spans = vec![];                         
                                                            
        for span in m_span.primary_spans() {                
            let data = span.data();                         
            let mut lo = data.lo;                           
            let mut hi = data.hi;                           
                                                            
            lo = lo - fm.start_pos + true_fm.start_pos + byt
            hi = hi - fm.start_pos + true_fm.start_pos + byt
                                                            
            let new_span = Span::new(lo, hi, data.ctxt);    
            out_spans.push(new_span);                       
        }                                                   
                                                            
        e.set_span(out_spans);                              
        e.emit();                                           
                                                            
        ()                                                  
    })                                                      
    .expect("failed to parse module");

With this code, it gives me the nice error messages that the crate already produces, but with correct line numbers:

error: Expected LParen, got Some(LBrace)
 --> <true.js>:2:14
  |
2 | function foo {}
  |              ^

Regarding your reply above:

Yes, but I prefer returning Vec<Error>.

The current error messages printed by the crate are quite informative, and neat; some way to still print these even with Vec<Error> would be great.

Also, all this still doesn't help with the output source-map that is generated. That would also have to be transformed manually (waiting on #349 to try this). Overall, I am okay with this for an interim solution. Pls. feel free to close this issue if you would like to.

useful!
source:https://uonfu.com/
Github User Rank List