# 5.4 Module Specifier

The initial task for executing a program involves creating a module specifier designated for the main module. In Deno, the main module serves as the initial piece of code, file, or program that is provided as input. This core module is also referred to as the root module or the main module.

```rust
let main_module = cli_options.resolve_main_module()?;
```

## Overview

The concept of a "Module Specifier" permeates throughout Deno's codebase. Essentially, the role of a Module Specifier in Deno is to transform an input path into a URL format. This format can take on various forms, such as "file," "http," or "https" URLs. This URL format is crucial because it helps Deno accurately locate and access the required modules, whether they are local files or resources from the web.

The code to resolve the main module is as follows:

```rust
DenoSubcommand::Run(run_flags) => {
  if run_flags.is_stdin() {
    std::env::current_dir()
      .context("Unable to get CWD")
      .and_then(|cwd| {
        resolve_url_or_path("./$deno$stdin.ts", &cwd)
          .map_err(AnyError::from)
      })
  } else if run_flags.watch.is_some() {
    resolve_url_or_path(&run_flags.script, self.initial_cwd())
      .map_err(AnyError::from)
  } else if NpmPackageReqReference::from_str(&run_flags.script).is_ok() {
    ModuleSpecifier::parse(&run_flags.script).map_err(AnyError::from)
  } else {
    resolve_url_or_path(&run_flags.script, self.initial_cwd())
      .map_err(AnyError::from)
  }
}
```

The main interface is called "resolve\_url\_or\_path," and it's also used by various other subcommands. This interface combines two distinct functionalities: resolving URLs and resolving file paths. These functionalities are designed to take the input, which could be either a URL or a file path, and convert it into a format that adheres to a Uniform Resource Identifier (URI) scheme. This applies to different types of files, whether they are stored locally or accessed remotely. As a result of using this interface, you obtain an object known as the "ModuleSpecifier," which encapsulates the resolved information about the input. &#x20;

## Functionality

As we discussed previously, the primary API called resolve\_url\_or\_path carries out two main functions:

* resolve\_url
* resolve\_path

Just as the names imply, the initial function is used for resolving a URL, whereas the latter one is employed to resolve a local file path. This means that the first function helps in figuring out the details of a web address, while the second function assists in determining the specifics of a file's location on your device.&#x20;

![](/files/-MOTTC4THnO7c69bcTlq)

### resolve\_url\_or\_path

Here is the source of the function resolve\_url\_or\_path:

```rust
pub fn resolve_url_or_path(
  specifier: &str,
  current_dir: &Path,
) -> Result<ModuleSpecifier, ModuleResolutionError> {
  if specifier_has_uri_scheme(specifier) {
    resolve_url(specifier)
  } else {
    resolve_path(specifier, current_dir)
  }
}
```

The code is quite straightforward.&#x20;

* If input already has a URI scheme
  * resolve as URL
* Otherwise,
  * resolve as a path (for local files)

Let's take an example to understand this better.&#x20;

<pre class="language-bash"><code class="lang-bash">> deno run helloLog.ts

// RESOLVED PATH -- 

file:///Users/mayankc/Work/source/deno-vs-nodejs/helloLog.ts

// -- 

<strong>> deno run https://raw.githubusercontent.com/mayankchoubey/deno-vs-nodejs/master/helloLog.ts
</strong>
// RESOLVED PATH -- 

https://raw.githubusercontent.com/mayankchoubey/deno-vs-nodejs/master/helloLog.ts
</code></pre>

The source code for the `resolve_url` function is also straightforward. It's not overly complex and can be easily understood.

```rust
pub fn resolve_url(
  url_str: &str,
) -> Result<ModuleSpecifier, ModuleResolutionError> {
  Url::parse(url_str).map_err(ModuleResolutionError::InvalidUrl)
}
```

Since the input is already in the form of a URL, we proceed to parse the URL mainly to validate its correctness. Now, let's look into the source of the resolve\_path function, which is quite straightforward:

```rust
pub fn resolve_path(
  path_str: &str,
  current_dir: &Path,
) -> Result<ModuleSpecifier, ModuleResolutionError> {
  let path = current_dir.join(path_str);
  let path = normalize_path(path);
  Url::from_file_path(&path)
    .map_err(|()| ModuleResolutionError::InvalidPath(path))
}
```

In resolving the path, it takes three steps:

* Append current directory path to input path
  * Example: `/Users/mayankc/Work/source/denoExamples/` + `helloLog.ts`
* The path is normalized
  * Example: `/Users/mayankc/Work/source/denoExamples/` + `../../ABC.ts` gets normalized to `/Users/mayankc/Work/ABC.ts`
* Build a file URI scheme from the path
  * Example: `/Users/mayankc/Work/source/denoExamples/helloLog.ts` gets converted to `file:///Users/mayankc/Work/source/denoExamples/helloLog.ts`

### resolve\_import

Up until now, we have examined how Deno handles the determination of the main module. This module refers to the primary file specified when using the 'deno run' command. But what about imports? It's important to note that imports also undergo a comparable resolution process. While we're discussing this subject, let's look into the concept of import resolution. It's worth mentioning that we will explore imports more extensively in Chapter 6 of this book. This will provide us with a deeper understanding of how Deno manages and resolves imported modules.&#x20;

```rust
pub fn resolve_import(
  specifier: &str,
  base: &str,
) -> Result<ModuleSpecifier, ModuleResolutionError> {
  let url = match Url::parse(specifier) {
    // 1. Apply the URL parser to specifier.
    //    If the result is not failure, return he result.
    Ok(url) => url,

    // 2. If specifier does not start with the character U+002F SOLIDUS (/),
    //    the two-character sequence U+002E FULL STOP, U+002F SOLIDUS (./),
    //    or the three-character sequence U+002E FULL STOP, U+002E FULL STOP,
    //    U+002F SOLIDUS (../), return failure.
    Err(ParseError::RelativeUrlWithoutBase)
      if !(specifier.starts_with('/')
        || specifier.starts_with("./")
        || specifier.starts_with("../")) =>
    {
      let maybe_referrer = if base.is_empty() {
        None
      } else {
        Some(base.to_string())
      };
      return Err(ImportPrefixMissing(specifier.to_string(), maybe_referrer));
    }

    // 3. Return the result of applying the URL parser to specifier with base
    //    URL as the base URL.
    Err(ParseError::RelativeUrlWithoutBase) => {
      let base = Url::parse(base).map_err(InvalidBaseUrl)?;
      base.join(specifier).map_err(InvalidUrl)?
    }

    // If parsing the specifier as a URL failed for a different reason than
    // it being relative, always return the original error. We don't want to
    // return `ImportPrefixMissing` or `InvalidBaseUrl` if the real
    // problem lies somewhere else.
    Err(err) => return Err(InvalidUrl(err)),
  };

  Ok(url)
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://choubey.gitbook.io/internals-of-deno/foundations/resolve_url_or_path.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
