summaryrefslogtreecommitdiff
path: root/cli/tsc
diff options
context:
space:
mode:
authorBartek IwaƄczuk <biwanczuk@gmail.com>2023-01-24 15:05:54 +0100
committerGitHub <noreply@github.com>2023-01-24 09:05:54 -0500
commitfc2e00152b162280e78b06028d51274e33275629 (patch)
treeee567a99cabc6633454de231939f7d898146f1d8 /cli/tsc
parentcadeaae045d2489fe125286b8c2c641c6d973c3f (diff)
feat: support node built-in module imports (#17264)
Co-authored-by: David Sherret <dsherret@gmail.com>
Diffstat (limited to 'cli/tsc')
-rw-r--r--cli/tsc/00_typescript.js15
-rw-r--r--cli/tsc/99_main_compiler.js26
-rw-r--r--cli/tsc/compiler.d.ts1
-rw-r--r--cli/tsc/diagnostics.rs8
-rw-r--r--cli/tsc/mod.rs214
5 files changed, 143 insertions, 121 deletions
diff --git a/cli/tsc/00_typescript.js b/cli/tsc/00_typescript.js
index 789de3a66..3fbf4624a 100644
--- a/cli/tsc/00_typescript.js
+++ b/cli/tsc/00_typescript.js
@@ -91389,10 +91389,15 @@ var ts;
var deno;
(function (deno) {
var isNodeSourceFile = function () { return false; };
+ var nodeBuiltInModuleNames = new ts.Set();
function setIsNodeSourceFileCallback(callback) {
isNodeSourceFile = callback;
}
deno.setIsNodeSourceFileCallback = setIsNodeSourceFileCallback;
+ function setNodeBuiltInModuleNames(names) {
+ nodeBuiltInModuleNames = new ts.Set(names);
+ }
+ deno.setNodeBuiltInModuleNames = setNodeBuiltInModuleNames;
// When upgrading:
// 1. Inspect all usages of "globals" and "globalThisSymbol" in checker.ts
// - Beware that `globalThisType` might refer to the global `this` type
@@ -91452,8 +91457,16 @@ var ts;
function getGlobalsForName(id) {
// Node ambient modules are only accessible in the node code,
// so put them on the node globals
- if (ambientModuleSymbolRegex.test(id))
+ if (ambientModuleSymbolRegex.test(id)) {
+ if (id.startsWith('"node:')) {
+ // check if it's a node specifier that we support
+ var name = id.slice(6, -1);
+ if (nodeBuiltInModuleNames.has(name)) {
+ return globals;
+ }
+ }
return nodeGlobals;
+ }
return nodeOnlyGlobalNames.has(id) ? nodeGlobals : globals;
}
function mergeGlobalSymbolTable(node, source, unidirectional) {
diff --git a/cli/tsc/99_main_compiler.js b/cli/tsc/99_main_compiler.js
index a0219fe13..138b24ba0 100644
--- a/cli/tsc/99_main_compiler.js
+++ b/cli/tsc/99_main_compiler.js
@@ -855,25 +855,7 @@ delete Object.prototype.__proto__;
...program.getOptionsDiagnostics(),
...program.getGlobalDiagnostics(),
...program.getSemanticDiagnostics(),
- ].filter((diagnostic) => {
- if (IGNORED_DIAGNOSTICS.includes(diagnostic.code)) {
- return false;
- } else if (
- diagnostic.code === 1259 &&
- typeof diagnostic.messageText === "string" &&
- diagnostic.messageText.startsWith(
- "Module '\"deno:///missing_dependency.d.ts\"' can only be default-imported using the 'allowSyntheticDefaultImports' flag",
- )
- ) {
- // For now, ignore diagnostics like:
- // > TS1259 [ERROR]: Module '"deno:///missing_dependency.d.ts"' can only be default-imported using the 'allowSyntheticDefaultImports' flag
- // This diagnostic has surfaced due to supporting node cjs imports because this module does `export =`.
- // See discussion in https://github.com/microsoft/TypeScript/pull/51136
- return false;
- } else {
- return true;
- }
- });
+ ].filter((diagnostic) => !IGNORED_DIAGNOSTICS.includes(diagnostic.code));
// emit the tsbuildinfo file
// @ts-ignore: emitBuildInfo is not exposed (https://github.com/microsoft/TypeScript/issues/49871)
@@ -1273,9 +1255,11 @@ delete Object.prototype.__proto__;
// A build time only op that provides some setup information that is used to
// ensure the snapshot is setup properly.
- /** @type {{ buildSpecifier: string; libs: string[] }} */
+ /** @type {{ buildSpecifier: string; libs: string[]; nodeBuiltInModuleNames: string[] }} */
+ const { buildSpecifier, libs, nodeBuiltInModuleNames } = ops.op_build_info();
+
+ ts.deno.setNodeBuiltInModuleNames(nodeBuiltInModuleNames);
- const { buildSpecifier, libs } = ops.op_build_info();
for (const lib of libs) {
const specifier = `lib.${lib}.d.ts`;
// we are using internal APIs here to "inject" our custom libraries into
diff --git a/cli/tsc/compiler.d.ts b/cli/tsc/compiler.d.ts
index ab6f95bd3..03784ae84 100644
--- a/cli/tsc/compiler.d.ts
+++ b/cli/tsc/compiler.d.ts
@@ -30,6 +30,7 @@ declare global {
function setIsNodeSourceFileCallback(
callback: (sourceFile: SourceFile) => boolean,
);
+ function setNodeBuiltInModuleNames(names: string[]);
}
}
diff --git a/cli/tsc/diagnostics.rs b/cli/tsc/diagnostics.rs
index fb7304c9b..b3026d934 100644
--- a/cli/tsc/diagnostics.rs
+++ b/cli/tsc/diagnostics.rs
@@ -299,9 +299,11 @@ impl Diagnostic {
fn fmt_related_information(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(related_information) = self.related_information.as_ref() {
- write!(f, "\n\n")?;
- for info in related_information {
- info.fmt_stack(f, 4)?;
+ if !related_information.is_empty() {
+ write!(f, "\n\n")?;
+ for info in related_information {
+ info.fmt_stack(f, 4)?;
+ }
}
}
diff --git a/cli/tsc/mod.rs b/cli/tsc/mod.rs
index 3da2f5f25..439a0de20 100644
--- a/cli/tsc/mod.rs
+++ b/cli/tsc/mod.rs
@@ -165,6 +165,12 @@ pub static LAZILY_LOADED_STATIC_ASSETS: Lazy<
"lib.webworker.iterable.d.ts",
inc!("lib.webworker.iterable.d.ts"),
),
+ (
+ // Special file that can be used to inject the @types/node package.
+ // This is used for `node:` specifiers.
+ "node_types.d.ts",
+ "/// <reference types=\"npm:@types/node\" />\n",
+ ),
])
.iter()
.cloned()
@@ -599,117 +605,133 @@ fn op_resolve(
"Error converting a string module specifier for \"op_resolve\".",
)?
};
- for specifier in &args.specifiers {
+ for specifier in args.specifiers {
+ if let Some(module_name) = specifier.strip_prefix("node:") {
+ if crate::node::resolve_builtin_node_module(module_name).is_ok() {
+ // return itself for node: specifiers because during type checking
+ // we resolve to the ambient modules in the @types/node package
+ // rather than deno_std/node
+ resolved.push((specifier, MediaType::Dts.to_string()));
+ continue;
+ }
+ }
+
if specifier.starts_with("asset:///") {
- resolved.push((
- specifier.clone(),
- MediaType::from(specifier).as_ts_extension().to_string(),
- ));
- } else {
- let graph_data = state.graph_data.read();
- let resolved_dep = match graph_data.get_dependencies(&referrer) {
- Some(dependencies) => dependencies.get(specifier).map(|d| {
- if matches!(d.maybe_type, Resolved::Ok { .. }) {
- &d.maybe_type
- } else {
- &d.maybe_code
- }
- }),
- None => None,
- };
- let maybe_result = match resolved_dep {
- Some(Resolved::Ok { specifier, .. }) => {
- let specifier = graph_data.follow_redirect(specifier);
- match graph_data.get(&specifier) {
- Some(ModuleEntry::Module {
- media_type,
- maybe_types,
- ..
- }) => match maybe_types {
- Some(Resolved::Ok { specifier, .. }) => {
- let types = graph_data.follow_redirect(specifier);
- match graph_data.get(&types) {
- Some(ModuleEntry::Module { media_type, .. }) => {
- Some((types, *media_type))
- }
- _ => None,
+ let media_type =
+ MediaType::from(&specifier).as_ts_extension().to_string();
+ resolved.push((specifier, media_type));
+ continue;
+ }
+
+ let graph_data = state.graph_data.read();
+ let resolved_dep = match graph_data.get_dependencies(&referrer) {
+ Some(dependencies) => dependencies.get(&specifier).map(|d| {
+ if matches!(d.maybe_type, Resolved::Ok { .. }) {
+ &d.maybe_type
+ } else {
+ &d.maybe_code
+ }
+ }),
+ None => None,
+ };
+ let maybe_result = match resolved_dep {
+ Some(Resolved::Ok { specifier, .. }) => {
+ let specifier = graph_data.follow_redirect(specifier);
+ match graph_data.get(&specifier) {
+ Some(ModuleEntry::Module {
+ media_type,
+ maybe_types,
+ ..
+ }) => match maybe_types {
+ Some(Resolved::Ok { specifier, .. }) => {
+ let types = graph_data.follow_redirect(specifier);
+ match graph_data.get(&types) {
+ Some(ModuleEntry::Module { media_type, .. }) => {
+ Some((types, *media_type))
}
+ _ => None,
}
- _ => Some((specifier, *media_type)),
- },
- _ => {
- // handle npm:<package> urls
- if let Ok(npm_ref) =
- NpmPackageReference::from_specifier(&specifier)
- {
- if let Some(npm_resolver) = &state.maybe_npm_resolver {
- Some(resolve_npm_package_reference_types(
- &npm_ref,
- npm_resolver,
- )?)
- } else {
- None
- }
+ }
+ _ => Some((specifier, *media_type)),
+ },
+ _ => {
+ // handle npm:<package> urls
+ if let Ok(npm_ref) = NpmPackageReference::from_specifier(&specifier)
+ {
+ if let Some(npm_resolver) = &state.maybe_npm_resolver {
+ Some(resolve_npm_package_reference_types(
+ &npm_ref,
+ npm_resolver,
+ )?)
} else {
None
}
- }
- }
- }
- _ => {
- state.maybe_npm_resolver.as_ref().and_then(|npm_resolver| {
- if npm_resolver.in_npm_package(&referrer) {
- // we're in an npm package, so use node resolution
- Some(NodeResolution::into_specifier_and_media_type(
- node::node_resolve(
- specifier,
- &referrer,
- NodeResolutionMode::Types,
- npm_resolver,
- &mut PermissionsContainer::allow_all(),
- )
- .ok()
- .flatten(),
- ))
} else {
None
}
- })
+ }
}
- };
- let result = match maybe_result {
- Some((specifier, media_type)) => {
- let specifier_str = match specifier.scheme() {
- "data" | "blob" => {
- let specifier_str = hash_url(&specifier, media_type);
+ }
+ _ => {
+ if let Some(npm_resolver) = state.maybe_npm_resolver.as_ref() {
+ if npm_resolver.in_npm_package(&referrer) {
+ // we're in an npm package, so use node resolution
+ Some(NodeResolution::into_specifier_and_media_type(
+ node::node_resolve(
+ &specifier,
+ &referrer,
+ NodeResolutionMode::Types,
+ npm_resolver,
+ &mut PermissionsContainer::allow_all(),
+ )
+ .ok()
+ .flatten(),
+ ))
+ } else if let Ok(npm_ref) = NpmPackageReference::from_str(&specifier)
+ {
+ // this could occur when resolving npm:@types/node when it is
+ // injected and not part of the graph
+ Some(resolve_npm_package_reference_types(&npm_ref, npm_resolver)?)
+ } else {
+ None
+ }
+ } else {
+ None
+ }
+ }
+ };
+ let result = match maybe_result {
+ Some((specifier, media_type)) => {
+ let specifier_str = match specifier.scheme() {
+ "data" | "blob" => {
+ let specifier_str = hash_url(&specifier, media_type);
+ state
+ .remapped_specifiers
+ .insert(specifier_str.clone(), specifier);
+ specifier_str
+ }
+ _ => {
+ if let Some(specifier_str) =
+ maybe_remap_specifier(&specifier, media_type)
+ {
state
.remapped_specifiers
.insert(specifier_str.clone(), specifier);
specifier_str
+ } else {
+ specifier.to_string()
}
- _ => {
- if let Some(specifier_str) =
- maybe_remap_specifier(&specifier, media_type)
- {
- state
- .remapped_specifiers
- .insert(specifier_str.clone(), specifier);
- specifier_str
- } else {
- specifier.to_string()
- }
- }
- };
- (specifier_str, media_type.as_ts_extension().into())
- }
- None => (
- "deno:///missing_dependency.d.ts".to_string(),
- ".d.ts".to_string(),
- ),
- };
- log::debug!("Resolved {} to {:?}", specifier, result);
- resolved.push(result);
- }
+ }
+ };
+ (specifier_str, media_type.as_ts_extension().into())
+ }
+ None => (
+ "deno:///missing_dependency.d.ts".to_string(),
+ ".d.ts".to_string(),
+ ),
+ };
+ log::debug!("Resolved {} to {:?}", specifier, result);
+ resolved.push(result);
}
Ok(resolved)