Vendor things
This commit is contained in:
parent
5deceec006
commit
977e3c17e5
19434 changed files with 10682014 additions and 0 deletions
292
third-party/vendor/swc_ecma_loader/src/resolvers/tsc.rs
vendored
Normal file
292
third-party/vendor/swc_ecma_loader/src/resolvers/tsc.rs
vendored
Normal file
|
|
@ -0,0 +1,292 @@
|
|||
use std::path::{Component, Path, PathBuf};
|
||||
|
||||
use anyhow::{bail, Context, Error};
|
||||
use swc_common::FileName;
|
||||
use tracing::{debug, info, trace, warn, Level};
|
||||
|
||||
use crate::resolve::Resolve;
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Pattern {
|
||||
Wildcard {
|
||||
prefix: String,
|
||||
},
|
||||
/// No wildcard.
|
||||
Exact(String),
|
||||
}
|
||||
|
||||
/// Support for `paths` of `tsconfig.json`.
|
||||
///
|
||||
/// See https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping
|
||||
#[derive(Debug)]
|
||||
pub struct TsConfigResolver<R>
|
||||
where
|
||||
R: Resolve,
|
||||
{
|
||||
inner: R,
|
||||
base_url: PathBuf,
|
||||
base_url_filename: FileName,
|
||||
paths: Vec<(Pattern, Vec<String>)>,
|
||||
}
|
||||
|
||||
impl<R> TsConfigResolver<R>
|
||||
where
|
||||
R: Resolve,
|
||||
{
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// ## base_url
|
||||
///
|
||||
/// See https://www.typescriptlang.org/tsconfig#baseUrl
|
||||
///
|
||||
/// The typescript documentation says `This must be specified if "paths"
|
||||
/// is.`.
|
||||
///
|
||||
/// ## `paths`
|
||||
///
|
||||
/// Pass `paths` map from `tsconfig.json`.
|
||||
///
|
||||
/// See https://www.typescriptlang.org/tsconfig#paths
|
||||
///
|
||||
/// Note that this is not a hashmap because value is not used as a hash map.
|
||||
pub fn new(inner: R, base_url: PathBuf, paths: Vec<(String, Vec<String>)>) -> Self {
|
||||
if cfg!(debug_assertions) {
|
||||
info!(
|
||||
base_url = tracing::field::display(base_url.display()),
|
||||
"jsc.paths"
|
||||
);
|
||||
}
|
||||
|
||||
let paths = paths
|
||||
.into_iter()
|
||||
.map(|(from, to)| {
|
||||
assert!(
|
||||
!to.is_empty(),
|
||||
"value of `paths.{}` should not be an empty array",
|
||||
from,
|
||||
);
|
||||
|
||||
let pos = from.as_bytes().iter().position(|&c| c == b'*');
|
||||
let pat = if from.contains('*') {
|
||||
if from.as_bytes().iter().rposition(|&c| c == b'*') != pos {
|
||||
panic!("`paths.{}` should have only one wildcard", from)
|
||||
}
|
||||
|
||||
Pattern::Wildcard {
|
||||
prefix: from[..pos.unwrap()].to_string(),
|
||||
}
|
||||
} else {
|
||||
assert_eq!(
|
||||
to.len(),
|
||||
1,
|
||||
"value of `paths.{}` should be an array with one element because the src \
|
||||
path does not contains * (wildcard)",
|
||||
from,
|
||||
);
|
||||
|
||||
Pattern::Exact(from)
|
||||
};
|
||||
|
||||
(pat, to)
|
||||
})
|
||||
.collect();
|
||||
|
||||
Self {
|
||||
inner,
|
||||
base_url_filename: FileName::Real(base_url.clone()),
|
||||
base_url,
|
||||
paths,
|
||||
}
|
||||
}
|
||||
|
||||
fn invoke_inner_resolver(
|
||||
&self,
|
||||
base: &FileName,
|
||||
module_specifier: &str,
|
||||
) -> Result<FileName, Error> {
|
||||
let res = self.inner.resolve(base, module_specifier).with_context(|| {
|
||||
format!(
|
||||
"failed to resolve `{module_specifier}` from `{base}` using inner \
|
||||
resolver\nbase_url={}",
|
||||
self.base_url_filename
|
||||
)
|
||||
});
|
||||
|
||||
match res {
|
||||
Ok(resolved) => {
|
||||
info!(
|
||||
"Resolved `{}` as `{}` from `{}`",
|
||||
module_specifier, resolved, base
|
||||
);
|
||||
|
||||
if let FileName::Real(target) = &resolved {
|
||||
// If node_modules is in path, we should return module specifier.
|
||||
if target.components().any(|c| {
|
||||
if let Component::Normal(v) = c {
|
||||
v == "node_modules"
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}) {
|
||||
return Ok(FileName::Real(module_specifier.into()));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(resolved)
|
||||
}
|
||||
|
||||
Err(err) => {
|
||||
warn!("{:?}", err);
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> Resolve for TsConfigResolver<R>
|
||||
where
|
||||
R: Resolve,
|
||||
{
|
||||
fn resolve(&self, base: &FileName, module_specifier: &str) -> Result<FileName, Error> {
|
||||
let _tracing = if cfg!(debug_assertions) {
|
||||
Some(
|
||||
tracing::span!(
|
||||
Level::ERROR,
|
||||
"TsConfigResolver::resolve",
|
||||
base_url = tracing::field::display(self.base_url.display()),
|
||||
base = tracing::field::display(base),
|
||||
src = tracing::field::display(module_specifier),
|
||||
)
|
||||
.entered(),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if module_specifier.starts_with('.')
|
||||
&& (module_specifier == ".."
|
||||
|| module_specifier.starts_with("./")
|
||||
|| module_specifier.starts_with("../"))
|
||||
{
|
||||
return self
|
||||
.invoke_inner_resolver(base, module_specifier)
|
||||
.context("not processed by tsc resolver because it's relative import");
|
||||
}
|
||||
|
||||
if let FileName::Real(v) = base {
|
||||
if v.components().any(|c| match c {
|
||||
Component::Normal(v) => v == "node_modules",
|
||||
_ => false,
|
||||
}) {
|
||||
return self.invoke_inner_resolver(base, module_specifier).context(
|
||||
"not processed by tsc resolver because base module is in node_modules",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
info!("Checking `jsc.paths`");
|
||||
|
||||
// https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping
|
||||
for (from, to) in &self.paths {
|
||||
match from {
|
||||
Pattern::Wildcard { prefix } => {
|
||||
debug!("Checking `{}` in `jsc.paths`", prefix);
|
||||
|
||||
let extra = module_specifier.strip_prefix(prefix);
|
||||
let extra = match extra {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
if cfg!(debug_assertions) {
|
||||
trace!("skip because src doesn't start with prefix");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
if cfg!(debug_assertions) {
|
||||
debug!("Extra: `{}`", extra);
|
||||
}
|
||||
|
||||
let mut errors = vec![];
|
||||
for target in to {
|
||||
let mut replaced = target.replace('*', extra);
|
||||
|
||||
let _tracing = if cfg!(debug_assertions) {
|
||||
Some(
|
||||
tracing::span!(
|
||||
Level::ERROR,
|
||||
"TsConfigResolver::resolve::jsc.paths",
|
||||
replaced = tracing::field::display(&replaced),
|
||||
)
|
||||
.entered(),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let relative = format!("./{}", replaced);
|
||||
|
||||
let res = self
|
||||
.invoke_inner_resolver(base, module_specifier)
|
||||
.or_else(|_| {
|
||||
self.invoke_inner_resolver(&self.base_url_filename, &relative)
|
||||
})
|
||||
.or_else(|_| {
|
||||
self.invoke_inner_resolver(&self.base_url_filename, &replaced)
|
||||
});
|
||||
|
||||
errors.push(match res {
|
||||
Ok(resolved) => return Ok(resolved),
|
||||
Err(err) => err,
|
||||
});
|
||||
|
||||
if cfg!(target_os = "windows") {
|
||||
replaced = replaced.replace('/', "\\");
|
||||
}
|
||||
|
||||
if to.len() == 1 {
|
||||
info!(
|
||||
"Using `{}` for `{}` because the length of the jsc.paths entry is \
|
||||
1",
|
||||
replaced, module_specifier
|
||||
);
|
||||
return Ok(FileName::Real(replaced.into()));
|
||||
}
|
||||
}
|
||||
|
||||
bail!(
|
||||
"`{}` matched `{}` (from tsconfig.paths) but failed to resolve:\n{:?}",
|
||||
module_specifier,
|
||||
prefix,
|
||||
errors
|
||||
)
|
||||
}
|
||||
Pattern::Exact(from) => {
|
||||
// Should be exactly matched
|
||||
if module_specifier != from {
|
||||
continue;
|
||||
}
|
||||
|
||||
let tp = Path::new(&to[0]);
|
||||
if tp.is_absolute() {
|
||||
return Ok(FileName::Real(tp.into()));
|
||||
}
|
||||
|
||||
if let Ok(res) = self.resolve(&self.base_url_filename, &format!("./{}", &to[0]))
|
||||
{
|
||||
return Ok(res);
|
||||
}
|
||||
|
||||
return Ok(FileName::Real(self.base_url.join(&to[0])));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Ok(v) = self.invoke_inner_resolver(&self.base_url_filename, module_specifier) {
|
||||
return Ok(v);
|
||||
}
|
||||
|
||||
self.invoke_inner_resolver(base, module_specifier)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue