Skip to content

Commit

Permalink
feat: add Resolver::resolve_tsconfig API (#312)
Browse files Browse the repository at this point in the history
closes #289
  • Loading branch information
Boshen authored Nov 20, 2024
1 parent 1419af5 commit 2070b35
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 43 deletions.
64 changes: 40 additions & 24 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,22 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
self.resolve_tracing(directory.as_ref(), specifier, &mut ctx)
}

/// Resolve `tsconfig`.
///
/// The path can be:
///
/// * Path to a file with `.json` extension.
/// * Path to a file without `.json` extension, `.json` will be appended to filename.
/// * Path to a directory, where the filename is defaulted to `tsconfig.json`
///
/// # Errors
///
/// * See [ResolveError]
pub fn resolve_tsconfig<P: AsRef<Path>>(&self, path: P) -> Result<Arc<TsConfig>, ResolveError> {
let path = path.as_ref();
self.load_tsconfig(true, path, &TsconfigReferences::Auto)
}

/// Resolve `specifier` at absolute `path` with [ResolveContext]
///
/// # Errors
Expand Down Expand Up @@ -1114,30 +1130,6 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
None
}

fn load_tsconfig_paths(
&self,
cached_path: &CachedPath,
specifier: &str,
ctx: &mut Ctx,
) -> ResolveResult {
let Some(tsconfig_options) = &self.options.tsconfig else {
return Ok(None);
};
let tsconfig = self.load_tsconfig(
/* root */ true,
&tsconfig_options.config_file,
&tsconfig_options.references,
)?;
let paths = tsconfig.resolve(cached_path.path(), specifier);
for path in paths {
let cached_path = self.cache.value(&path);
if let Ok(path) = self.require_relative(&cached_path, ".", ctx) {
return Ok(Some(path));
}
}
Ok(None)
}

fn load_tsconfig(
&self,
root: bool,
Expand Down Expand Up @@ -1205,6 +1197,30 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
})
}

fn load_tsconfig_paths(
&self,
cached_path: &CachedPath,
specifier: &str,
ctx: &mut Ctx,
) -> ResolveResult {
let Some(tsconfig_options) = &self.options.tsconfig else {
return Ok(None);
};
let tsconfig = self.load_tsconfig(
/* root */ true,
&tsconfig_options.config_file,
&tsconfig_options.references,
)?;
let paths = tsconfig.resolve(cached_path.path(), specifier);
for path in paths {
let cached_path = self.cache.value(&path);
if let Ok(path) = self.require_relative(&cached_path, ".", ctx) {
return Ok(Some(path));
}
}
Ok(None)
}

fn get_extended_tsconfig_path(
&self,
directory: &CachedPath,
Expand Down
42 changes: 23 additions & 19 deletions src/tsconfig.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ pub struct TsConfig {
/// Whether this is the caller tsconfig.
/// Used for final template variable substitution when all configs are extended and merged.
#[serde(skip)]
root: bool,
pub root: bool,

/// Path to `tsconfig.json`. Contains the `tsconfig.json` filename.
#[serde(skip)]
pub(crate) path: PathBuf,
pub path: PathBuf,

#[serde(default)]
pub extends: Option<ExtendsField>,
Expand All @@ -48,10 +48,10 @@ pub struct TsConfig {
#[derive(Debug, Default, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CompilerOptions {
base_url: Option<PathBuf>,
pub base_url: Option<PathBuf>,

/// Path aliases
paths: Option<CompilerOptionsPathsMap>,
pub paths: Option<CompilerOptionsPathsMap>,

/// The actual base for where path aliases are resolved from.
#[serde(skip)]
Expand All @@ -73,7 +73,21 @@ pub struct ProjectReference {
}

impl TsConfig {
pub fn parse(root: bool, path: &Path, json: &mut str) -> Result<Self, serde_json::Error> {
/// Directory to `tsconfig.json`
///
/// # Panics
///
/// * When the `tsconfig.json` path is misconfigured.
pub fn directory(&self) -> &Path {
debug_assert!(self.path.file_name().is_some());
self.path.parent().unwrap()
}

pub(crate) fn parse(
root: bool,
path: &Path,
json: &mut str,
) -> Result<Self, serde_json::Error> {
_ = json_strip_comments::strip(json);
let mut tsconfig: Self = serde_json::from_str(json)?;
tsconfig.root = root;
Expand All @@ -89,7 +103,7 @@ impl TsConfig {
Ok(tsconfig)
}

pub fn build(mut self) -> Self {
pub(crate) fn build(mut self) -> Self {
if self.root {
let dir = self.directory().to_path_buf();
// Substitute template variable in `tsconfig.compilerOptions.paths`
Expand All @@ -104,17 +118,7 @@ impl TsConfig {
self
}

/// Directory to `tsconfig.json`
///
/// # Panics
///
/// * When the `tsconfig.json` path is misconfigured.
pub fn directory(&self) -> &Path {
debug_assert!(self.path.file_name().is_some());
self.path.parent().unwrap()
}

pub fn extend_tsconfig(&mut self, tsconfig: &Self) {
pub(crate) fn extend_tsconfig(&mut self, tsconfig: &Self) {
let compiler_options = &mut self.compiler_options;
if compiler_options.paths.is_none() {
compiler_options.paths_base = compiler_options
Expand All @@ -128,7 +132,7 @@ impl TsConfig {
}
}

pub fn resolve(&self, path: &Path, specifier: &str) -> Vec<PathBuf> {
pub(crate) fn resolve(&self, path: &Path, specifier: &str) -> Vec<PathBuf> {
if path.starts_with(self.base_path()) {
let paths = self.resolve_path_alias(specifier);
if !paths.is_empty() {
Expand All @@ -145,7 +149,7 @@ impl TsConfig {

// Copied from parcel
// <https://github.com/parcel-bundler/parcel/blob/b6224fd519f95e68d8b93ba90376fd94c8b76e69/packages/utils/node-resolver-rs/src/tsconfig.rs#L93>
pub fn resolve_path_alias(&self, specifier: &str) -> Vec<PathBuf> {
pub(crate) fn resolve_path_alias(&self, specifier: &str) -> Vec<PathBuf> {
if specifier.starts_with(['/', '.']) {
return vec![];
}
Expand Down
8 changes: 8 additions & 0 deletions tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ fn package_json() {
assert!(package_json.side_effects.as_ref().unwrap().is_object());
}

#[test]
fn tsconfig() {
let resolver = Resolver::new(ResolveOptions::default());
let tsconfig = resolver.resolve_tsconfig("./tests").unwrap();
assert!(tsconfig.root);
assert_eq!(tsconfig.path, PathBuf::from("./tests/tsconfig.json"));
}

#[cfg(feature = "package_json_raw_json_api")]
#[test]
fn package_json_raw_json_api() {
Expand Down
2 changes: 2 additions & 0 deletions tests/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{
}

0 comments on commit 2070b35

Please sign in to comment.