mirror of
https://github.com/denoland/deno.git
synced 2024-11-21 15:04:11 -05:00
fix(npm): handle directory resolution when resolving declaration files (#16706)
Also fixes resolving specifiers like `./something.generated` in declaration files. Closes #16695
This commit is contained in:
parent
7ab08130a0
commit
a57134de38
7 changed files with 88 additions and 12 deletions
|
@ -4,3 +4,7 @@ export class Class1 extends Class2 {
|
|||
|
||||
export class Class2 extends Class1 {
|
||||
}
|
||||
|
||||
// these should be fine though
|
||||
export { subDir } from "./sub_dir";
|
||||
export { otherDir } from "./other_dir";
|
||||
|
|
1
cli/tests/testdata/npm/registry/@denotest/check-error/1.0.0/other_dir.d.ts
vendored
Normal file
1
cli/tests/testdata/npm/registry/@denotest/check-error/1.0.0/other_dir.d.ts
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
export const otherDir: 2;
|
1
cli/tests/testdata/npm/registry/@denotest/check-error/1.0.0/other_dir/index.js
vendored
Normal file
1
cli/tests/testdata/npm/registry/@denotest/check-error/1.0.0/other_dir/index.js
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
module.exports.otherDir = 2;
|
1
cli/tests/testdata/npm/registry/@denotest/check-error/1.0.0/sub_dir/index.d.ts
vendored
Normal file
1
cli/tests/testdata/npm/registry/@denotest/check-error/1.0.0/sub_dir/index.d.ts
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
export * from './lib';
|
1
cli/tests/testdata/npm/registry/@denotest/check-error/1.0.0/sub_dir/index.js
vendored
Normal file
1
cli/tests/testdata/npm/registry/@denotest/check-error/1.0.0/sub_dir/index.js
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
module.exports.subDir = 1;
|
1
cli/tests/testdata/npm/registry/@denotest/check-error/1.0.0/sub_dir/lib.d.ts
vendored
Normal file
1
cli/tests/testdata/npm/registry/@denotest/check-error/1.0.0/sub_dir/lib.d.ts
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
export const subDir: 1;
|
|
@ -32,6 +32,25 @@ pub fn path_to_declaration_path(
|
|||
path: PathBuf,
|
||||
referrer_kind: NodeModuleKind,
|
||||
) -> PathBuf {
|
||||
fn probe_extensions(
|
||||
path: &Path,
|
||||
referrer_kind: NodeModuleKind,
|
||||
) -> Option<PathBuf> {
|
||||
let specific_dts_path = match referrer_kind {
|
||||
NodeModuleKind::Cjs => with_known_extension(path, "d.cts"),
|
||||
NodeModuleKind::Esm => with_known_extension(path, "d.mts"),
|
||||
};
|
||||
if specific_dts_path.exists() {
|
||||
return Some(specific_dts_path);
|
||||
}
|
||||
let dts_path = with_known_extension(path, "d.ts");
|
||||
if dts_path.exists() {
|
||||
Some(dts_path)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
let lowercase_path = path.to_string_lossy().to_lowercase();
|
||||
if lowercase_path.ends_with(".d.ts")
|
||||
|| lowercase_path.ends_with(".d.cts")
|
||||
|
@ -39,20 +58,54 @@ pub fn path_to_declaration_path(
|
|||
{
|
||||
return path;
|
||||
}
|
||||
let specific_dts_path = match referrer_kind {
|
||||
NodeModuleKind::Cjs => path.with_extension("d.cts"),
|
||||
NodeModuleKind::Esm => path.with_extension("d.mts"),
|
||||
};
|
||||
if specific_dts_path.exists() {
|
||||
specific_dts_path
|
||||
} else {
|
||||
let dts_path = path.with_extension("d.ts");
|
||||
if dts_path.exists() {
|
||||
dts_path
|
||||
} else {
|
||||
path
|
||||
if let Some(path) = probe_extensions(&path, referrer_kind) {
|
||||
return path;
|
||||
}
|
||||
if path.is_dir() {
|
||||
if let Some(path) = probe_extensions(&path.join("index"), referrer_kind) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
path
|
||||
}
|
||||
|
||||
/// Alternate `PathBuf::with_extension` that will handle known extensions
|
||||
/// more intelligently.
|
||||
pub fn with_known_extension(path: &Path, ext: &str) -> PathBuf {
|
||||
const NON_DECL_EXTS: &[&str] = &["cjs", "js", "json", "jsx", "mjs", "tsx"];
|
||||
const DECL_EXTS: &[&str] = &["cts", "mts", "ts"];
|
||||
|
||||
let file_name = match path.file_name() {
|
||||
Some(value) => value.to_string_lossy(),
|
||||
None => return path.to_path_buf(),
|
||||
};
|
||||
let lowercase_file_name = file_name.to_lowercase();
|
||||
let period_index = lowercase_file_name.rfind('.').and_then(|period_index| {
|
||||
let ext = &lowercase_file_name[period_index + 1..];
|
||||
if DECL_EXTS.contains(&ext) {
|
||||
if let Some(next_period_index) =
|
||||
lowercase_file_name[..period_index].rfind('.')
|
||||
{
|
||||
if &lowercase_file_name[next_period_index + 1..period_index] == "d" {
|
||||
Some(next_period_index)
|
||||
} else {
|
||||
Some(period_index)
|
||||
}
|
||||
} else {
|
||||
Some(period_index)
|
||||
}
|
||||
} else if NON_DECL_EXTS.contains(&ext) {
|
||||
Some(period_index)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
let file_name = match period_index {
|
||||
Some(period_index) => &file_name[..period_index],
|
||||
None => &file_name,
|
||||
};
|
||||
path.with_file_name(format!("{}.{}", file_name, ext))
|
||||
}
|
||||
|
||||
fn to_specifier_display_string(url: &ModuleSpecifier) -> String {
|
||||
|
@ -854,4 +907,18 @@ mod tests {
|
|||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_with_known_extension() {
|
||||
let cases = &[
|
||||
("test", "d.ts", "test.d.ts"),
|
||||
("test.d.ts", "ts", "test.ts"),
|
||||
("test.worker", "d.ts", "test.worker.d.ts"),
|
||||
("test.d.mts", "js", "test.js"),
|
||||
];
|
||||
for (path, ext, expected) in cases {
|
||||
let actual = with_known_extension(&PathBuf::from(path), ext);
|
||||
assert_eq!(actual.to_string_lossy(), *expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue