mirror of
https://github.com/denoland/deno.git
synced 2025-01-21 04:52:26 -05:00
fix(lsp/check): don't resolve unknown media types to a .js
extension (#27631)
Fixes https://github.com/denoland/deno/issues/25762. Note that some of the things in that issue are not resolved (vite/client types not working properly which has other root causes), but the wildcard module augmentation specifically is fixed by this. We were telling TSC that files with unknown media types had an extension of `.js`, so the ambient module declarations weren't applying. Instead, just don't resolve them, so the ambient declaration applies.
This commit is contained in:
parent
f6dcc13537
commit
70c822bfe2
4 changed files with 66 additions and 18 deletions
|
@ -4509,11 +4509,12 @@ fn op_release(
|
||||||
|
|
||||||
#[op2]
|
#[op2]
|
||||||
#[serde]
|
#[serde]
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
fn op_resolve(
|
fn op_resolve(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[string] base: String,
|
#[string] base: String,
|
||||||
#[serde] specifiers: Vec<(bool, String)>,
|
#[serde] specifiers: Vec<(bool, String)>,
|
||||||
) -> Result<Vec<Option<(String, String)>>, deno_core::url::ParseError> {
|
) -> Result<Vec<Option<(String, Option<String>)>>, deno_core::url::ParseError> {
|
||||||
op_resolve_inner(state, ResolveArgs { base, specifiers })
|
op_resolve_inner(state, ResolveArgs { base, specifiers })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4595,10 +4596,11 @@ async fn op_poll_requests(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
fn op_resolve_inner(
|
fn op_resolve_inner(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
args: ResolveArgs,
|
args: ResolveArgs,
|
||||||
) -> Result<Vec<Option<(String, String)>>, deno_core::url::ParseError> {
|
) -> Result<Vec<Option<(String, Option<String>)>>, deno_core::url::ParseError> {
|
||||||
let state = state.borrow_mut::<State>();
|
let state = state.borrow_mut::<State>();
|
||||||
let mark = state.performance.mark_with_args("tsc.op.op_resolve", &args);
|
let mark = state.performance.mark_with_args("tsc.op.op_resolve", &args);
|
||||||
let referrer = state.specifier_map.normalize(&args.base)?;
|
let referrer = state.specifier_map.normalize(&args.base)?;
|
||||||
|
@ -4611,7 +4613,11 @@ fn op_resolve_inner(
|
||||||
o.map(|(s, mt)| {
|
o.map(|(s, mt)| {
|
||||||
(
|
(
|
||||||
state.specifier_map.denormalize(&s),
|
state.specifier_map.denormalize(&s),
|
||||||
mt.as_ts_extension().to_string(),
|
if matches!(mt, MediaType::Unknown) {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(mt.as_ts_extension().to_string())
|
||||||
|
},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -6461,7 +6467,7 @@ mod tests {
|
||||||
resolved,
|
resolved,
|
||||||
vec![Some((
|
vec![Some((
|
||||||
temp_dir.url().join("b.ts").unwrap().to_string(),
|
temp_dir.url().join("b.ts").unwrap().to_string(),
|
||||||
MediaType::TypeScript.as_ts_extension().to_string()
|
Some(MediaType::TypeScript.as_ts_extension().to_string())
|
||||||
))]
|
))]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -723,7 +723,7 @@ delete Object.prototype.__proto__;
|
||||||
}
|
}
|
||||||
: arg;
|
: arg;
|
||||||
if (fileReference.fileName.startsWith("npm:")) {
|
if (fileReference.fileName.startsWith("npm:")) {
|
||||||
/** @type {[string, ts.Extension] | undefined} */
|
/** @type {[string, ts.Extension | null] | undefined} */
|
||||||
const resolved = ops.op_resolve(
|
const resolved = ops.op_resolve(
|
||||||
containingFilePath,
|
containingFilePath,
|
||||||
[
|
[
|
||||||
|
@ -735,7 +735,7 @@ delete Object.prototype.__proto__;
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
)?.[0];
|
)?.[0];
|
||||||
if (resolved) {
|
if (resolved && resolved[1]) {
|
||||||
return {
|
return {
|
||||||
resolvedTypeReferenceDirective: {
|
resolvedTypeReferenceDirective: {
|
||||||
primary: true,
|
primary: true,
|
||||||
|
@ -785,7 +785,7 @@ delete Object.prototype.__proto__;
|
||||||
debug(` base: ${base}`);
|
debug(` base: ${base}`);
|
||||||
debug(` specifiers: ${specifiers.map((s) => s[1]).join(", ")}`);
|
debug(` specifiers: ${specifiers.map((s) => s[1]).join(", ")}`);
|
||||||
}
|
}
|
||||||
/** @type {Array<[string, ts.Extension] | undefined>} */
|
/** @type {Array<[string, ts.Extension | null] | undefined>} */
|
||||||
const resolved = ops.op_resolve(
|
const resolved = ops.op_resolve(
|
||||||
base,
|
base,
|
||||||
specifiers,
|
specifiers,
|
||||||
|
@ -793,7 +793,7 @@ delete Object.prototype.__proto__;
|
||||||
if (resolved) {
|
if (resolved) {
|
||||||
/** @type {Array<ts.ResolvedModuleWithFailedLookupLocations>} */
|
/** @type {Array<ts.ResolvedModuleWithFailedLookupLocations>} */
|
||||||
const result = resolved.map((item) => {
|
const result = resolved.map((item) => {
|
||||||
if (item) {
|
if (item && item[1]) {
|
||||||
const [resolvedFileName, extension] = item;
|
const [resolvedFileName, extension] = item;
|
||||||
return {
|
return {
|
||||||
resolvedModule: {
|
resolvedModule: {
|
||||||
|
|
|
@ -746,7 +746,7 @@ fn op_resolve(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
#[string] base: String,
|
#[string] base: String,
|
||||||
#[serde] specifiers: Vec<(bool, String)>,
|
#[serde] specifiers: Vec<(bool, String)>,
|
||||||
) -> Result<Vec<(String, &'static str)>, ResolveError> {
|
) -> Result<Vec<(String, Option<&'static str>)>, ResolveError> {
|
||||||
op_resolve_inner(state, ResolveArgs { base, specifiers })
|
op_resolve_inner(state, ResolveArgs { base, specifiers })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -754,9 +754,9 @@ fn op_resolve(
|
||||||
fn op_resolve_inner(
|
fn op_resolve_inner(
|
||||||
state: &mut OpState,
|
state: &mut OpState,
|
||||||
args: ResolveArgs,
|
args: ResolveArgs,
|
||||||
) -> Result<Vec<(String, &'static str)>, ResolveError> {
|
) -> Result<Vec<(String, Option<&'static str>)>, ResolveError> {
|
||||||
let state = state.borrow_mut::<State>();
|
let state = state.borrow_mut::<State>();
|
||||||
let mut resolved: Vec<(String, &'static str)> =
|
let mut resolved: Vec<(String, Option<&'static str>)> =
|
||||||
Vec::with_capacity(args.specifiers.len());
|
Vec::with_capacity(args.specifiers.len());
|
||||||
let referrer = if let Some(remapped_specifier) =
|
let referrer = if let Some(remapped_specifier) =
|
||||||
state.maybe_remapped_specifier(&args.base)
|
state.maybe_remapped_specifier(&args.base)
|
||||||
|
@ -770,14 +770,14 @@ fn op_resolve_inner(
|
||||||
if specifier.starts_with("node:") {
|
if specifier.starts_with("node:") {
|
||||||
resolved.push((
|
resolved.push((
|
||||||
MISSING_DEPENDENCY_SPECIFIER.to_string(),
|
MISSING_DEPENDENCY_SPECIFIER.to_string(),
|
||||||
MediaType::Dts.as_ts_extension(),
|
Some(MediaType::Dts.as_ts_extension()),
|
||||||
));
|
));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if specifier.starts_with("asset:///") {
|
if specifier.starts_with("asset:///") {
|
||||||
let ext = MediaType::from_str(&specifier).as_ts_extension();
|
let ext = MediaType::from_str(&specifier).as_ts_extension();
|
||||||
resolved.push((specifier, ext));
|
resolved.push((specifier, Some(ext)));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -857,14 +857,15 @@ fn op_resolve_inner(
|
||||||
(
|
(
|
||||||
specifier_str,
|
specifier_str,
|
||||||
match media_type {
|
match media_type {
|
||||||
MediaType::Css => ".js", // surface these as .js for typescript
|
MediaType::Css => Some(".js"), // surface these as .js for typescript
|
||||||
media_type => media_type.as_ts_extension(),
|
MediaType::Unknown => None,
|
||||||
|
media_type => Some(media_type.as_ts_extension()),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
None => (
|
None => (
|
||||||
MISSING_DEPENDENCY_SPECIFIER.to_string(),
|
MISSING_DEPENDENCY_SPECIFIER.to_string(),
|
||||||
MediaType::Dts.as_ts_extension(),
|
Some(MediaType::Dts.as_ts_extension()),
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
log::debug!("Resolved {} from {} to {:?}", specifier, referrer, result);
|
log::debug!("Resolved {} from {} to {:?}", specifier, referrer, result);
|
||||||
|
@ -1441,7 +1442,10 @@ mod tests {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.expect("should have invoked op");
|
.expect("should have invoked op");
|
||||||
assert_eq!(actual, vec![("https://deno.land/x/b.ts".into(), ".ts")]);
|
assert_eq!(
|
||||||
|
actual,
|
||||||
|
vec![("https://deno.land/x/b.ts".into(), Some(".ts"))]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
@ -1460,7 +1464,10 @@ mod tests {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.expect("should have not errored");
|
.expect("should have not errored");
|
||||||
assert_eq!(actual, vec![(MISSING_DEPENDENCY_SPECIFIER.into(), ".d.ts")]);
|
assert_eq!(
|
||||||
|
actual,
|
||||||
|
vec![(MISSING_DEPENDENCY_SPECIFIER.into(), Some(".d.ts"))]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|
|
@ -17221,3 +17221,38 @@ fn lsp_wasm_module() {
|
||||||
);
|
);
|
||||||
client.shutdown();
|
client.shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn wildcard_augment() {
|
||||||
|
let context = TestContextBuilder::new().use_temp_cwd().build();
|
||||||
|
let mut client = context.new_lsp_command().build();
|
||||||
|
let temp_dir = context.temp_dir().path();
|
||||||
|
let source = source_file(
|
||||||
|
temp_dir.join("index.ts"),
|
||||||
|
r#"
|
||||||
|
import styles from "./hello_world.scss";
|
||||||
|
|
||||||
|
function bar(v: string): string {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
bar(styles);
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
temp_dir.join("index.d.ts").write(
|
||||||
|
r#"
|
||||||
|
declare module '*.scss' {
|
||||||
|
const content: string;
|
||||||
|
export default content;
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
temp_dir
|
||||||
|
.join("hello_world.scss")
|
||||||
|
.write("body { color: red; }");
|
||||||
|
|
||||||
|
client.initialize_default();
|
||||||
|
|
||||||
|
let diagnostics = client.did_open_file(&source);
|
||||||
|
assert_eq!(diagnostics.all().len(), 0);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue