Repository: denoland/deno
Pull request: fix(install/global): do not error if path is an npm pkg and relative file

Closes https://github.com/denoland/deno/issues/26969

Changed files:
filename: cli/tools/installer.rs
patch: @@ -359,6 +359,7 @@ async fn install_global(
   // ensure the module is cached
   let factory = CliFactory::from_flags(flags.clone());
 
+  let cli_options = factory.cli_options()?;
   let http_client = factory.http_client_provider();
   let deps_http_cache = factory.global_http_cache()?;
   let mut deps_file_fetcher = FileFetcher::new(
@@ -381,20 +382,22 @@ async fn install_global(
   ));
 
   let entry_text = install_flags_global.module_url.as_str();
-  let req = super::registry::AddRmPackageReq::parse(entry_text);
-
-  // found a package requirement but missing the prefix
-  if let Ok(Err(package_req)) = req {
-    if jsr_resolver.req_to_nv(&package_req).await.is_some() {
-      bail!(
-        "{entry_text} is missing a prefix. Did you mean `{}`?",
-        crate::colors::yellow(format!("deno install -g jsr:{package_req}"))
-      );
-    } else if npm_resolver.req_to_nv(&package_req).await.is_some() {
-      bail!(
-        "{entry_text} is missing a prefix. Did you mean `{}`?",
-        crate::colors::yellow(format!("deno install -g npm:{package_req}"))
-      );
+  if !cli_options.initial_cwd().join(entry_text).exists() {
+    // check for package requirement missing prefix
+    if let Ok(Err(package_req)) =
+      super::registry::AddRmPackageReq::parse(entry_text)
+    {
+      if jsr_resolver.req_to_nv(&package_req).await.is_some() {
+        bail!(
+          "{entry_text} is missing a prefix. Did you mean `{}`?",
+          crate::colors::yellow(format!("deno install -g jsr:{package_req}"))
+        );
+      } else if npm_resolver.req_to_nv(&package_req).await.is_some() {
+        bail!(
+          "{entry_text} is missing a prefix. Did you mean `{}`?",
+          crate::colors::yellow(format!("deno install -g npm:{package_req}"))
+        );
+      }
     }
   }
 

filename: tests/registry/npm/cli.ts/registry.json
patch: @@ -0,0 +1,32 @@
+{
+  "name": "cli.ts",
+  "description": "Package with name like a file path",
+  "dist-tags": {
+    "latest": "2.2.0"
+  },
+  "versions": {
+    "2.2.0": {
+      "name": "cli.ts",
+      "version": "2.2.0",
+      "description": "Package with name like a file path",
+      "license": "MIT",
+      "author": {},
+      "engines": {
+        "node": ">=6"
+      },
+      "gitHead": "91440c5a1615354fb9419354650937c434eb9f49",
+      "_id": "cli.ts@2.2.0",
+      "_nodeVersion": "10.16.0",
+      "_npmVersion": "6.9.0",
+      "dist": {
+        "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
+        "shasum": "ee8472dbb129e727b31e8a10a427dee9dfe4008b",
+        "tarball": "http://localhost:4260/cli.ts/cli.ts-2.2.0.tgz",
+        "fileCount": 5,
+        "unpackedSize": 5508
+      },
+      "directories": {},
+      "_hasShrinkwrap": false
+    }
+  }
+}

filename: tests/specs/install/global/pkg_name_same_as_file/__test__.jsonc
patch: @@ -0,0 +1,20 @@
+{
+  "tempDir": true,
+  "tests": {
+    "file_exists": {
+      "steps": [{
+        "args": ["eval", "Deno.writeTextFileSync('cli.ts', '')"],
+        "output": "[WILDCARD]"
+      }, {
+        // success
+        "args": "install --root ./bins -g --name my-cli cli.ts",
+        "output": "[WILDCARD]"
+      }]
+    },
+    "file_not_exists": {
+      "args": "install --root ./bins -g --name my-cli cli.ts",
+      "output": "file_not_exists.out",
+      "exitCode": 1
+    }
+  }
+}

filename: tests/specs/install/global/pkg_name_same_as_file/file_not_exists.out
patch: @@ -0,0 +1 @@
+error: cli.ts is missing a prefix. Did you mean `deno install -g npm:cli.ts`?