mirror of
https://github.com/denoland/deno.git
synced 2025-03-03 17:34:47 -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
8465bd0037
commit
b03d82e5d3
9 changed files with 119 additions and 66 deletions
|
@ -105,6 +105,18 @@ itest!(check_broadcast_channel_unstable {
|
||||||
exit_code: 0,
|
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]
|
#[test]
|
||||||
fn cache_switching_config_then_no_config() {
|
fn cache_switching_config_then_no_config() {
|
||||||
let context = TestContext::default();
|
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]
|
[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);
|
console.log(Deno.umask);
|
||||||
~~~~~
|
~~~~~
|
||||||
at [WILDCARD]/unstable.ts:1:18
|
at [WILDCARD]/unstable.ts:1:18
|
||||||
|
|
|
@ -29,6 +29,37 @@ delete Object.prototype.__proto__;
|
||||||
/** @type {Map<string, string>} */
|
/** @type {Map<string, string>} */
|
||||||
const normalizedToOriginalMap = new Map();
|
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
|
* @param {unknown} value
|
||||||
* @returns {value is ts.CreateSourceFileOptions}
|
* @returns {value is ts.CreateSourceFileOptions}
|
||||||
|
@ -303,6 +334,49 @@ delete Object.prototype.__proto__;
|
||||||
return isNodeSourceFile;
|
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 */
|
/** @param {ts.DiagnosticRelatedInformation} diagnostic */
|
||||||
function fromRelatedInformation({
|
function fromRelatedInformation({
|
||||||
start,
|
start,
|
||||||
|
@ -316,7 +390,7 @@ delete Object.prototype.__proto__;
|
||||||
if (typeof msgText === "object") {
|
if (typeof msgText === "object") {
|
||||||
messageChain = msgText;
|
messageChain = msgText;
|
||||||
} else {
|
} else {
|
||||||
messageText = msgText;
|
messageText = formatMessage(msgText, ri.code);
|
||||||
}
|
}
|
||||||
if (start !== undefined && length !== undefined && file) {
|
if (start !== undefined && length !== undefined && file) {
|
||||||
const startPos = file.getLineAndCharacterOfPosition(start);
|
const startPos = file.getLineAndCharacterOfPosition(start);
|
||||||
|
@ -341,7 +415,7 @@ delete Object.prototype.__proto__;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @param {readonly ts.Diagnostic[]} diagnostics */
|
/** @param {readonly ts.Diagnostic[]} diagnostics */
|
||||||
function fromTypeScriptDiagnostic(diagnostics) {
|
function fromTypeScriptDiagnostics(diagnostics) {
|
||||||
return diagnostics.map(({ relatedInformation: ri, source, ...diag }) => {
|
return diagnostics.map(({ relatedInformation: ri, source, ...diag }) => {
|
||||||
/** @type {any} */
|
/** @type {any} */
|
||||||
const value = fromRelatedInformation(diag);
|
const value = fromRelatedInformation(diag);
|
||||||
|
@ -864,7 +938,7 @@ delete Object.prototype.__proto__;
|
||||||
performanceProgram({ program });
|
performanceProgram({ program });
|
||||||
|
|
||||||
ops.op_respond({
|
ops.op_respond({
|
||||||
diagnostics: fromTypeScriptDiagnostic(diagnostics),
|
diagnostics: fromTypeScriptDiagnostics(diagnostics),
|
||||||
stats: performanceEnd(),
|
stats: performanceEnd(),
|
||||||
});
|
});
|
||||||
debug("<<< exec stop");
|
debug("<<< exec stop");
|
||||||
|
@ -1055,7 +1129,7 @@ delete Object.prototype.__proto__;
|
||||||
/** @type {Record<string, any[]>} */
|
/** @type {Record<string, any[]>} */
|
||||||
const diagnosticMap = {};
|
const diagnosticMap = {};
|
||||||
for (const specifier of request.specifiers) {
|
for (const specifier of request.specifiers) {
|
||||||
diagnosticMap[specifier] = fromTypeScriptDiagnostic([
|
diagnosticMap[specifier] = fromTypeScriptDiagnostics([
|
||||||
...languageService.getSemanticDiagnostics(specifier),
|
...languageService.getSemanticDiagnostics(specifier),
|
||||||
...languageService.getSuggestionDiagnostics(specifier),
|
...languageService.getSuggestionDiagnostics(specifier),
|
||||||
...languageService.getSyntacticDiagnostics(specifier),
|
...languageService.getSyntacticDiagnostics(specifier),
|
||||||
|
|
|
@ -6,71 +6,11 @@ use deno_core::serde::Deserialize;
|
||||||
use deno_core::serde::Deserializer;
|
use deno_core::serde::Deserializer;
|
||||||
use deno_core::serde::Serialize;
|
use deno_core::serde::Serialize;
|
||||||
use deno_core::serde::Serializer;
|
use deno_core::serde::Serializer;
|
||||||
use lazy_regex::lazy_regex;
|
|
||||||
use once_cell::sync::Lazy;
|
|
||||||
use regex::Regex;
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
const MAX_SOURCE_LINE_LENGTH: usize = 150;
|
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)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
pub enum DiagnosticCategory {
|
pub enum DiagnosticCategory {
|
||||||
Warning,
|
Warning,
|
||||||
|
@ -227,7 +167,7 @@ impl Diagnostic {
|
||||||
f,
|
f,
|
||||||
"{:indent$}{}",
|
"{:indent$}{}",
|
||||||
"",
|
"",
|
||||||
format_message(&self.message_text.clone().unwrap(), &self.code),
|
self.message_text.as_deref().unwrap_or_default(),
|
||||||
indent = level,
|
indent = level,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,6 +152,7 @@ const denoNs = {
|
||||||
ChildProcess: process.ChildProcess,
|
ChildProcess: process.ChildProcess,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// when editing this list, also update unstableDenoProps in cli/tsc/99_main_compiler.js
|
||||||
const denoNsUnstable = {
|
const denoNsUnstable = {
|
||||||
listenDatagram: net.createListenDatagram(
|
listenDatagram: net.createListenDatagram(
|
||||||
ops.op_net_listen_udp,
|
ops.op_net_listen_udp,
|
||||||
|
|
Loading…
Add table
Reference in a new issue