2021-01-12 02:13:41 +09:00
// Copyright 2018-2021 the Deno authors. All rights reserved. MIT license.
2020-09-06 02:34:02 +02:00
2021-10-11 08:26:22 +11:00
use crate ::cache ;
use crate ::config_file ::IgnoredCompilerOptions ;
use crate ::diagnostics ::Diagnostics ;
use crate ::emit ;
use crate ::errors ::get_error_class_name ;
2021-09-24 11:10:42 -04:00
use crate ::proc_state ::ProcState ;
2021-10-11 08:26:22 +11:00
use crate ::resolver ::ImportMapResolver ;
2020-11-02 13:51:56 +11:00
2021-10-11 08:26:22 +11:00
use deno_core ::error ::custom_error ;
2021-01-01 08:43:54 +11:00
use deno_core ::error ::generic_error ;
2020-09-14 18:48:57 +02:00
use deno_core ::error ::AnyError ;
2020-11-02 13:51:56 +11:00
use deno_core ::error ::Context ;
2021-02-17 13:47:18 -05:00
use deno_core ::resolve_url_or_path ;
2021-10-11 08:26:22 +11:00
use deno_core ::serde_json ;
2020-09-21 18:36:37 +02:00
use deno_core ::serde_json ::Value ;
2021-10-11 08:26:22 +11:00
use deno_core ::ModuleSpecifier ;
2020-09-10 09:57:45 -04:00
use deno_core ::OpState ;
2021-10-11 08:26:22 +11:00
use deno_graph ;
2020-12-30 15:17:17 +11:00
use deno_runtime ::permissions ::Permissions ;
2021-09-11 03:38:24 +02:00
use import_map ::ImportMap ;
2020-09-16 12:43:08 -04:00
use serde ::Deserialize ;
2021-10-05 22:38:27 +02:00
use serde ::Serialize ;
2020-09-10 09:57:45 -04:00
use std ::cell ::RefCell ;
2020-01-21 17:50:06 +01:00
use std ::collections ::HashMap ;
2021-10-11 08:26:22 +11:00
use std ::collections ::HashSet ;
2020-08-18 18:30:13 +02:00
use std ::rc ::Rc ;
2020-12-30 15:17:17 +11:00
use std ::sync ::Arc ;
2020-01-21 17:50:06 +01:00
2020-09-10 09:57:45 -04:00
pub fn init ( rt : & mut deno_core ::JsRuntime ) {
2021-04-12 21:55:05 +02:00
super ::reg_async ( rt , " op_emit " , op_emit ) ;
2020-01-21 17:50:06 +01:00
}
2021-01-01 08:43:54 +11:00
#[ derive(Debug, Deserialize) ]
enum RuntimeBundleType {
2021-04-25 21:54:57 +01:00
#[ serde(rename = " module " ) ]
Module ,
#[ serde(rename = " classic " ) ]
Classic ,
2021-01-01 08:43:54 +11:00
}
2021-10-11 08:26:22 +11:00
impl < ' a > From < & ' a RuntimeBundleType > for emit ::BundleType {
fn from ( bundle_type : & ' a RuntimeBundleType ) -> Self {
match bundle_type {
RuntimeBundleType ::Classic = > Self ::Classic ,
RuntimeBundleType ::Module = > Self ::Module ,
}
}
}
2021-01-01 08:43:54 +11:00
#[ derive(Debug, Deserialize) ]
2020-01-21 17:50:06 +01:00
#[ serde(rename_all = " camelCase " ) ]
2021-01-01 08:43:54 +11:00
struct EmitArgs {
bundle : Option < RuntimeBundleType > ,
check : Option < bool > ,
compiler_options : Option < HashMap < String , Value > > ,
import_map : Option < Value > ,
import_map_path : Option < String > ,
root_specifier : String ,
2021-09-07 10:39:32 -04:00
sources : Option < HashMap < String , Arc < String > > > ,
2020-01-21 17:50:06 +01:00
}
2021-10-05 22:38:27 +02:00
#[ derive(Serialize) ]
#[ serde(rename_all = " camelCase " ) ]
struct EmitResult {
2021-10-11 08:26:22 +11:00
diagnostics : Diagnostics ,
2021-10-05 22:38:27 +02:00
files : HashMap < String , String > ,
2021-10-11 08:26:22 +11:00
#[ serde(rename = " ignoredOptions " ) ]
maybe_ignored_options : Option < IgnoredCompilerOptions > ,
stats : emit ::Stats ,
}
fn to_maybe_imports (
referrer : & ModuleSpecifier ,
maybe_options : Option < & HashMap < String , Value > > ,
) -> Option < Vec < ( ModuleSpecifier , Vec < String > ) > > {
let options = maybe_options . as_ref ( ) ? ;
let types_value = options . get ( " types " ) ? ;
let types : Vec < String > = serde_json ::from_value ( types_value . clone ( ) ) . ok ( ) ? ;
Some ( vec! [ ( referrer . clone ( ) , types ) ] )
2021-10-05 22:38:27 +02:00
}
2021-01-01 08:43:54 +11:00
async fn op_emit (
2020-09-10 09:57:45 -04:00
state : Rc < RefCell < OpState > > ,
2021-10-05 22:38:27 +02:00
args : EmitArgs ,
2021-05-08 14:37:42 +02:00
_ : ( ) ,
2021-10-05 22:38:27 +02:00
) -> Result < EmitResult , AnyError > {
2021-01-01 08:43:54 +11:00
deno_runtime ::ops ::check_unstable2 ( & state , " Deno.emit " ) ;
2021-01-29 10:33:58 +09:00
let root_specifier = args . root_specifier ;
2021-10-11 08:26:22 +11:00
let state = state . borrow ( ) ;
let ps = state . borrow ::< ProcState > ( ) ;
let mut runtime_permissions = { state . borrow ::< Permissions > ( ) . clone ( ) } ;
let mut cache : Box < dyn cache ::CacherLoader > =
if let Some ( sources ) = & args . sources {
Box ::new ( cache ::MemoryCacher ::new ( sources . clone ( ) ) )
2020-11-02 13:51:56 +11:00
} else {
2021-10-11 08:26:22 +11:00
Box ::new ( cache ::FetchCacher ::new (
ps . dir . gen_cache . clone ( ) ,
ps . file_fetcher . clone ( ) ,
2021-02-17 14:32:57 +01:00
runtime_permissions . clone ( ) ,
2021-05-17 09:44:38 +02:00
runtime_permissions . clone ( ) ,
2021-10-11 08:26:22 +11:00
) )
2020-11-02 13:51:56 +11:00
} ;
2021-01-01 08:43:54 +11:00
let maybe_import_map = if let Some ( import_map_str ) = args . import_map_path {
2021-02-17 13:47:18 -05:00
let import_map_specifier = resolve_url_or_path ( & import_map_str )
. context ( format! ( " Bad URL ( \" {} \" ) for import map. " , import_map_str ) ) ? ;
2021-01-01 08:43:54 +11:00
let import_map = if let Some ( value ) = args . import_map {
2021-02-17 13:47:18 -05:00
ImportMap ::from_json ( import_map_specifier . as_str ( ) , & value . to_string ( ) ) ?
2021-01-01 08:43:54 +11:00
} else {
2021-09-24 11:10:42 -04:00
let file = ps
2021-02-17 14:32:57 +01:00
. file_fetcher
2021-04-12 04:15:43 +02:00
. fetch ( & import_map_specifier , & mut runtime_permissions )
2021-05-04 17:57:20 +05:30
. await
. map_err ( | e | {
generic_error ( format! (
" Unable to load '{}' import map: {} " ,
import_map_specifier , e
) )
} ) ? ;
2021-02-17 14:32:57 +01:00
ImportMap ::from_json ( import_map_specifier . as_str ( ) , & file . source ) ?
2021-01-01 08:43:54 +11:00
} ;
Some ( import_map )
} else if args . import_map . is_some ( ) {
return Err ( generic_error ( " An importMap was specified, but no importMapPath was provided, which is required. " ) ) ;
2020-08-28 17:08:24 +02:00
} else {
2021-01-01 08:43:54 +11:00
None
} ;
2021-10-11 08:26:22 +11:00
let roots = vec! [ resolve_url_or_path ( & root_specifier ) ? ] ;
let maybe_imports =
to_maybe_imports ( & roots [ 0 ] , args . compiler_options . as_ref ( ) ) ;
let maybe_resolver = maybe_import_map . as_ref ( ) . map ( ImportMapResolver ::new ) ;
let graph = Arc ::new (
deno_graph ::create_graph (
roots ,
true ,
maybe_imports ,
cache . as_mut_loader ( ) ,
maybe_resolver . as_ref ( ) . map ( | r | r . as_resolver ( ) ) ,
None ,
None ,
)
. await ,
) ;
// There are certain graph errors that we want to return as an error of an op,
// versus something that gets returned as a diagnostic of the op, this is
// handled here.
if let Err ( err ) = graph . valid ( ) {
let err : AnyError = err . into ( ) ;
if get_error_class_name ( & err ) = = " PermissionDenied " {
return Err ( err ) ;
}
}
let check = args . check . unwrap_or ( true ) ;
2021-09-24 11:10:42 -04:00
let debug = ps . flags . log_level = = Some ( log ::Level ::Debug ) ;
2021-10-11 08:26:22 +11:00
let tsc_emit = check & & args . bundle . is_none ( ) ;
let ( ts_config , maybe_ignored_options ) = emit ::get_ts_config (
emit ::ConfigType ::RuntimeEmit { tsc_emit } ,
None ,
args . compiler_options . as_ref ( ) ,
) ? ;
let ( files , mut diagnostics , stats ) = if check & & args . bundle . is_none ( ) {
let ( diagnostics , stats ) = if args . sources . is_none ( )
& & emit ::valid_emit (
graph . as_ref ( ) ,
cache . as_cacher ( ) ,
& ts_config ,
ps . flags . reload ,
& HashSet ::default ( ) ,
) {
log ::debug! (
" cache is valid for \" {} \" , skipping check/emit " ,
root_specifier
) ;
( Diagnostics ::default ( ) , emit ::Stats ::default ( ) )
} else {
let emit_result = emit ::check_and_maybe_emit (
graph . clone ( ) ,
cache . as_mut_cacher ( ) ,
emit ::CheckOptions {
debug ,
emit_with_diagnostics : true ,
maybe_config_specifier : None ,
ts_config ,
} ,
) ? ;
( emit_result . diagnostics , emit_result . stats )
} ;
let files = emit ::to_file_map ( graph . as_ref ( ) , cache . as_mut_cacher ( ) ) ;
( files , diagnostics , stats )
} else if let Some ( bundle ) = & args . bundle {
let ( diagnostics , stats ) = if check {
if ts_config . get_declaration ( ) {
return Err ( custom_error ( " TypeError " , " The bundle option is set, but the compiler option of `declaration` is true which is not currently supported. " ) ) ;
}
let emit_result = emit ::check_and_maybe_emit (
graph . clone ( ) ,
cache . as_mut_cacher ( ) ,
emit ::CheckOptions {
debug ,
emit_with_diagnostics : true ,
maybe_config_specifier : None ,
ts_config : ts_config . clone ( ) ,
} ,
) ? ;
( emit_result . diagnostics , emit_result . stats )
} else {
( Diagnostics ::default ( ) , Default ::default ( ) )
} ;
let ( emit , maybe_map ) = emit ::bundle (
graph . as_ref ( ) ,
emit ::BundleOptions {
bundle_type : bundle . into ( ) ,
ts_config ,
} ,
) ? ;
let mut files = HashMap ::new ( ) ;
files . insert ( " deno:///bundle.js " . to_string ( ) , emit ) ;
if let Some ( map ) = maybe_map {
files . insert ( " deno:///bundle.js.map " . to_string ( ) , map ) ;
}
( files , diagnostics , stats )
} else {
if ts_config . get_declaration ( ) {
return Err ( custom_error ( " TypeError " , " The option of `check` is false, but the compiler option of `declaration` is true which is not currently supported. " ) ) ;
}
let emit_result = emit ::emit (
graph . as_ref ( ) ,
cache . as_mut_cacher ( ) ,
emit ::EmitOptions {
reload : ps . flags . reload ,
ts_config ,
reload_exclusions : HashSet ::default ( ) ,
} ,
) ? ;
let files = emit ::to_file_map ( graph . as_ref ( ) , cache . as_mut_cacher ( ) ) ;
( files , emit_result . diagnostics , emit_result . stats )
} ;
// we want to add any errors that were returned as an `Err` earlier by adding
// them to the diagnostics.
diagnostics . extend_graph_errors ( graph . errors ( ) ) ;
2020-11-02 13:51:56 +11:00
2021-10-05 22:38:27 +02:00
Ok ( EmitResult {
2021-10-11 08:26:22 +11:00
diagnostics ,
2021-10-05 22:38:27 +02:00
files ,
2021-10-11 08:26:22 +11:00
maybe_ignored_options ,
stats ,
2021-10-05 22:38:27 +02:00
} )
2020-01-21 17:50:06 +01:00
}