1
0
Fork 0
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:
David Sherret 2023-07-13 19:29:51 -04:00 committed by Bartek Iwańczuk
parent ae2fecf45d
commit 533ee83fde
No known key found for this signature in database
GPG key ID: 0C6BCDDC3B3AD750
9 changed files with 119 additions and 66 deletions

View file

@ -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();

View 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

View file

@ -0,0 +1,4 @@
/// <reference no-default-lib="true"/>
/// <reference lib="es5" />
Deno;

View 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.

View file

@ -0,0 +1,2 @@
Deno.openKv;
Deno.createHttpClient;

View file

@ -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

View file

@ -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),

View file

@ -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,
)
}

View file

@ -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,