Skip to content

Commit

Permalink
fix: native default jsxImportSource resolution
Browse files Browse the repository at this point in the history
This commit adds support for natively resolving a default
jsxImportSource specified in a config file per module.
  • Loading branch information
lucacasonato committed Aug 23, 2022
1 parent c5393a1 commit 15f3eaf
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 16 deletions.
45 changes: 33 additions & 12 deletions src/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::analyzer::ModuleAnalyzer;
use crate::analyzer::ModuleInfo;
use crate::analyzer::PositionRange;
use crate::analyzer::TypeScriptReference;
use crate::SpecifierWithRange;

use crate::module_specifier::resolve_import;
use crate::module_specifier::ModuleSpecifier;
Expand Down Expand Up @@ -1342,18 +1343,38 @@ pub(crate) fn parse_module_from_module_info(
}
}

// Analyze any JSX Import Source pragma
if let Some(import_source) = module_info.jsx_import_source {
let jsx_import_source_module = maybe_resolver
.map(|r| r.jsx_import_source_module())
.unwrap_or(DEFAULT_JSX_IMPORT_SOURCE_MODULE);
let specifier =
format!("{}/{}", import_source.text, jsx_import_source_module);
let range =
Range::from_position_range(&module.specifier, &import_source.range);
let resolved_dependency = resolve(&specifier, &range, maybe_resolver);
let dep = module.dependencies.entry(specifier).or_default();
dep.maybe_code = resolved_dependency;
// Inject the JSX import source dependency if needed. This is done as follows:
// 1. Check that the module is a JSX or TSX module.
// 2. If the module has a @jsxImportSource pragma, use that as the import
// source.
// 3. If the resolver has a default JSX import source, use that as the import
// source.
// 4. If none of the above are true, do not inject a dependency.
if matches!(media_type, MediaType::Jsx | MediaType::Tsx) {
let res = module_info.jsx_import_source.or_else(|| {
maybe_resolver.and_then(|r| {
r.default_jsx_import_source()
.map(|import_source| SpecifierWithRange {
text: import_source,
range: PositionRange {
start: Position::zeroed(),
end: Position::zeroed(),
},
})
})
});
if let Some(import_source) = res {
let jsx_import_source_module = maybe_resolver
.map(|r| r.jsx_import_source_module())
.unwrap_or(DEFAULT_JSX_IMPORT_SOURCE_MODULE);
let specifier =
format!("{}/{}", import_source.text, jsx_import_source_module);
let range =
Range::from_position_range(&module.specifier, &import_source.range);
let resolved_dependency = resolve(&specifier, &range, maybe_resolver);
let dep = module.dependencies.entry(specifier).or_default();
dep.maybe_code = resolved_dependency;
}
}

// Analyze any JSDoc type imports
Expand Down
7 changes: 7 additions & 0 deletions src/js_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,18 +145,21 @@ impl Locker for JsLocker {

#[derive(Debug)]
pub struct JsResolver {
maybe_default_jsx_import_source: Option<String>,
maybe_jsx_import_source_module: Option<String>,
maybe_resolve: Option<js_sys::Function>,
maybe_resolve_types: Option<js_sys::Function>,
}

impl JsResolver {
pub fn new(
maybe_default_jsx_import_source: Option<String>,
maybe_jsx_import_source_module: Option<String>,
maybe_resolve: Option<js_sys::Function>,
maybe_resolve_types: Option<js_sys::Function>,
) -> Self {
Self {
maybe_default_jsx_import_source,
maybe_jsx_import_source_module,
maybe_resolve,
maybe_resolve_types,
Expand All @@ -171,6 +174,10 @@ struct JsResolveTypesResponse {
}

impl Resolver for JsResolver {
fn default_jsx_import_source(&self) -> Option<String> {
self.maybe_default_jsx_import_source.clone()
}

fn jsx_import_source_module(&self) -> &str {
self
.maybe_jsx_import_source_module
Expand Down
54 changes: 50 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ cfg_if! {
pub async fn js_create_graph(
roots: JsValue,
load: js_sys::Function,
maybe_default_jsx_import_source: Option<String>,
maybe_jsx_import_source_module: Option<String>,
maybe_cache_info: Option<js_sys::Function>,
maybe_resolve: Option<js_sys::Function>,
Expand All @@ -239,8 +240,8 @@ cfg_if! {
let roots_vec: Vec<StringOrTuple> = roots.into_serde().map_err(|err| JsValue::from(js_sys::Error::new(&err.to_string())))?;
let maybe_imports_map: Option<HashMap<String, Vec<String>>> = maybe_imports.into_serde().map_err(|err| JsValue::from(js_sys::Error::new(&err.to_string())))?;
let mut loader = js_graph::JsLoader::new(load, maybe_cache_info);
let maybe_resolver = if maybe_jsx_import_source_module.is_some() || maybe_resolve.is_some() || maybe_resolve_types.is_some() {
Some(js_graph::JsResolver::new(maybe_jsx_import_source_module, maybe_resolve, maybe_resolve_types))
let maybe_resolver = if maybe_default_jsx_import_source.is_some() || maybe_jsx_import_source_module.is_some() || maybe_resolve.is_some() || maybe_resolve_types.is_some() {
Some(js_graph::JsResolver::new(maybe_default_jsx_import_source, maybe_jsx_import_source_module, maybe_resolve, maybe_resolve_types))
} else {
None
};
Expand Down Expand Up @@ -290,6 +291,7 @@ cfg_if! {
pub fn js_parse_module(
specifier: String,
maybe_headers: JsValue,
maybe_default_jsx_import_source: Option<String>,
maybe_jsx_import_source_module: Option<String>,
content: String,
maybe_kind: JsValue,
Expand All @@ -301,8 +303,8 @@ cfg_if! {
.map_err(|err| js_sys::Error::new(&err.to_string()))?;
let specifier = module_specifier::ModuleSpecifier::parse(&specifier)
.map_err(|err| js_sys::Error::new(&err.to_string()))?;
let maybe_resolver = if maybe_jsx_import_source_module.is_some() || maybe_resolve.is_some() || maybe_resolve_types.is_some() {
Some(js_graph::JsResolver::new(maybe_jsx_import_source_module, maybe_resolve, maybe_resolve_types))
let maybe_resolver = if maybe_default_jsx_import_source.is_some() || maybe_jsx_import_source_module.is_some() || maybe_resolve.is_some() || maybe_resolve_types.is_some() {
Some(js_graph::JsResolver::new(maybe_default_jsx_import_source, maybe_jsx_import_source_module, maybe_resolve, maybe_resolve_types))
} else {
None
};
Expand Down Expand Up @@ -3034,6 +3036,50 @@ export function a(a) {
assert_eq!(actual.media_type, MediaType::Tsx);
}

#[test]
fn test_default_jsx_import_source() {
#[derive(Debug)]
struct R;
impl Resolver for R {
fn default_jsx_import_source(&self) -> Option<String> {
Some("https://example.com/preact".into())
}
}

let specifier = ModuleSpecifier::parse("file:///a/test01.tsx").unwrap();
let result = parse_module(
&specifier,
None,
r#"
export function A() {
return <div>Hello Deno</div>;
}
"#
.into(),
Some(&ModuleKind::Esm),
Some(&R),
None,
);
assert!(result.is_ok());
let actual = result.unwrap();
assert_eq!(actual.dependencies.len(), 1);
let dep = actual
.dependencies
.get("https://example.com/preact/jsx-runtime")
.unwrap();
assert!(!dep.maybe_code.is_none());
if let Resolved::Ok { specifier, .. } = &dep.maybe_code {
assert_eq!(
specifier,
&ModuleSpecifier::parse("https://example.com/preact/jsx-runtime")
.unwrap()
);
}
assert!(dep.maybe_type.is_none());
assert_eq!(actual.specifier, specifier);
assert_eq!(actual.media_type, MediaType::Tsx);
}

#[test]
fn test_parse_module_with_headers() {
let specifier = ModuleSpecifier::parse("https://localhost/file").unwrap();
Expand Down
8 changes: 8 additions & 0 deletions src/source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,14 @@ impl From<Result<ModuleSpecifier, url::ParseError>> for ResolveResponse {
/// dependencies. This can be use to provide import maps and override other
/// default resolution logic used by `deno_graph`.
pub trait Resolver: fmt::Debug {
/// An optional method that returns the default JSX import source if one is
/// configured. If this method returns `Some` and a JSX file is encountered
/// that does not have an import source specified as a pragma, this import
/// source will be used instead.
fn default_jsx_import_source(&self) -> Option<String> {
None
}

/// An optional method which returns the JSX import source module which will
/// be appended to any JSX import source pragmas identified.
fn jsx_import_source_module(&self) -> &str {
Expand Down

0 comments on commit 15f3eaf

Please sign in to comment.