mirror of
https://github.com/denoland/deno.git
synced 2024-11-28 16:20:57 -05:00
fix(tsc): more informative diagnostic when Deno
does not exist (#19825)
Also improved the diagnostic when using something like `Deno.openKv` and it doesn't exist.
This commit is contained in:
parent
ae2fecf45d
commit
533ee83fde
9 changed files with 119 additions and 66 deletions
|
@ -105,6 +105,18 @@ itest!(check_broadcast_channel_unstable {
|
|||
exit_code: 0,
|
||||
});
|
||||
|
||||
itest!(check_deno_not_found {
|
||||
args: "check --quiet check/deno_not_found/main.ts",
|
||||
output: "check/deno_not_found/main.out",
|
||||
exit_code: 1,
|
||||
});
|
||||
|
||||
itest!(check_deno_unstable_not_found {
|
||||
args: "check --quiet check/deno_unstable_not_found/main.ts",
|
||||
output: "check/deno_unstable_not_found/main.out",
|
||||
exit_code: 1,
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn cache_switching_config_then_no_config() {
|
||||
let context = TestContext::default();
|
||||
|
|
4
cli/tests/testdata/check/deno_not_found/main.out
vendored
Normal file
4
cli/tests/testdata/check/deno_not_found/main.out
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
error: TS2304 [ERROR]: Cannot find name 'Deno'. Do you need to change your target library? Try changing the 'lib' compiler option to include 'deno.ns' or add a triple-slash directive to your entrypoint: /// <reference lib="deno.ns" />
|
||||
Deno;
|
||||
~~~~
|
||||
at file:///[WILDCARD]/check/deno_not_found/main.ts:4:1
|
4
cli/tests/testdata/check/deno_not_found/main.ts
vendored
Normal file
4
cli/tests/testdata/check/deno_not_found/main.ts
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
/// <reference no-default-lib="true"/>
|
||||
/// <reference lib="es5" />
|
||||
|
||||
Deno;
|
16
cli/tests/testdata/check/deno_unstable_not_found/main.out
vendored
Normal file
16
cli/tests/testdata/check/deno_unstable_not_found/main.out
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
error: TS2551 [ERROR]: Property 'openKv' does not exist on type 'typeof Deno'. Did you mean 'open'? 'Deno.openKv' is an unstable API. Did you forget to run with the '--unstable' flag, or did you mean 'open'? If not, try changing the 'lib' compiler option to include 'deno.unstable' or add a triple-slash directive to your entrypoint: /// <reference lib="deno.unstable" />
|
||||
Deno.openKv;
|
||||
~~~~~~
|
||||
at file:///[WILDCARD]/deno_unstable_not_found/main.ts:1:6
|
||||
|
||||
'open' is declared here.
|
||||
export function open(
|
||||
~~~~
|
||||
at asset:///lib.deno.ns.d.ts:1667:19
|
||||
|
||||
TS2339 [ERROR]: Property 'createHttpClient' does not exist on type 'typeof Deno'. 'Deno.createHttpClient' is an unstable API. Did you forget to run with the '--unstable' flag? If not, try changing the 'lib' compiler option to include 'deno.unstable' or add a triple-slash directive to your entrypoint: /// <reference lib="deno.unstable" />
|
||||
Deno.createHttpClient;
|
||||
~~~~~~~~~~~~~~~~
|
||||
at file:///[WILDCARD]/deno_unstable_not_found/main.ts:2:6
|
||||
|
||||
Found 2 errors.
|
2
cli/tests/testdata/check/deno_unstable_not_found/main.ts
vendored
Normal file
2
cli/tests/testdata/check/deno_unstable_not_found/main.ts
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
Deno.openKv;
|
||||
Deno.createHttpClient;
|
2
cli/tests/testdata/run/unstable_disabled.out
vendored
2
cli/tests/testdata/run/unstable_disabled.out
vendored
|
@ -1,5 +1,5 @@
|
|||
[WILDCARD]
|
||||
error: TS2339 [ERROR]: Property 'umask' does not exist on type 'typeof Deno'. 'Deno.umask' is an unstable API. Did you forget to run with the '--unstable' flag?
|
||||
error: TS2339 [ERROR]: Property 'umask' does not exist on type 'typeof Deno'. 'Deno.umask' is an unstable API. Did you forget to run with the '--unstable' flag? If not, try changing the 'lib' compiler option to include 'deno.unstable' or add a triple-slash directive to your entrypoint: /// <reference lib="deno.unstable" />
|
||||
console.log(Deno.umask);
|
||||
~~~~~
|
||||
at [WILDCARD]/unstable.ts:1:18
|
||||
|
|
|
@ -29,6 +29,37 @@ delete Object.prototype.__proto__;
|
|||
/** @type {Map<string, string>} */
|
||||
const normalizedToOriginalMap = new Map();
|
||||
|
||||
/** @type {ReadonlySet<string>} */
|
||||
const unstableDenoProps = new Set([
|
||||
"AtomicOperation",
|
||||
"CreateHttpClientOptions",
|
||||
"DatagramConn",
|
||||
"HttpClient",
|
||||
"Kv",
|
||||
"KvListIterator",
|
||||
"KvU64",
|
||||
"UnsafeCallback",
|
||||
"UnsafePointer",
|
||||
"UnsafePointerView",
|
||||
"UnsafeFnPointer",
|
||||
"UnixConnectOptions",
|
||||
"UnixListenOptions",
|
||||
"createHttpClient",
|
||||
"dlopen",
|
||||
"flock",
|
||||
"flockSync",
|
||||
"funlock",
|
||||
"funlockSync",
|
||||
"listen",
|
||||
"listenDatagram",
|
||||
"openKv",
|
||||
"upgradeHttp",
|
||||
"umask",
|
||||
]);
|
||||
const unstableMsgSuggestion =
|
||||
"If not, try changing the 'lib' compiler option to include 'deno.unstable' " +
|
||||
'or add a triple-slash directive to your entrypoint: /// <reference lib="deno.unstable" />';
|
||||
|
||||
/**
|
||||
* @param {unknown} value
|
||||
* @returns {value is ts.CreateSourceFileOptions}
|
||||
|
@ -303,6 +334,49 @@ delete Object.prototype.__proto__;
|
|||
return isNodeSourceFile;
|
||||
});
|
||||
|
||||
/**
|
||||
* @param msg {string}
|
||||
* @param code {number}
|
||||
*/
|
||||
function formatMessage(msg, code) {
|
||||
switch (code) {
|
||||
case 2304: {
|
||||
if (msg === "Cannot find name 'Deno'.") {
|
||||
msg += " Do you need to change your target library? " +
|
||||
"Try changing the 'lib' compiler option to include 'deno.ns' " +
|
||||
'or add a triple-slash directive to your entrypoint: /// <reference lib="deno.ns" />';
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
case 2339: {
|
||||
const property = getProperty();
|
||||
if (property && unstableDenoProps.has(property)) {
|
||||
return `${msg} 'Deno.${property}' is an unstable API. Did you forget to run with the '--unstable' flag? ${unstableMsgSuggestion}`;
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
default: {
|
||||
const property = getProperty();
|
||||
if (property && unstableDenoProps.has(property)) {
|
||||
const suggestion = getMsgSuggestion();
|
||||
if (suggestion) {
|
||||
return `${msg} 'Deno.${property}' is an unstable API. Did you forget to run with the '--unstable' flag, or did you mean '${suggestion}'? ${unstableMsgSuggestion}`;
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
|
||||
function getProperty() {
|
||||
return /Property '([^']+)' does not exist on type 'typeof Deno'/
|
||||
.exec(msg)?.[1];
|
||||
}
|
||||
|
||||
function getMsgSuggestion() {
|
||||
return / Did you mean '([^']+)'\?/.exec(msg)?.[1];
|
||||
}
|
||||
}
|
||||
|
||||
/** @param {ts.DiagnosticRelatedInformation} diagnostic */
|
||||
function fromRelatedInformation({
|
||||
start,
|
||||
|
@ -316,7 +390,7 @@ delete Object.prototype.__proto__;
|
|||
if (typeof msgText === "object") {
|
||||
messageChain = msgText;
|
||||
} else {
|
||||
messageText = msgText;
|
||||
messageText = formatMessage(msgText, ri.code);
|
||||
}
|
||||
if (start !== undefined && length !== undefined && file) {
|
||||
const startPos = file.getLineAndCharacterOfPosition(start);
|
||||
|
@ -341,7 +415,7 @@ delete Object.prototype.__proto__;
|
|||
}
|
||||
|
||||
/** @param {readonly ts.Diagnostic[]} diagnostics */
|
||||
function fromTypeScriptDiagnostic(diagnostics) {
|
||||
function fromTypeScriptDiagnostics(diagnostics) {
|
||||
return diagnostics.map(({ relatedInformation: ri, source, ...diag }) => {
|
||||
/** @type {any} */
|
||||
const value = fromRelatedInformation(diag);
|
||||
|
@ -864,7 +938,7 @@ delete Object.prototype.__proto__;
|
|||
performanceProgram({ program });
|
||||
|
||||
ops.op_respond({
|
||||
diagnostics: fromTypeScriptDiagnostic(diagnostics),
|
||||
diagnostics: fromTypeScriptDiagnostics(diagnostics),
|
||||
stats: performanceEnd(),
|
||||
});
|
||||
debug("<<< exec stop");
|
||||
|
@ -1055,7 +1129,7 @@ delete Object.prototype.__proto__;
|
|||
/** @type {Record<string, any[]>} */
|
||||
const diagnosticMap = {};
|
||||
for (const specifier of request.specifiers) {
|
||||
diagnosticMap[specifier] = fromTypeScriptDiagnostic([
|
||||
diagnosticMap[specifier] = fromTypeScriptDiagnostics([
|
||||
...languageService.getSemanticDiagnostics(specifier),
|
||||
...languageService.getSuggestionDiagnostics(specifier),
|
||||
...languageService.getSyntacticDiagnostics(specifier),
|
||||
|
|
|
@ -6,71 +6,11 @@ use deno_core::serde::Deserialize;
|
|||
use deno_core::serde::Deserializer;
|
||||
use deno_core::serde::Serialize;
|
||||
use deno_core::serde::Serializer;
|
||||
use lazy_regex::lazy_regex;
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
|
||||
const MAX_SOURCE_LINE_LENGTH: usize = 150;
|
||||
|
||||
const UNSTABLE_DENO_PROPS: &[&str] = &[
|
||||
"CreateHttpClientOptions",
|
||||
"DatagramConn",
|
||||
"HttpClient",
|
||||
"UnixConnectOptions",
|
||||
"UnixListenOptions",
|
||||
"connect",
|
||||
"createHttpClient",
|
||||
"listen",
|
||||
"listenDatagram",
|
||||
"dlopen",
|
||||
"removeSignalListener",
|
||||
"shutdown",
|
||||
"umask",
|
||||
];
|
||||
|
||||
static MSG_MISSING_PROPERTY_DENO: Lazy<Regex> =
|
||||
lazy_regex!(r#"Property '([^']+)' does not exist on type 'typeof Deno'"#);
|
||||
|
||||
static MSG_SUGGESTION: Lazy<Regex> =
|
||||
lazy_regex!(r#" Did you mean '([^']+)'\?"#);
|
||||
|
||||
/// Potentially convert a "raw" diagnostic message from TSC to something that
|
||||
/// provides a more sensible error message given a Deno runtime context.
|
||||
fn format_message(msg: &str, code: &u64) -> String {
|
||||
match code {
|
||||
2339 => {
|
||||
if let Some(captures) = MSG_MISSING_PROPERTY_DENO.captures(msg) {
|
||||
if let Some(property) = captures.get(1) {
|
||||
if UNSTABLE_DENO_PROPS.contains(&property.as_str()) {
|
||||
return format!("{} 'Deno.{}' is an unstable API. Did you forget to run with the '--unstable' flag?", msg, property.as_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
msg.to_string()
|
||||
}
|
||||
2551 => {
|
||||
if let (Some(caps_property), Some(caps_suggestion)) = (
|
||||
MSG_MISSING_PROPERTY_DENO.captures(msg),
|
||||
MSG_SUGGESTION.captures(msg),
|
||||
) {
|
||||
if let (Some(property), Some(suggestion)) =
|
||||
(caps_property.get(1), caps_suggestion.get(1))
|
||||
{
|
||||
if UNSTABLE_DENO_PROPS.contains(&property.as_str()) {
|
||||
return format!("{} 'Deno.{}' is an unstable API. Did you forget to run with the '--unstable' flag, or did you mean '{}'?", MSG_SUGGESTION.replace(msg, ""), property.as_str(), suggestion.as_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
msg.to_string()
|
||||
}
|
||||
_ => msg.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum DiagnosticCategory {
|
||||
Warning,
|
||||
|
@ -227,7 +167,7 @@ impl Diagnostic {
|
|||
f,
|
||||
"{:indent$}{}",
|
||||
"",
|
||||
format_message(&self.message_text.clone().unwrap(), &self.code),
|
||||
self.message_text.as_deref().unwrap_or_default(),
|
||||
indent = level,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -152,6 +152,7 @@ const denoNs = {
|
|||
ChildProcess: process.ChildProcess,
|
||||
};
|
||||
|
||||
// when editing this list, also update unstableDenoProps in cli/tsc/99_main_compiler.js
|
||||
const denoNsUnstable = {
|
||||
listenDatagram: net.createListenDatagram(
|
||||
ops.op_net_listen_udp,
|
||||
|
|
Loading…
Reference in a new issue