mirror of
https://github.com/denoland/deno.git
synced 2025-12-23 08:48:24 +00:00
fix(check): improve node types handling (#31677)
1. Always injects node types when someone has a `node:` import (like
before, so this isn't dependent on the lib setting... which fixes the
linked issue)
2. Handles someone doing `/// <reference lib="node" />`. Previously this
was slightly broken.
*
c5cb3b27ac
* https://github.com/denoland/typescript-go/pull/18
Closes https://github.com/denoland/deno/issues/31649
This commit is contained in:
parent
d3668555dc
commit
6aaed850b8
15 changed files with 206 additions and 21 deletions
|
|
@ -3,6 +3,7 @@
|
|||
use std::borrow::Cow;
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use std::fs;
|
||||
use std::future::Future;
|
||||
use std::ops::Range;
|
||||
|
|
@ -1506,6 +1507,11 @@ impl DocumentModules {
|
|||
for dependency in module.dependencies.values() {
|
||||
let code_specifier = dependency.get_code();
|
||||
let type_specifier = dependency.get_type();
|
||||
if let Some(dep) = code_specifier
|
||||
&& dep.scheme() == "node"
|
||||
{
|
||||
dep_info.has_node_specifier = true;
|
||||
}
|
||||
if dependency.maybe_deno_types_specifier.is_some()
|
||||
&& let (Some(code_specifier), Some(type_specifier)) =
|
||||
(code_specifier, type_specifier)
|
||||
|
|
@ -1587,6 +1593,15 @@ impl DocumentModules {
|
|||
.clone()
|
||||
}
|
||||
|
||||
pub fn scopes_with_node_specifier(&self) -> HashSet<Option<Arc<Url>>> {
|
||||
self
|
||||
.dep_info_by_scope()
|
||||
.iter()
|
||||
.filter(|(_, i)| i.has_node_specifier)
|
||||
.map(|(s, _)| s.clone())
|
||||
.collect::<HashSet<_>>()
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "lsp-tracing", tracing::instrument(skip_all))]
|
||||
pub fn resolve(
|
||||
&self,
|
||||
|
|
|
|||
|
|
@ -602,6 +602,7 @@ impl LspResolver {
|
|||
#[derive(Debug, Default, Clone)]
|
||||
pub struct ScopeDepInfo {
|
||||
pub deno_types_to_code_resolutions: HashMap<ModuleSpecifier, ModuleSpecifier>,
|
||||
pub has_node_specifier: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
|
|
|
|||
|
|
@ -5094,6 +5094,11 @@ fn op_script_names(state: &mut OpState) -> ScriptNames {
|
|||
by_notebook_uri: Default::default(),
|
||||
};
|
||||
|
||||
let scopes_with_node_specifier = state
|
||||
.state_snapshot
|
||||
.document_modules
|
||||
.scopes_with_node_specifier();
|
||||
|
||||
// Insert global scripts.
|
||||
for (compiler_options_key, compiler_options_data) in
|
||||
state.state_snapshot.compiler_options_resolver.entries()
|
||||
|
|
@ -5111,6 +5116,9 @@ fn op_script_names(state: &mut OpState) -> ScriptNames {
|
|||
.state_snapshot
|
||||
.resolver
|
||||
.get_scoped_resolver(scope.as_deref());
|
||||
if scopes_with_node_specifier.contains(&scope) {
|
||||
script_names.insert("asset:///reference_types_node.d.ts".to_string());
|
||||
}
|
||||
for (referrer, relative_specifiers) in compiler_options_data
|
||||
.ts_config_files
|
||||
.iter()
|
||||
|
|
|
|||
38
cli/tsc/00_typescript.js
vendored
38
cli/tsc/00_typescript.js
vendored
|
|
@ -127196,7 +127196,7 @@ function createCreateProgramOptions(rootNames, options, host, oldProgram, config
|
|||
};
|
||||
}
|
||||
function createProgram(_rootNamesOrOptions, _options, _host, _oldProgram, _configFileParsingDiagnostics) {
|
||||
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
|
||||
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q;
|
||||
let _createProgramOptions = isArray(_rootNamesOrOptions) ? createCreateProgramOptions(_rootNamesOrOptions, _options, _host, _oldProgram, _configFileParsingDiagnostics) : _rootNamesOrOptions;
|
||||
const { rootNames, options, configFileParsingDiagnostics, projectReferences, typeScriptVersion: typeScriptVersion2, host: createProgramOptionsHost } = _createProgramOptions;
|
||||
let { oldProgram } = _createProgramOptions;
|
||||
|
|
@ -127331,6 +127331,8 @@ function createProgram(_rootNamesOrOptions, _options, _host, _oldProgram, _confi
|
|||
let redirectTargetsMap = createMultiMap();
|
||||
let usesUriStyleNodeCoreModules;
|
||||
const filesByName = /* @__PURE__ */ new Map();
|
||||
let shouldLoadNodeTypes = false;
|
||||
let foundNodeTypes = false;
|
||||
let missingFileNames = /* @__PURE__ */ new Map();
|
||||
const filesByNameIgnoreCase = host.useCaseSensitiveFileNames() ? /* @__PURE__ */ new Map() : void 0;
|
||||
let resolvedProjectReferences;
|
||||
|
|
@ -127438,13 +127440,6 @@ function createProgram(_rootNamesOrOptions, _options, _host, _oldProgram, _confi
|
|||
);
|
||||
} else {
|
||||
forEach(options.lib, (libFileName, index) => {
|
||||
if (libFileName === "lib.node.d.ts") {
|
||||
for (const path of filesByName.keys()) {
|
||||
if (deno_exports.isTypesNodePkgPath(path)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
processRootFile(
|
||||
pathForLibFile(libFileName),
|
||||
/*isDefaultLib*/
|
||||
|
|
@ -127456,6 +127451,25 @@ function createProgram(_rootNamesOrOptions, _options, _host, _oldProgram, _confi
|
|||
});
|
||||
}
|
||||
}
|
||||
const hasTypesNodePackage = () => {
|
||||
for (const path of filesByName.keys()) {
|
||||
if (deno_exports.isTypesNodePkgPath(path)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
if (foundNodeTypes && !hasTypesNodePackage()) {
|
||||
shouldLoadNodeTypes = true;
|
||||
processRootFile(
|
||||
"asset:///lib.node.d.ts",
|
||||
/*isDefaultLib*/
|
||||
true,
|
||||
/*ignoreNoDefaultLib*/
|
||||
false,
|
||||
{ kind: 6 /* LibFile */, index: ((_o = options.lib) == null ? void 0 : _o.length) ?? 0 }
|
||||
);
|
||||
}
|
||||
files = toSorted(processingDefaultLibFiles, compareDefaultLibFiles).concat(processingOtherFiles);
|
||||
processingDefaultLibFiles = void 0;
|
||||
processingOtherFiles = void 0;
|
||||
|
|
@ -127576,7 +127590,7 @@ function createProgram(_rootNamesOrOptions, _options, _host, _oldProgram, _confi
|
|||
readFile,
|
||||
directoryExists,
|
||||
getSymlinkCache,
|
||||
realpath: (_o = host.realpath) == null ? void 0 : _o.bind(host),
|
||||
realpath: (_p = host.realpath) == null ? void 0 : _p.bind(host),
|
||||
useCaseSensitiveFileNames: () => host.useCaseSensitiveFileNames(),
|
||||
getCanonicalFileName,
|
||||
getFileIncludeReasons: () => programDiagnostics.getFileReasons(),
|
||||
|
|
@ -127590,7 +127604,7 @@ function createProgram(_rootNamesOrOptions, _options, _host, _oldProgram, _confi
|
|||
}
|
||||
mark("afterProgram");
|
||||
measure("Program", "beforeProgram", "afterProgram");
|
||||
(_p = tracing) == null ? void 0 : _p.pop();
|
||||
(_q = tracing) == null ? void 0 : _q.pop();
|
||||
return program;
|
||||
function getResolvedModule(file, moduleName, mode) {
|
||||
var _a2;
|
||||
|
|
@ -128812,6 +128826,10 @@ function createProgram(_rootNamesOrOptions, _options, _host, _oldProgram, _confi
|
|||
}
|
||||
}
|
||||
function processSourceFile(fileName, isDefaultLib, ignoreNoDefaultLib, packageId, reason) {
|
||||
if (fileName === "asset:///lib.node.d.ts" && !shouldLoadNodeTypes) {
|
||||
foundNodeTypes = true;
|
||||
return;
|
||||
}
|
||||
getSourceFileFromReferenceWorker(
|
||||
fileName,
|
||||
(fileName2) => findSourceFile(fileName2, isDefaultLib, ignoreNoDefaultLib, reason, packageId),
|
||||
|
|
|
|||
|
|
@ -23,15 +23,15 @@ impl Hashes {
|
|||
}
|
||||
}
|
||||
|
||||
pub const VERSION: &str = "0.1.12";
|
||||
pub const VERSION: &str = "0.1.13";
|
||||
pub const DOWNLOAD_BASE_URL: &str =
|
||||
"https://github.com/denoland/typescript-go/releases/download/v0.1.12";
|
||||
"https://github.com/denoland/typescript-go/releases/download/v0.1.13";
|
||||
pub const HASHES: Hashes = Hashes {
|
||||
windows_x64: "sha256:6ee2dce2752cbf67ee118fb6568bf0436aef6676cdf59afb4cc6075d2ad58994",
|
||||
macos_x64: "sha256:deecdf9f080347865df6b48031fb893e0cf0d87e8fa3e73c922d7e420cdd5c18",
|
||||
macos_arm64: "sha256:e9cd03c44ae4c4be56bfaea53191851b7aed1059ffe6e2dadb38e6171483b20c",
|
||||
linux_x64: "sha256:f7640e41fff1830fdb2a7d0aefbe8a5941e31de5a547eda43ec60d5b75b1605d",
|
||||
linux_arm64: "sha256:abf296d2bfd0fb3a4eceb3e55ea5dc9d1ed6683ada9cf4f36370e2f1eecde36e",
|
||||
windows_x64: "sha256:0d884056a42af3943a2d9b17eb862f199a5b763d132506036205853ffd499142",
|
||||
macos_x64: "sha256:5d34443bd0af95debbc9edbfea1ae6d45d78af26a6da1fe5f547b5824b63c2d0",
|
||||
macos_arm64: "sha256:e93c671629e6929cb0b3ebad2a8834641b77e4953c3038a50b29daeb2f36e070",
|
||||
linux_x64: "sha256:dd29cd82d8f89bc70d23011e9cc687d7d4d9631ef395ffeac43f605ab8409255",
|
||||
linux_arm64: "sha256:bf6380027b63e3758cdd29be7d35daaa02371ce60e285b7da3d37a2c3f950fc0",
|
||||
};
|
||||
|
||||
const _: () = {
|
||||
|
|
|
|||
|
|
@ -312,6 +312,19 @@ pub static LAZILY_LOADED_STATIC_ASSETS: Lazy<
|
|||
maybe_compressed_lib!("lib.webworker.d.ts"),
|
||||
maybe_compressed_lib!("lib.webworker.importscripts.d.ts"),
|
||||
maybe_compressed_lib!("lib.webworker.iterable.d.ts"),
|
||||
(
|
||||
// Special file that can be used to inject the @types/node package.
|
||||
// This is used for `node:` specifiers.
|
||||
"reference_types_node.d.ts",
|
||||
StaticAsset {
|
||||
is_lib: false,
|
||||
source: StaticAssetSource::Uncompressed(
|
||||
// causes either the built-in node types to be used or it
|
||||
// prefers the @types/node if it exists
|
||||
"/// <reference lib=\"node\" />\n/// <reference types=\"npm:@types/node\" />\n",
|
||||
),
|
||||
},
|
||||
),
|
||||
])
|
||||
.into_iter()
|
||||
.chain(node_type_libs!())
|
||||
|
|
@ -767,7 +780,36 @@ fn resolve_non_graph_specifier_types(
|
|||
.ok(),
|
||||
)))
|
||||
} else {
|
||||
Ok(None)
|
||||
match NpmPackageReqReference::from_str(raw_specifier) {
|
||||
Ok(npm_req_ref) => {
|
||||
debug_assert_eq!(resolution_mode, ResolutionMode::Import);
|
||||
// This could occur when resolving npm:@types/node when it is
|
||||
// injected and not part of the graph
|
||||
let package_folder =
|
||||
npm.npm_resolver.resolve_pkg_folder_from_deno_module_req(
|
||||
npm_req_ref.req(),
|
||||
referrer,
|
||||
)?;
|
||||
let res_result = node_resolver
|
||||
.resolve_package_subpath_from_deno_module(
|
||||
&package_folder,
|
||||
npm_req_ref.sub_path(),
|
||||
Some(referrer),
|
||||
resolution_mode,
|
||||
NodeResolutionKind::Types,
|
||||
);
|
||||
let maybe_url = match res_result {
|
||||
Ok(url_or_path) => Some(url_or_path.into_url()?),
|
||||
Err(err) => match err.code() {
|
||||
NodeJsErrorCode::ERR_MODULE_NOT_FOUND
|
||||
| NodeJsErrorCode::ERR_TYPES_NOT_FOUND => None,
|
||||
_ => return Err(err.into()),
|
||||
},
|
||||
};
|
||||
Ok(Some(into_specifier_and_media_type(maybe_url)))
|
||||
}
|
||||
_ => Ok(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -943,7 +985,10 @@ pub fn resolve_specifier_for_tsc(
|
|||
) => {
|
||||
// it's most likely requesting the jsxImportSource, which isn't loaded
|
||||
// into the graph when not using jsx, so just ignore this error
|
||||
if specifier.ends_with("/jsx-runtime") {
|
||||
if specifier.ends_with("/jsx-runtime")
|
||||
// ignore in order to support attempt to load when it doesn't exist
|
||||
|| specifier == "npm:@types/node"
|
||||
{
|
||||
None
|
||||
} else {
|
||||
return Err(err.into());
|
||||
|
|
|
|||
|
|
@ -650,6 +650,7 @@ struct GraphWalker<'a> {
|
|||
maybe_hasher: Option<FastInsecureHasher>,
|
||||
seen: HashSet<&'a Url>,
|
||||
pending: VecDeque<(&'a Url, bool)>,
|
||||
has_seen_node_builtin: bool,
|
||||
roots: Vec<(ModuleSpecifier, MediaType)>,
|
||||
missing_diagnostics: tsc::Diagnostics,
|
||||
}
|
||||
|
|
@ -689,6 +690,7 @@ impl<'a> GraphWalker<'a> {
|
|||
graph.imports.len() + graph.specifiers_count(),
|
||||
),
|
||||
pending: VecDeque::new(),
|
||||
has_seen_node_builtin: false,
|
||||
roots: Vec::with_capacity(graph.imports.len() + graph.specifiers_count()),
|
||||
missing_diagnostics: Default::default(),
|
||||
}
|
||||
|
|
@ -736,7 +738,14 @@ impl<'a> GraphWalker<'a> {
|
|||
/// redirects resolved. We need to include all the emittable files in
|
||||
/// the roots, so they get type checked and optionally emitted,
|
||||
/// otherwise they would be ignored if only imported into JavaScript.
|
||||
pub fn into_tsc_roots(self) -> TscRoots {
|
||||
pub fn into_tsc_roots(mut self) -> TscRoots {
|
||||
if self.has_seen_node_builtin && !self.roots.is_empty() {
|
||||
// inject a specifier that will force node types to be resolved
|
||||
self.roots.push((
|
||||
ModuleSpecifier::parse("asset:///reference_types_node.d.ts").unwrap(),
|
||||
MediaType::Dts,
|
||||
));
|
||||
}
|
||||
TscRoots {
|
||||
roots: self.roots,
|
||||
missing_diagnostics: self.missing_diagnostics,
|
||||
|
|
@ -788,7 +797,7 @@ impl<'a> GraphWalker<'a> {
|
|||
Module::Wasm(module) => {
|
||||
maybe_module_dependencies = Some(&module.dependencies);
|
||||
}
|
||||
Module::Json(_) | Module::Node(_) | Module::Npm(_) => {}
|
||||
Module::Json(_) | Module::Npm(_) => {}
|
||||
Module::External(module) => {
|
||||
// NPM files for `"nodeModulesDir": "manual"`.
|
||||
let media_type = MediaType::from_specifier(&module.specifier);
|
||||
|
|
@ -796,6 +805,11 @@ impl<'a> GraphWalker<'a> {
|
|||
self.roots.push((module.specifier.clone(), media_type));
|
||||
}
|
||||
}
|
||||
Module::Node(_) => {
|
||||
if !self.has_seen_node_builtin {
|
||||
self.has_seen_node_builtin = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if module.media_type().is_declaration() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"args": "check -q --all main.ts",
|
||||
"output": "",
|
||||
"variants": {
|
||||
"tsgo": {
|
||||
"use_tsgo": "1"
|
||||
},
|
||||
"tsc": {
|
||||
"use_tsgo": ""
|
||||
}
|
||||
},
|
||||
"envs": {
|
||||
"DENO_UNSTABLE_TSGO": "${use_tsgo}"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
// Notice there's no "node" here. In this case, it
|
||||
// should inject and use the built-in types
|
||||
"lib": ["deno.window"]
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
import { test } from "node:test";
|
||||
|
||||
test("test", (ctx) => {
|
||||
console.log(ctx);
|
||||
});
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"tempDir": true,
|
||||
"steps": [{
|
||||
"args": "install",
|
||||
"output": "[WILDCARD]"
|
||||
}, {
|
||||
"args": "check --all --quiet main.ts",
|
||||
"output": ""
|
||||
}],
|
||||
"variants": {
|
||||
"tsgo": {
|
||||
"use_tsgo": "1"
|
||||
},
|
||||
"tsc": {
|
||||
"use_tsgo": ""
|
||||
}
|
||||
},
|
||||
"envs": {
|
||||
"DENO_UNSTABLE_TSGO": "${use_tsgo}"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
// Notice there's no "node" here, but the user still
|
||||
// has a @types/node specified.
|
||||
"lib": ["deno.window"]
|
||||
},
|
||||
"imports": {
|
||||
"@types/node": "npm:@types/node"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
import { test } from "node:test";
|
||||
|
||||
test("test", (ctx) => {
|
||||
console.log(ctx);
|
||||
});
|
||||
15
tests/specs/check/node_types_lib/__test__.jsonc
Normal file
15
tests/specs/check/node_types_lib/__test__.jsonc
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"args": "check -q --all main.ts",
|
||||
"output": "",
|
||||
"variants": {
|
||||
"tsgo": {
|
||||
"use_tsgo": "1"
|
||||
},
|
||||
"tsc": {
|
||||
"use_tsgo": ""
|
||||
}
|
||||
},
|
||||
"envs": {
|
||||
"DENO_UNSTABLE_TSGO": "${use_tsgo}"
|
||||
}
|
||||
}
|
||||
6
tests/specs/check/node_types_lib/main.ts
Normal file
6
tests/specs/check/node_types_lib/main.ts
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
/// <reference lib="node" />
|
||||
import { test } from "node:test";
|
||||
|
||||
test("test", (ctx) => {
|
||||
console.log(ctx);
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue