diff options
author | haturau <135221985+haturatu@users.noreply.github.com> | 2024-11-20 01:20:47 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-11-20 01:20:47 +0900 |
commit | 85719a67e59c7aa45bead26e4942d7df8b1b42d4 (patch) | |
tree | face0aecaac53e93ce2f23b53c48859bcf1a36ec /cli/tsc | |
parent | 67697bc2e4a62a9670699fd18ad0dd8efc5bd955 (diff) | |
parent | 186b52731c6bb326c4d32905c5e732d082e83465 (diff) |
Merge branch 'denoland:main' into main
Diffstat (limited to 'cli/tsc')
-rw-r--r-- | cli/tsc/99_main_compiler.js | 105 | ||||
-rw-r--r-- | cli/tsc/diagnostics.rs | 2 | ||||
-rw-r--r-- | cli/tsc/dts/lib.deno.ns.d.ts | 44 | ||||
-rw-r--r-- | cli/tsc/dts/lib.deno.unstable.d.ts | 93 | ||||
-rw-r--r-- | cli/tsc/mod.rs | 221 |
5 files changed, 335 insertions, 130 deletions
diff --git a/cli/tsc/99_main_compiler.js b/cli/tsc/99_main_compiler.js index 719f2b982..68d099253 100644 --- a/cli/tsc/99_main_compiler.js +++ b/cli/tsc/99_main_compiler.js @@ -121,8 +121,8 @@ delete Object.prototype.__proto__; /** @type {Map<string, ts.SourceFile>} */ const sourceFileCache = new Map(); - /** @type {Map<string, string>} */ - const sourceTextCache = new Map(); + /** @type {Map<string, ts.IScriptSnapshot & { isCjs?: boolean; }>} */ + const scriptSnapshotCache = new Map(); /** @type {Map<string, number>} */ const sourceRefCounts = new Map(); @@ -133,9 +133,6 @@ delete Object.prototype.__proto__; /** @type {Map<string, boolean>} */ const isNodeSourceFileCache = new Map(); - /** @type {Map<string, boolean>} */ - const isCjsCache = new Map(); - // Maps asset specifiers to the first scope that the asset was loaded into. /** @type {Map<string, string | null>} */ const assetScopes = new Map(); @@ -210,12 +207,13 @@ delete Object.prototype.__proto__; const mapKey = path + key; let sourceFile = documentRegistrySourceFileCache.get(mapKey); if (!sourceFile || sourceFile.version !== version) { + const isCjs = /** @type {any} */ (scriptSnapshot).isCjs; sourceFile = ts.createLanguageServiceSourceFile( fileName, scriptSnapshot, { ...getCreateSourceFileOptions(sourceFileOptions), - impliedNodeFormat: (isCjsCache.get(fileName) ?? false) + impliedNodeFormat: isCjs ? ts.ModuleKind.CommonJS : ts.ModuleKind.ESNext, // in the lsp we want to be able to show documentation @@ -320,7 +318,7 @@ delete Object.prototype.__proto__; if (lastRequestMethod != "cleanupSemanticCache") { const mapKey = path + key; documentRegistrySourceFileCache.delete(mapKey); - sourceTextCache.delete(path); + scriptSnapshotCache.delete(path); ops.op_release(path); } } else { @@ -516,7 +514,6 @@ delete Object.prototype.__proto__; /** @typedef {{ * ls: ts.LanguageService & { [k:string]: any }, * compilerOptions: ts.CompilerOptions, - * forceEnabledVerbatimModuleSyntax: boolean, * }} LanguageServiceEntry */ /** @type {{ unscoped: LanguageServiceEntry, byScope: Map<string, LanguageServiceEntry> }} */ const languageServiceEntries = { @@ -625,8 +622,6 @@ delete Object.prototype.__proto__; `"data" is unexpectedly null for "${specifier}".`, ); - isCjsCache.set(specifier, isCjs); - sourceFile = ts.createSourceFile( specifier, data, @@ -700,7 +695,7 @@ delete Object.prototype.__proto__; /** @type {[string, ts.Extension] | undefined} */ const resolved = ops.op_resolve( containingFilePath, - isCjsCache.get(containingFilePath) ?? false, + containingFileMode === ts.ModuleKind.CommonJS, [fileReference.fileName], )?.[0]; if (resolved) { @@ -724,7 +719,14 @@ delete Object.prototype.__proto__; } }); }, - resolveModuleNames(specifiers, base) { + resolveModuleNames( + specifiers, + base, + _reusedNames, + _redirectedReference, + _options, + containingSourceFile, + ) { if (logDebug) { debug(`host.resolveModuleNames()`); debug(` base: ${base}`); @@ -733,7 +735,7 @@ delete Object.prototype.__proto__; /** @type {Array<[string, ts.Extension] | undefined>} */ const resolved = ops.op_resolve( base, - isCjsCache.get(base) ?? false, + containingSourceFile?.impliedNodeFormat === ts.ModuleKind.CommonJS, specifiers, ); if (resolved) { @@ -802,27 +804,32 @@ delete Object.prototype.__proto__; if (logDebug) { debug(`host.getScriptSnapshot("${specifier}")`); } - const sourceFile = sourceFileCache.get(specifier); - if (sourceFile) { - if (!assetScopes.has(specifier)) { - assetScopes.set(specifier, lastRequestScope); + if (specifier.startsWith(ASSETS_URL_PREFIX)) { + const sourceFile = this.getSourceFile( + specifier, + ts.ScriptTarget.ESNext, + ); + if (sourceFile) { + if (!assetScopes.has(specifier)) { + assetScopes.set(specifier, lastRequestScope); + } + // This case only occurs for assets. + return ts.ScriptSnapshot.fromString(sourceFile.text); } - // This case only occurs for assets. - return ts.ScriptSnapshot.fromString(sourceFile.text); } - let sourceText = sourceTextCache.get(specifier); - if (sourceText == undefined) { + let scriptSnapshot = scriptSnapshotCache.get(specifier); + if (scriptSnapshot == undefined) { /** @type {{ data: string, version: string, isCjs: boolean }} */ const fileInfo = ops.op_load(specifier); if (!fileInfo) { return undefined; } - isCjsCache.set(specifier, fileInfo.isCjs); - sourceTextCache.set(specifier, fileInfo.data); + scriptSnapshot = ts.ScriptSnapshot.fromString(fileInfo.data); + scriptSnapshot.isCjs = fileInfo.isCjs; + scriptSnapshotCache.set(specifier, scriptSnapshot); scriptVersionCache.set(specifier, fileInfo.version); - sourceText = fileInfo.data; } - return ts.ScriptSnapshot.fromString(sourceText); + return scriptSnapshot; }, }; @@ -846,6 +853,8 @@ delete Object.prototype.__proto__; jqueryMessage, "Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_jQuery_Try_npm_i_save_dev_types_Slash_2592": jqueryMessage, + "Module_0_was_resolved_to_1_but_allowArbitraryExtensions_is_not_set_6263": + "Module '{0}' was resolved to '{1}', but importing these modules is not supported.", }; })()); @@ -1026,7 +1035,7 @@ delete Object.prototype.__proto__; : ts.sortAndDeduplicateDiagnostics( checkFiles.map((s) => program.getSemanticDiagnostics(s)).flat(), )), - ].filter(filterMapDiagnostic.bind(null, false)); + ].filter(filterMapDiagnostic); // emit the tsbuildinfo file // @ts-ignore: emitBuildInfo is not exposed (https://github.com/microsoft/TypeScript/issues/49871) @@ -1041,28 +1050,11 @@ delete Object.prototype.__proto__; debug("<<< exec stop"); } - /** - * @param {boolean} isLsp - * @param {ts.Diagnostic} diagnostic - */ - function filterMapDiagnostic(isLsp, diagnostic) { + /** @param {ts.Diagnostic} diagnostic */ + function filterMapDiagnostic(diagnostic) { if (IGNORED_DIAGNOSTICS.includes(diagnostic.code)) { return false; } - if (isLsp) { - // TS1484: `...` is a type and must be imported using a type-only import when 'verbatimModuleSyntax' is enabled. - // We force-enable `verbatimModuleSyntax` in the LSP so the `type` - // modifier is used when auto-importing types. But we don't want this - // diagnostic unless it was explicitly enabled by the user. - if (diagnostic.code == 1484) { - const entry = (lastRequestScope - ? languageServiceEntries.byScope.get(lastRequestScope) - : null) ?? languageServiceEntries.unscoped; - if (entry.forceEnabledVerbatimModuleSyntax) { - return false; - } - } - } // make the diagnostic for using an `export =` in an es module a warning if (diagnostic.code === 1203) { diagnostic.category = ts.DiagnosticCategory.Warning; @@ -1159,12 +1151,10 @@ delete Object.prototype.__proto__; "strict": true, "target": "esnext", "useDefineForClassFields": true, - "verbatimModuleSyntax": true, "jsx": "react", "jsxFactory": "React.createElement", "jsxFragmentFactory": "React.Fragment", }), - forceEnabledVerbatimModuleSyntax: true, }; setLogDebug(enableDebugLogging, "TSLS"); debug("serverInit()"); @@ -1230,17 +1220,8 @@ delete Object.prototype.__proto__; const ls = oldEntry ? oldEntry.ls : ts.createLanguageService(host, documentRegistry); - let forceEnabledVerbatimModuleSyntax = false; - if (!config["verbatimModuleSyntax"]) { - config["verbatimModuleSyntax"] = true; - forceEnabledVerbatimModuleSyntax = true; - } const compilerOptions = lspTsConfigToCompilerOptions(config); - newByScope.set(scope, { - ls, - compilerOptions, - forceEnabledVerbatimModuleSyntax, - }); + newByScope.set(scope, { ls, compilerOptions }); languageServiceEntries.byScope.delete(scope); } for (const oldEntry of languageServiceEntries.byScope.values()) { @@ -1260,7 +1241,7 @@ delete Object.prototype.__proto__; closed = true; } scriptVersionCache.delete(script); - sourceTextCache.delete(script); + scriptSnapshotCache.delete(script); } if (newConfigsByScope || opened || closed) { @@ -1305,7 +1286,7 @@ delete Object.prototype.__proto__; ...ls.getSemanticDiagnostics(specifier), ...ls.getSuggestionDiagnostics(specifier), ...ls.getSyntacticDiagnostics(specifier), - ].filter(filterMapDiagnostic.bind(null, true))); + ].filter(filterMapDiagnostic)); } return respond(id, diagnosticMap); } catch (e) { @@ -1366,18 +1347,12 @@ delete Object.prototype.__proto__; "console", "Console", "ErrorConstructor", - "exports", "gc", "Global", "ImportMeta", "localStorage", - "module", - "NodeModule", - "NodeRequire", - "process", "queueMicrotask", "RequestInit", - "require", "ResponseInit", "sessionStorage", "setImmediate", diff --git a/cli/tsc/diagnostics.rs b/cli/tsc/diagnostics.rs index b0394ec17..d3795706e 100644 --- a/cli/tsc/diagnostics.rs +++ b/cli/tsc/diagnostics.rs @@ -323,7 +323,7 @@ impl Diagnostics { // todo(dsherret): use a short lived cache to prevent parsing // source maps so often if let Ok(source_map) = - SourceMap::from_slice(&fast_check_module.source_map) + SourceMap::from_slice(fast_check_module.source_map.as_bytes()) { if let Some(start) = d.start.as_mut() { let maybe_token = source_map diff --git a/cli/tsc/dts/lib.deno.ns.d.ts b/cli/tsc/dts/lib.deno.ns.d.ts index 36592e10d..8179e4223 100644 --- a/cli/tsc/dts/lib.deno.ns.d.ts +++ b/cli/tsc/dts/lib.deno.ns.d.ts @@ -556,14 +556,23 @@ declare namespace Deno { */ env?: "inherit" | boolean | string[]; - /** Specifies if the `sys` permission should be requested or revoked. - * If set to `"inherit"`, the current `sys` permission will be inherited. - * If set to `true`, the global `sys` permission will be requested. - * If set to `false`, the global `sys` permission will be revoked. + /** Specifies if the `ffi` permission should be requested or revoked. + * If set to `"inherit"`, the current `ffi` permission will be inherited. + * If set to `true`, the global `ffi` permission will be requested. + * If set to `false`, the global `ffi` permission will be revoked. * * @default {false} */ - sys?: "inherit" | boolean | string[]; + ffi?: "inherit" | boolean | Array<string | URL>; + + /** Specifies if the `import` permission should be requested or revoked. + * If set to `"inherit"` the current `import` permission will be inherited. + * If set to `true`, the global `import` permission will be requested. + * If set to `false`, the global `import` permission will be revoked. + * If set to `Array<string>`, the `import` permissions will be requested with the + * specified domains. + */ + import?: "inherit" | boolean | Array<string>; /** Specifies if the `net` permission should be requested or revoked. * if set to `"inherit"`, the current `net` permission will be inherited. @@ -638,15 +647,6 @@ declare namespace Deno { */ net?: "inherit" | boolean | string[]; - /** Specifies if the `ffi` permission should be requested or revoked. - * If set to `"inherit"`, the current `ffi` permission will be inherited. - * If set to `true`, the global `ffi` permission will be requested. - * If set to `false`, the global `ffi` permission will be revoked. - * - * @default {false} - */ - ffi?: "inherit" | boolean | Array<string | URL>; - /** Specifies if the `read` permission should be requested or revoked. * If set to `"inherit"`, the current `read` permission will be inherited. * If set to `true`, the global `read` permission will be requested. @@ -667,6 +667,15 @@ declare namespace Deno { */ run?: "inherit" | boolean | Array<string | URL>; + /** Specifies if the `sys` permission should be requested or revoked. + * If set to `"inherit"`, the current `sys` permission will be inherited. + * If set to `true`, the global `sys` permission will be requested. + * If set to `false`, the global `sys` permission will be revoked. + * + * @default {false} + */ + sys?: "inherit" | boolean | string[]; + /** Specifies if the `write` permission should be requested or revoked. * If set to `"inherit"`, the current `write` permission will be inherited. * If set to `true`, the global `write` permission will be requested. @@ -2962,6 +2971,10 @@ declare namespace Deno { * field from `stat` on Mac/BSD and `ftCreationTime` on Windows. This may * not be available on all platforms. */ birthtime: Date | null; + /** The last change time of the file. This corresponds to the `ctime` + * field from `stat` on Mac/BSD and `ChangeTime` on Windows. This may + * not be available on all platforms. */ + ctime: Date | null; /** ID of the device containing the file. */ dev: number; /** Inode number. @@ -2970,8 +2983,7 @@ declare namespace Deno { ino: number | null; /** The underlying raw `st_mode` bits that contain the standard Unix * permissions for this file/directory. - * - * _Linux/Mac OS only._ */ + */ mode: number | null; /** Number of hard links pointing to this file. * diff --git a/cli/tsc/dts/lib.deno.unstable.d.ts b/cli/tsc/dts/lib.deno.unstable.d.ts index 973a09d92..6759856e6 100644 --- a/cli/tsc/dts/lib.deno.unstable.d.ts +++ b/cli/tsc/dts/lib.deno.unstable.d.ts @@ -1181,6 +1181,32 @@ declare namespace Deno { ): Displayable; /** + * Display a JPG or PNG image. + * + * ``` + * Deno.jupyter.image("./cat.jpg"); + * Deno.jupyter.image("./dog.png"); + * ``` + * + * @category Jupyter + * @experimental + */ + export function image(path: string): Displayable; + + /** + * Display a JPG or PNG image. + * + * ``` + * const img = Deno.readFileSync("./cat.jpg"); + * Deno.jupyter.image(img); + * ``` + * + * @category Jupyter + * @experimental + */ + export function image(data: Uint8Array): Displayable; + + /** * Format an object for displaying in Deno * * @param obj - The object to be displayed @@ -1225,6 +1251,73 @@ declare namespace Deno { export {}; // only export exports } + /** + * **UNSTABLE**: New API, yet to be vetted. + * + * APIs for working with the OpenTelemetry observability framework. Deno can + * export traces, metrics, and logs to OpenTelemetry compatible backends via + * the OTLP protocol. + * + * Deno automatically instruments the runtime with OpenTelemetry traces and + * metrics. This data is exported via OTLP to OpenTelemetry compatible + * backends. User logs from the `console` API are exported as OpenTelemetry + * logs via OTLP. + * + * User code can also create custom traces, metrics, and logs using the + * OpenTelemetry API. This is done using the official OpenTelemetry package + * for JavaScript: + * [`npm:@opentelemetry/api`](https://opentelemetry.io/docs/languages/js/). + * Deno integrates with this package to provide trace context propagation + * between native Deno APIs (like `Deno.serve` or `fetch`) and custom user + * code. Deno also provides APIs that allow exporting custom telemetry data + * via the same OTLP channel used by the Deno runtime. This is done using the + * [`jsr:@deno/otel`](https://jsr.io/@deno/otel) package. + * + * @example Using OpenTelemetry API to create custom traces + * ```ts,ignore + * import { trace } from "npm:@opentelemetry/api@1"; + * import "jsr:@deno/otel@0.0.2/register"; + * + * const tracer = trace.getTracer("example-tracer"); + * + * async function doWork() { + * return tracer.startActiveSpan("doWork", async (span) => { + * span.setAttribute("key", "value"); + * await new Promise((resolve) => setTimeout(resolve, 1000)); + * span.end(); + * }); + * } + * + * Deno.serve(async (req) => { + * await doWork(); + * const resp = await fetch("https://example.com"); + * return resp; + * }); + * ``` + * + * @category Telemetry + * @experimental + */ + export namespace telemetry { + /** + * A SpanExporter compatible with OpenTelemetry.js + * https://open-telemetry.github.io/opentelemetry-js/interfaces/_opentelemetry_sdk_trace_base.SpanExporter.html + * @category Telemetry + * @experimental + */ + export class SpanExporter {} + + /** + * A ContextManager compatible with OpenTelemetry.js + * https://open-telemetry.github.io/opentelemetry-js/interfaces/_opentelemetry_api.ContextManager.html + * @category Telemetry + * @experimental + */ + export class ContextManager {} + + export {}; // only export exports + } + export {}; // only export exports } diff --git a/cli/tsc/mod.rs b/cli/tsc/mod.rs index 0e3387494..8f8bed20a 100644 --- a/cli/tsc/mod.rs +++ b/cli/tsc/mod.rs @@ -3,10 +3,13 @@ use crate::args::TsConfig; use crate::args::TypeCheckMode; use crate::cache::FastInsecureHasher; +use crate::cache::ModuleInfoCache; use crate::node; use crate::npm::CliNpmResolver; +use crate::resolver::CjsTracker; use crate::util::checksum; use crate::util::path::mapped_specifier_for_tsc; +use crate::worker::create_isolate_create_params; use deno_ast::MediaType; use deno_core::anyhow::anyhow; @@ -31,12 +34,14 @@ use deno_graph::GraphKind; use deno_graph::Module; use deno_graph::ModuleGraph; use deno_graph::ResolutionResolved; +use deno_resolver::npm::ResolvePkgFolderFromDenoReqError; +use deno_runtime::deno_fs; use deno_runtime::deno_node::NodeResolver; use deno_semver::npm::NpmPackageReqReference; use node_resolver::errors::NodeJsErrorCode; use node_resolver::errors::NodeJsErrorCoded; +use node_resolver::errors::PackageSubpathResolveError; use node_resolver::NodeModuleKind; -use node_resolver::NodeResolution; use node_resolver::NodeResolutionMode; use once_cell::sync::Lazy; use std::borrow::Cow; @@ -45,6 +50,7 @@ use std::fmt; use std::path::Path; use std::path::PathBuf; use std::sync::Arc; +use thiserror::Error; mod diagnostics; @@ -299,8 +305,81 @@ pub struct EmittedFile { pub media_type: MediaType, } +pub fn into_specifier_and_media_type( + specifier: Option<ModuleSpecifier>, +) -> (ModuleSpecifier, MediaType) { + match specifier { + Some(specifier) => { + let media_type = MediaType::from_specifier(&specifier); + + (specifier, media_type) + } + None => ( + Url::parse("internal:///missing_dependency.d.ts").unwrap(), + MediaType::Dts, + ), + } +} + +#[derive(Debug)] +pub struct TypeCheckingCjsTracker { + cjs_tracker: Arc<CjsTracker>, + module_info_cache: Arc<ModuleInfoCache>, +} + +impl TypeCheckingCjsTracker { + pub fn new( + cjs_tracker: Arc<CjsTracker>, + module_info_cache: Arc<ModuleInfoCache>, + ) -> Self { + Self { + cjs_tracker, + module_info_cache, + } + } + + pub fn is_cjs( + &self, + specifier: &ModuleSpecifier, + media_type: MediaType, + code: &Arc<str>, + ) -> bool { + let maybe_is_script = self + .module_info_cache + .as_module_analyzer() + .analyze_sync(specifier, media_type, code) + .ok() + .map(|info| info.is_script); + maybe_is_script + .and_then(|is_script| { + self + .cjs_tracker + .is_cjs_with_known_is_script(specifier, media_type, is_script) + .ok() + }) + .unwrap_or_else(|| { + self + .cjs_tracker + .is_maybe_cjs(specifier, media_type) + .unwrap_or(false) + }) + } + + pub fn is_cjs_with_known_is_script( + &self, + specifier: &ModuleSpecifier, + media_type: MediaType, + is_script: bool, + ) -> Result<bool, node_resolver::errors::ClosestPkgJsonError> { + self + .cjs_tracker + .is_cjs_with_known_is_script(specifier, media_type, is_script) + } +} + #[derive(Debug)] pub struct RequestNpmState { + pub cjs_tracker: Arc<TypeCheckingCjsTracker>, pub node_resolver: Arc<NodeResolver>, pub npm_resolver: Arc<dyn CliNpmResolver>, } @@ -453,7 +532,7 @@ pub fn as_ts_script_kind(media_type: MediaType) -> i32 { MediaType::Tsx => 4, MediaType::Json => 6, MediaType::SourceMap - | MediaType::TsBuildInfo + | MediaType::Css | MediaType::Wasm | MediaType::Unknown => 0, } @@ -486,25 +565,22 @@ fn op_load_inner( ) -> Result<Option<LoadResponse>, AnyError> { fn load_from_node_modules( specifier: &ModuleSpecifier, - node_resolver: Option<&NodeResolver>, + npm_state: Option<&RequestNpmState>, media_type: &mut MediaType, is_cjs: &mut bool, ) -> Result<String, AnyError> { *media_type = MediaType::from_specifier(specifier); - *is_cjs = node_resolver - .map(|node_resolver| { - match node_resolver.url_to_node_resolution(specifier.clone()) { - Ok(NodeResolution::CommonJs(_)) => true, - Ok(NodeResolution::Esm(_)) - | Ok(NodeResolution::BuiltIn(_)) - | Err(_) => false, - } - }) - .unwrap_or(false); let file_path = specifier.to_file_path().unwrap(); let code = std::fs::read_to_string(&file_path) .with_context(|| format!("Unable to load {}", file_path.display()))?; - Ok(code) + let code: Arc<str> = code.into(); + *is_cjs = npm_state + .map(|npm_state| { + npm_state.cjs_tracker.is_cjs(specifier, *media_type, &code) + }) + .unwrap_or(false); + // todo(dsherret): how to avoid cloning here? + Ok(code.to_string()) } let state = state.borrow_mut::<State>(); @@ -557,6 +633,13 @@ fn op_load_inner( match module { Module::Js(module) => { media_type = module.media_type; + if let Some(npm_state) = &state.maybe_npm { + is_cjs = npm_state.cjs_tracker.is_cjs_with_known_is_script( + specifier, + module.media_type, + module.is_script, + )?; + } let source = module .fast_check_module() .map(|m| &*m.source) @@ -570,11 +653,13 @@ fn op_load_inner( Module::Npm(_) | Module::Node(_) => None, Module::External(module) => { // means it's Deno code importing an npm module - let specifier = - node::resolve_specifier_into_node_modules(&module.specifier); + let specifier = node::resolve_specifier_into_node_modules( + &module.specifier, + &deno_fs::RealFs, + ); Some(Cow::Owned(load_from_node_modules( &specifier, - state.maybe_npm.as_ref().map(|n| n.node_resolver.as_ref()), + state.maybe_npm.as_ref(), &mut media_type, &mut is_cjs, )?)) @@ -587,7 +672,7 @@ fn op_load_inner( { Some(Cow::Owned(load_from_node_modules( specifier, - Some(npm.node_resolver.as_ref()), + Some(npm), &mut media_type, &mut is_cjs, )?)) @@ -662,6 +747,7 @@ fn op_resolve_inner( "Error converting a string module specifier for \"op_resolve\".", )? }; + let referrer_module = state.graph.get(&referrer); for specifier in args.specifiers { if specifier.starts_with("node:") { resolved.push(( @@ -677,23 +763,44 @@ fn op_resolve_inner( continue; } - let graph = &state.graph; - let resolved_dep = graph - .get(&referrer) + let resolved_dep = referrer_module .and_then(|m| m.js()) .and_then(|m| m.dependencies_prefer_fast_check().get(&specifier)) .and_then(|d| d.maybe_type.ok().or_else(|| d.maybe_code.ok())); let maybe_result = match resolved_dep { Some(ResolutionResolved { specifier, .. }) => { - resolve_graph_specifier_types(specifier, &referrer, state)? + resolve_graph_specifier_types( + specifier, + &referrer, + referrer_kind, + state, + )? + } + _ => { + match resolve_non_graph_specifier_types( + &specifier, + &referrer, + referrer_kind, + state, + ) { + Ok(maybe_result) => maybe_result, + Err( + err @ ResolveNonGraphSpecifierTypesError::ResolvePkgFolderFromDenoReq( + ResolvePkgFolderFromDenoReqError::Managed(_), + ), + ) => { + // 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") { + None + } else { + return Err(err.into()); + } + } + Err(err) => return Err(err.into()), + } } - _ => resolve_non_graph_specifier_types( - &specifier, - &referrer, - referrer_kind, - state, - )?, }; let result = match maybe_result { Some((specifier, media_type)) => { @@ -718,7 +825,13 @@ fn op_resolve_inner( } } }; - (specifier_str, media_type.as_ts_extension()) + ( + specifier_str, + match media_type { + MediaType::Css => ".js", // surface these as .js for typescript + media_type => media_type.as_ts_extension(), + }, + ) } None => ( MISSING_DEPENDENCY_SPECIFIER.to_string(), @@ -735,6 +848,7 @@ fn op_resolve_inner( fn resolve_graph_specifier_types( specifier: &ModuleSpecifier, referrer: &ModuleSpecifier, + referrer_kind: NodeModuleKind, state: &State, ) -> Result<Option<(ModuleSpecifier, MediaType)>, AnyError> { let graph = &state.graph; @@ -787,43 +901,53 @@ fn resolve_graph_specifier_types( &package_folder, module.nv_reference.sub_path(), Some(referrer), + referrer_kind, NodeResolutionMode::Types, ); - let maybe_resolution = match res_result { - Ok(res) => Some(res), + let maybe_url = match res_result { + Ok(url) => Some(url), Err(err) => match err.code() { NodeJsErrorCode::ERR_TYPES_NOT_FOUND | NodeJsErrorCode::ERR_MODULE_NOT_FOUND => None, _ => return Err(err.into()), }, }; - Ok(Some(NodeResolution::into_specifier_and_media_type( - maybe_resolution, - ))) + Ok(Some(into_specifier_and_media_type(maybe_url))) } else { Ok(None) } } Some(Module::External(module)) => { // we currently only use "External" for when the module is in an npm package - Ok(state.maybe_npm.as_ref().map(|npm| { - let specifier = - node::resolve_specifier_into_node_modules(&module.specifier); - NodeResolution::into_specifier_and_media_type( - npm.node_resolver.url_to_node_resolution(specifier).ok(), - ) + Ok(state.maybe_npm.as_ref().map(|_| { + let specifier = node::resolve_specifier_into_node_modules( + &module.specifier, + &deno_fs::RealFs, + ); + into_specifier_and_media_type(Some(specifier)) })) } Some(Module::Node(_)) | None => Ok(None), } } +#[derive(Debug, Error)] +enum ResolveNonGraphSpecifierTypesError { + #[error(transparent)] + ResolvePkgFolderFromDenoReq(#[from] ResolvePkgFolderFromDenoReqError), + #[error(transparent)] + PackageSubpathResolve(#[from] PackageSubpathResolveError), +} + fn resolve_non_graph_specifier_types( raw_specifier: &str, referrer: &ModuleSpecifier, referrer_kind: NodeModuleKind, state: &State, -) -> Result<Option<(ModuleSpecifier, MediaType)>, AnyError> { +) -> Result< + Option<(ModuleSpecifier, MediaType)>, + ResolveNonGraphSpecifierTypesError, +> { let npm = match state.maybe_npm.as_ref() { Some(npm) => npm, None => return Ok(None), // we only support non-graph types for npm packages @@ -831,7 +955,7 @@ fn resolve_non_graph_specifier_types( let node_resolver = &npm.node_resolver; if node_resolver.in_npm_package(referrer) { // we're in an npm package, so use node resolution - Ok(Some(NodeResolution::into_specifier_and_media_type( + Ok(Some(into_specifier_and_media_type( node_resolver .resolve( raw_specifier, @@ -839,7 +963,8 @@ fn resolve_non_graph_specifier_types( referrer_kind, NodeResolutionMode::Types, ) - .ok(), + .ok() + .map(|res| res.into_url()), ))) } else if let Ok(npm_req_ref) = NpmPackageReqReference::from_str(raw_specifier) @@ -856,19 +981,18 @@ fn resolve_non_graph_specifier_types( &package_folder, npm_req_ref.sub_path(), Some(referrer), + referrer_kind, NodeResolutionMode::Types, ); - let maybe_resolution = match res_result { - Ok(res) => Some(res), + let maybe_url = match res_result { + Ok(url) => Some(url), Err(err) => match err.code() { NodeJsErrorCode::ERR_TYPES_NOT_FOUND | NodeJsErrorCode::ERR_MODULE_NOT_FOUND => None, _ => return Err(err.into()), }, }; - Ok(Some(NodeResolution::into_specifier_and_media_type( - maybe_resolution, - ))) + Ok(Some(into_specifier_and_media_type(maybe_url))) } else { Ok(None) } @@ -981,6 +1105,7 @@ pub fn exec(request: Request) -> Result<Response, AnyError> { root_map, remapped_specifiers, )], + create_params: create_isolate_create_params(), ..Default::default() }); |