summaryrefslogtreecommitdiff
path: root/cli/deno_dir.rs
diff options
context:
space:
mode:
authorRyan Dahl <ry@tinyclouds.org>2019-03-19 12:18:05 -0400
committerGitHub <noreply@github.com>2019-03-19 12:18:05 -0400
commitfa3c35301aa44975776b96c85f200de8eb500c22 (patch)
tree76f8d5e6f42e1c306a40efd0b80dce18528952f4 /cli/deno_dir.rs
parentc7d81fa9ff495986675c05e52e13acc9ffc85372 (diff)
Rename //src/ to //cli/ (#1962)
To better distinguish the deno_core crate from the executable deno, which will now be called "the cli" internally.
Diffstat (limited to 'cli/deno_dir.rs')
-rw-r--r--cli/deno_dir.rs1369
1 files changed, 1369 insertions, 0 deletions
diff --git a/cli/deno_dir.rs b/cli/deno_dir.rs
new file mode 100644
index 000000000..829af5aa2
--- /dev/null
+++ b/cli/deno_dir.rs
@@ -0,0 +1,1369 @@
+// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
+use crate::compiler::ModuleMetaData;
+use crate::errors;
+use crate::errors::DenoError;
+use crate::errors::DenoResult;
+use crate::errors::ErrorKind;
+use crate::fs as deno_fs;
+use crate::http_util;
+use crate::js_errors::SourceMapGetter;
+use crate::msg;
+use crate::version;
+
+use dirs;
+use ring;
+use std;
+use std::fmt::Write;
+use std::fs;
+use std::path::Path;
+use std::path::PathBuf;
+use std::result::Result;
+use std::str;
+use url;
+use url::Url;
+
+/// Gets corresponding MediaType given extension
+fn extmap(ext: &str) -> msg::MediaType {
+ match ext {
+ "ts" => msg::MediaType::TypeScript,
+ "js" => msg::MediaType::JavaScript,
+ "json" => msg::MediaType::Json,
+ _ => msg::MediaType::Unknown,
+ }
+}
+
+pub struct DenoDir {
+ // Example: /Users/rld/.deno/
+ pub root: PathBuf,
+ // In the Go code this was called SrcDir.
+ // This is where we cache http resources. Example:
+ // /Users/rld/.deno/deps/github.com/ry/blah.js
+ pub gen: PathBuf,
+ // In the Go code this was called CacheDir.
+ // This is where we cache compilation outputs. Example:
+ // /Users/rld/.deno/gen/f39a473452321cacd7c346a870efb0e3e1264b43.js
+ pub deps: PathBuf,
+ // This splits to http and https deps
+ pub deps_http: PathBuf,
+ pub deps_https: PathBuf,
+ // If remote resources should be reloaded.
+ reload: bool,
+ // recompile the typescript files.
+ // if true, not load cache files
+ // else, load cache files
+ recompile: bool,
+}
+
+impl DenoDir {
+ // Must be called before using any function from this module.
+ // https://github.com/denoland/deno/blob/golang/deno_dir.go#L99-L111
+ pub fn new(
+ reload: bool,
+ recompile: bool,
+ custom_root: Option<PathBuf>,
+ ) -> std::io::Result<Self> {
+ // Only setup once.
+ let home_dir = dirs::home_dir().expect("Could not get home directory.");
+ let fallback = home_dir.join(".deno");
+ // We use the OS cache dir because all files deno writes are cache files
+ // Once that changes we need to start using different roots if DENO_DIR
+ // is not set, and keep a single one if it is.
+ let default = dirs::cache_dir()
+ .map(|d| d.join("deno"))
+ .unwrap_or(fallback);
+
+ let root: PathBuf = custom_root.unwrap_or(default);
+ let gen = root.as_path().join("gen");
+ let deps = root.as_path().join("deps");
+ let deps_http = deps.join("http");
+ let deps_https = deps.join("https");
+
+ let deno_dir = Self {
+ root,
+ gen,
+ deps,
+ deps_http,
+ deps_https,
+ reload,
+ recompile,
+ };
+
+ // TODO Lazily create these directories.
+ deno_fs::mkdir(deno_dir.gen.as_ref(), 0o755, true)?;
+ deno_fs::mkdir(deno_dir.deps.as_ref(), 0o755, true)?;
+ deno_fs::mkdir(deno_dir.deps_http.as_ref(), 0o755, true)?;
+ deno_fs::mkdir(deno_dir.deps_https.as_ref(), 0o755, true)?;
+
+ debug!("root {}", deno_dir.root.display());
+ debug!("gen {}", deno_dir.gen.display());
+ debug!("deps {}", deno_dir.deps.display());
+ debug!("deps_http {}", deno_dir.deps_http.display());
+ debug!("deps_https {}", deno_dir.deps_https.display());
+
+ Ok(deno_dir)
+ }
+
+ // https://github.com/denoland/deno/blob/golang/deno_dir.go#L32-L35
+ pub fn cache_path(
+ self: &Self,
+ filename: &str,
+ source_code: &[u8],
+ ) -> (PathBuf, PathBuf) {
+ let cache_key = source_code_hash(filename, source_code, version::DENO);
+ (
+ self.gen.join(cache_key.to_string() + ".js"),
+ self.gen.join(cache_key.to_string() + ".js.map"),
+ )
+ }
+
+ fn load_cache(
+ self: &Self,
+ filename: &str,
+ source_code: &[u8],
+ ) -> Result<(Vec<u8>, Vec<u8>), std::io::Error> {
+ let (output_code, source_map) = self.cache_path(filename, source_code);
+ debug!(
+ "load_cache code: {} map: {}",
+ output_code.display(),
+ source_map.display()
+ );
+ let read_output_code = fs::read(&output_code)?;
+ let read_source_map = fs::read(&source_map)?;
+ Ok((read_output_code, read_source_map))
+ }
+
+ pub fn code_cache(
+ self: &Self,
+ module_meta_data: &ModuleMetaData,
+ ) -> std::io::Result<()> {
+ let (cache_path, source_map_path) = self
+ .cache_path(&module_meta_data.filename, &module_meta_data.source_code);
+ // TODO(ry) This is a race condition w.r.t to exists() -- probably should
+ // create the file in exclusive mode. A worry is what might happen is there
+ // are two processes and one reads the cache file while the other is in the
+ // midst of writing it.
+ if cache_path.exists() && source_map_path.exists() {
+ Ok(())
+ } else {
+ match &module_meta_data.maybe_output_code {
+ Some(output_code) => fs::write(cache_path, output_code),
+ _ => Ok(()),
+ }?;
+ match &module_meta_data.maybe_source_map {
+ Some(source_map) => fs::write(source_map_path, source_map),
+ _ => Ok(()),
+ }?;
+ Ok(())
+ }
+ }
+
+ // Prototype https://github.com/denoland/deno/blob/golang/deno_dir.go#L37-L73
+ /// Fetch remote source code.
+ fn fetch_remote_source(
+ self: &Self,
+ module_name: &str,
+ filename: &str,
+ ) -> DenoResult<Option<ModuleMetaData>> {
+ let p = Path::new(&filename);
+ // We write a special ".mime" file into the `.deno/deps` directory along side the
+ // cached file, containing just the media type.
+ let media_type_filename = [&filename, ".mime"].concat();
+ let mt = Path::new(&media_type_filename);
+ eprint!("Downloading {}...", &module_name); // no newline
+ let maybe_source = http_util::fetch_sync_string(&module_name);
+ if let Ok((source, content_type)) = maybe_source {
+ eprintln!(""); // next line
+ match p.parent() {
+ Some(ref parent) => fs::create_dir_all(parent),
+ None => Ok(()),
+ }?;
+ deno_fs::write_file(&p, &source, 0o666)?;
+ // Remove possibly existing stale .mime file
+ // may not exist. DON'T unwrap
+ let _ = std::fs::remove_file(&media_type_filename);
+ // Create .mime file only when content type different from extension
+ let resolved_content_type = map_content_type(&p, Some(&content_type));
+ let ext = p
+ .extension()
+ .map(|x| x.to_str().unwrap_or(""))
+ .unwrap_or("");
+ let media_type = extmap(&ext);
+ if media_type == msg::MediaType::Unknown
+ || media_type != resolved_content_type
+ {
+ deno_fs::write_file(&mt, content_type.as_bytes(), 0o666)?
+ }
+ return Ok(Some(ModuleMetaData {
+ module_name: module_name.to_string(),
+ filename: filename.to_string(),
+ media_type: map_content_type(&p, Some(&content_type)),
+ source_code: source.as_bytes().to_owned(),
+ maybe_output_code_filename: None,
+ maybe_output_code: None,
+ maybe_source_map_filename: None,
+ maybe_source_map: None,
+ }));
+ } else {
+ eprintln!(" NOT FOUND");
+ }
+ Ok(None)
+ }
+
+ /// Fetch local or cached source code.
+ fn fetch_local_source(
+ self: &Self,
+ module_name: &str,
+ filename: &str,
+ ) -> DenoResult<Option<ModuleMetaData>> {
+ let p = Path::new(&filename);
+ let media_type_filename = [&filename, ".mime"].concat();
+ let mt = Path::new(&media_type_filename);
+ let source_code = match fs::read(p) {
+ Err(e) => {
+ if e.kind() == std::io::ErrorKind::NotFound {
+ return Ok(None);
+ } else {
+ return Err(e.into());
+ }
+ }
+ Ok(c) => c,
+ };
+ // .mime file might not exists
+ // this is okay for local source: maybe_content_type_str will be None
+ let maybe_content_type_string = fs::read_to_string(&mt).ok();
+ // Option<String> -> Option<&str>
+ let maybe_content_type_str =
+ maybe_content_type_string.as_ref().map(String::as_str);
+ Ok(Some(ModuleMetaData {
+ module_name: module_name.to_string(),
+ filename: filename.to_string(),
+ media_type: map_content_type(&p, maybe_content_type_str),
+ source_code,
+ maybe_output_code_filename: None,
+ maybe_output_code: None,
+ maybe_source_map_filename: None,
+ maybe_source_map: None,
+ }))
+ }
+
+ // Prototype: https://github.com/denoland/deno/blob/golang/os.go#L122-L138
+ fn get_source_code(
+ self: &Self,
+ module_name: &str,
+ filename: &str,
+ ) -> DenoResult<ModuleMetaData> {
+ let is_module_remote = is_remote(module_name);
+ // We try fetch local. Two cases:
+ // 1. This is a remote module, but no reload provided
+ // 2. This is a local module
+ if !is_module_remote || !self.reload {
+ debug!(
+ "fetch local or reload {} is_module_remote {}",
+ module_name, is_module_remote
+ );
+ match self.fetch_local_source(&module_name, &filename)? {
+ Some(output) => {
+ debug!("found local source ");
+ return Ok(output);
+ }
+ None => {
+ debug!("fetch_local_source returned None");
+ }
+ }
+ }
+
+ // If not remote file, stop here!
+ if !is_module_remote {
+ debug!("not remote file stop here");
+ return Err(DenoError::from(std::io::Error::new(
+ std::io::ErrorKind::NotFound,
+ format!("cannot find local file '{}'", filename),
+ )));
+ }
+
+ debug!("is remote but didn't find module");
+
+ // not cached/local, try remote
+ let maybe_remote_source =
+ self.fetch_remote_source(&module_name, &filename)?;
+ if let Some(output) = maybe_remote_source {
+ return Ok(output);
+ }
+ Err(DenoError::from(std::io::Error::new(
+ std::io::ErrorKind::NotFound,
+ format!("cannot find remote file '{}'", filename),
+ )))
+ }
+
+ pub fn fetch_module_meta_data(
+ self: &Self,
+ specifier: &str,
+ referrer: &str,
+ ) -> Result<ModuleMetaData, errors::DenoError> {
+ debug!(
+ "fetch_module_meta_data. specifier {} referrer {}",
+ specifier, referrer
+ );
+
+ let (module_name, filename) = self.resolve_module(specifier, referrer)?;
+
+ let result = self.get_source_code(module_name.as_str(), filename.as_str());
+ let mut out = match result {
+ Ok(out) => out,
+ Err(err) => {
+ if err.kind() == ErrorKind::NotFound {
+ // For NotFound, change the message to something better.
+ return Err(errors::new(
+ ErrorKind::NotFound,
+ format!(
+ "Cannot resolve module \"{}\" from \"{}\"",
+ specifier, referrer
+ ),
+ ));
+ } else {
+ return Err(err);
+ }
+ }
+ };
+
+ if out.source_code.starts_with("#!".as_bytes()) {
+ out.source_code = filter_shebang(out.source_code);
+ }
+
+ if out.media_type != msg::MediaType::TypeScript {
+ return Ok(out);
+ }
+
+ let (output_code_filename, output_source_map_filename) =
+ self.cache_path(&out.filename, &out.source_code);
+ let mut maybe_output_code = None;
+ let mut maybe_source_map = None;
+
+ if !self.recompile {
+ let result = self.load_cache(out.filename.as_str(), &out.source_code);
+ match result {
+ Err(err) => {
+ if err.kind() == std::io::ErrorKind::NotFound {
+ return Ok(out);
+ } else {
+ return Err(err.into());
+ }
+ }
+ Ok((output_code, source_map)) => {
+ maybe_output_code = Some(output_code);
+ maybe_source_map = Some(source_map);
+ }
+ }
+ }
+
+ Ok(ModuleMetaData {
+ module_name: out.module_name,
+ filename: out.filename,
+ media_type: out.media_type,
+ source_code: out.source_code,
+ maybe_output_code_filename: output_code_filename
+ .to_str()
+ .map(String::from),
+ maybe_output_code,
+ maybe_source_map_filename: output_source_map_filename
+ .to_str()
+ .map(String::from),
+ maybe_source_map,
+ })
+ }
+
+ // Prototype: https://github.com/denoland/deno/blob/golang/os.go#L56-L68
+ fn src_file_to_url(self: &Self, filename: &str) -> String {
+ let filename_path = Path::new(filename);
+ if filename_path.starts_with(&self.deps) {
+ let (rest, prefix) = if filename_path.starts_with(&self.deps_https) {
+ let rest = filename_path.strip_prefix(&self.deps_https).unwrap();
+ let prefix = "https://".to_string();
+ (rest, prefix)
+ } else if filename_path.starts_with(&self.deps_http) {
+ let rest = filename_path.strip_prefix(&self.deps_http).unwrap();
+ let prefix = "http://".to_string();
+ (rest, prefix)
+ } else {
+ // TODO(kevinkassimo): change this to support other protocols than http
+ unimplemented!()
+ };
+ // Windows doesn't support ":" in filenames, so we represent port using a
+ // special string.
+ // TODO(ry) This current implementation will break on a URL that has
+ // the default port but contains "_PORT" in the path.
+ let rest = rest.to_str().unwrap().replacen("_PORT", ":", 1);
+ prefix + &rest
+ } else {
+ String::from(filename)
+ }
+ }
+
+ /// Returns (module name, local filename)
+ pub fn resolve_module_url(
+ self: &Self,
+ specifier: &str,
+ referrer: &str,
+ ) -> Result<Url, url::ParseError> {
+ let specifier = self.src_file_to_url(specifier);
+ let mut referrer = self.src_file_to_url(referrer);
+
+ debug!(
+ "resolve_module specifier {} referrer {}",
+ specifier, referrer
+ );
+
+ if referrer.starts_with('.') {
+ let cwd = std::env::current_dir().unwrap();
+ let referrer_path = cwd.join(referrer);
+ referrer = referrer_path.to_str().unwrap().to_string() + "/";
+ }
+
+ let j = if is_remote(&specifier) || Path::new(&specifier).is_absolute() {
+ parse_local_or_remote(&specifier)?
+ } else if referrer.ends_with('/') {
+ let r = Url::from_directory_path(&referrer);
+ // TODO(ry) Properly handle error.
+ if r.is_err() {
+ error!("Url::from_directory_path error {}", referrer);
+ }
+ let base = r.unwrap();
+ base.join(specifier.as_ref())?
+ } else {
+ let base = parse_local_or_remote(&referrer)?;
+ base.join(specifier.as_ref())?
+ };
+ Ok(j)
+ }
+
+ /// Returns (module name, local filename)
+ pub fn resolve_module(
+ self: &Self,
+ specifier: &str,
+ referrer: &str,
+ ) -> Result<(String, String), url::ParseError> {
+ let j = self.resolve_module_url(specifier, referrer)?;
+
+ let module_name = j.to_string();
+ let filename;
+ match j.scheme() {
+ "file" => {
+ filename = deno_fs::normalize_path(j.to_file_path().unwrap().as_ref());
+ }
+ "https" => {
+ filename = deno_fs::normalize_path(
+ get_cache_filename(self.deps_https.as_path(), &j).as_ref(),
+ )
+ }
+ "http" => {
+ filename = deno_fs::normalize_path(
+ get_cache_filename(self.deps_http.as_path(), &j).as_ref(),
+ )
+ }
+ // TODO(kevinkassimo): change this to support other protocols than http
+ _ => unimplemented!(),
+ }
+
+ debug!("module_name: {}, filename: {}", module_name, filename);
+ Ok((module_name, filename))
+ }
+}
+
+impl SourceMapGetter for DenoDir {
+ fn get_source_map(&self, script_name: &str) -> Option<Vec<u8>> {
+ match self.fetch_module_meta_data(script_name, ".") {
+ Err(_e) => None,
+ Ok(out) => match out.maybe_source_map {
+ None => None,
+ Some(source_map) => Some(source_map),
+ },
+ }
+ }
+}
+
+fn get_cache_filename(basedir: &Path, url: &Url) -> PathBuf {
+ let host = url.host_str().unwrap();
+ let host_port = match url.port() {
+ // Windows doesn't support ":" in filenames, so we represent port using a
+ // special string.
+ Some(port) => format!("{}_PORT{}", host, port),
+ None => host.to_string(),
+ };
+
+ let mut out = basedir.to_path_buf();
+ out.push(host_port);
+ for path_seg in url.path_segments().unwrap() {
+ out.push(path_seg);
+ }
+ out
+}
+
+fn source_code_hash(
+ filename: &str,
+ source_code: &[u8],
+ version: &str,
+) -> String {
+ let mut ctx = ring::digest::Context::new(&ring::digest::SHA1);
+ ctx.update(version.as_bytes());
+ ctx.update(filename.as_bytes());
+ ctx.update(source_code);
+ let digest = ctx.finish();
+ let mut out = String::new();
+ // TODO There must be a better way to do this...
+ for byte in digest.as_ref() {
+ write!(&mut out, "{:02x}", byte).unwrap();
+ }
+ out
+}
+
+fn is_remote(module_name: &str) -> bool {
+ module_name.starts_with("http://") || module_name.starts_with("https://")
+}
+
+fn parse_local_or_remote(p: &str) -> Result<url::Url, url::ParseError> {
+ if is_remote(p) || p.starts_with("file:") {
+ Url::parse(p)
+ } else {
+ Url::from_file_path(p).map_err(|_err| url::ParseError::IdnaError)
+ }
+}
+
+fn map_file_extension(path: &Path) -> msg::MediaType {
+ match path.extension() {
+ None => msg::MediaType::Unknown,
+ Some(os_str) => match os_str.to_str() {
+ Some("ts") => msg::MediaType::TypeScript,
+ Some("js") => msg::MediaType::JavaScript,
+ Some("json") => msg::MediaType::Json,
+ _ => msg::MediaType::Unknown,
+ },
+ }
+}
+
+// convert a ContentType string into a enumerated MediaType
+fn map_content_type(path: &Path, content_type: Option<&str>) -> msg::MediaType {
+ match content_type {
+ Some(content_type) => {
+ // sometimes there is additional data after the media type in
+ // Content-Type so we have to do a bit of manipulation so we are only
+ // dealing with the actual media type
+ let ct_vector: Vec<&str> = content_type.split(';').collect();
+ let ct: &str = ct_vector.first().unwrap();
+ match ct.to_lowercase().as_ref() {
+ "application/typescript"
+ | "text/typescript"
+ | "video/vnd.dlna.mpeg-tts"
+ | "video/mp2t"
+ | "application/x-typescript" => msg::MediaType::TypeScript,
+ "application/javascript"
+ | "text/javascript"
+ | "application/ecmascript"
+ | "text/ecmascript"
+ | "application/x-javascript" => msg::MediaType::JavaScript,
+ "application/json" | "text/json" => msg::MediaType::Json,
+ "text/plain" => map_file_extension(path),
+ _ => {
+ debug!("unknown content type: {}", content_type);
+ msg::MediaType::Unknown
+ }
+ }
+ }
+ None => map_file_extension(path),
+ }
+}
+
+fn filter_shebang(bytes: Vec<u8>) -> Vec<u8> {
+ let string = str::from_utf8(&bytes).unwrap();
+ if let Some(i) = string.find('\n') {
+ let (_, rest) = string.split_at(i);
+ rest.as_bytes().to_owned()
+ } else {
+ Vec::new()
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::tokio_util;
+ use tempfile::TempDir;
+
+ fn test_setup(reload: bool, recompile: bool) -> (TempDir, DenoDir) {
+ let temp_dir = TempDir::new().expect("tempdir fail");
+ let deno_dir =
+ DenoDir::new(reload, recompile, Some(temp_dir.path().to_path_buf()))
+ .expect("setup fail");
+ (temp_dir, deno_dir)
+ }
+
+ // The `add_root` macro prepends "C:" to a string if on windows; on posix
+ // systems it returns the input string untouched. This is necessary because
+ // `Url::from_file_path()` fails if the input path isn't an absolute path.
+ macro_rules! add_root {
+ ($path:expr) => {
+ if cfg!(target_os = "windows") {
+ concat!("C:", $path)
+ } else {
+ $path
+ }
+ };
+ }
+
+ macro_rules! file_url {
+ ($path:expr) => {
+ if cfg!(target_os = "windows") {
+ concat!("file:///C:", $path)
+ } else {
+ concat!("file://", $path)
+ }
+ };
+ }
+
+ #[test]
+ fn test_get_cache_filename() {
+ let url = Url::parse("http://example.com:1234/path/to/file.ts").unwrap();
+ let basedir = Path::new("/cache/dir/");
+ let cache_file = get_cache_filename(&basedir, &url);
+ assert_eq!(
+ cache_file,
+ Path::new("/cache/dir/example.com_PORT1234/path/to/file.ts")
+ );
+ }
+
+ #[test]
+ fn test_cache_path() {
+ let (temp_dir, deno_dir) = test_setup(false, false);
+ let filename = "hello.js";
+ let source_code = "1+2".as_bytes();
+ let hash = source_code_hash(filename, source_code, version::DENO);
+ assert_eq!(
+ (
+ temp_dir.path().join(format!("gen/{}.js", hash)),
+ temp_dir.path().join(format!("gen/{}.js.map", hash))
+ ),
+ deno_dir.cache_path(filename, source_code)
+ );
+ }
+
+ #[test]
+ fn test_code_cache() {
+ let (_temp_dir, deno_dir) = test_setup(false, false);
+
+ let filename = "hello.js";
+ let source_code = "1+2".as_bytes();
+ let output_code = "1+2 // output code".as_bytes();
+ let source_map = "{}".as_bytes();
+ let hash = source_code_hash(filename, source_code, version::DENO);
+ let (cache_path, source_map_path) =
+ deno_dir.cache_path(filename, source_code);
+ assert!(cache_path.ends_with(format!("gen/{}.js", hash)));
+ assert!(source_map_path.ends_with(format!("gen/{}.js.map", hash)));
+
+ let out = ModuleMetaData {
+ filename: filename.to_owned(),
+ source_code: source_code.to_owned(),
+ module_name: "hello.js".to_owned(),
+ media_type: msg::MediaType::TypeScript,
+ maybe_output_code: Some(output_code.to_owned()),
+ maybe_output_code_filename: None,
+ maybe_source_map: Some(source_map.to_owned()),
+ maybe_source_map_filename: None,
+ };
+
+ let r = deno_dir.code_cache(&out);
+ r.expect("code_cache error");
+ assert!(cache_path.exists());
+ assert_eq!(output_code.to_owned(), fs::read(&cache_path).unwrap());
+ }
+
+ #[test]
+ fn test_source_code_hash() {
+ assert_eq!(
+ "7e44de2ed9e0065da09d835b76b8d70be503d276",
+ source_code_hash("hello.ts", "1+2".as_bytes(), "0.2.11")
+ );
+ // Different source_code should result in different hash.
+ assert_eq!(
+ "57033366cf9db1ef93deca258cdbcd9ef5f4bde1",
+ source_code_hash("hello.ts", "1".as_bytes(), "0.2.11")
+ );
+ // Different filename should result in different hash.
+ assert_eq!(
+ "19657f90b5b0540f87679e2fb362e7bd62b644b0",
+ source_code_hash("hi.ts", "1+2".as_bytes(), "0.2.11")
+ );
+ // Different version should result in different hash.
+ assert_eq!(
+ "e2b4b7162975a02bf2770f16836eb21d5bcb8be1",
+ source_code_hash("hi.ts", "1+2".as_bytes(), "0.2.0")
+ );
+ }
+
+ #[test]
+ fn test_get_source_code_1() {
+ let (temp_dir, deno_dir) = test_setup(false, false);
+ // http_util::fetch_sync_string requires tokio
+ tokio_util::init(|| {
+ let module_name = "http://localhost:4545/tests/subdir/mod2.ts";
+ let filename = deno_fs::normalize_path(
+ deno_dir
+ .deps_http
+ .join("localhost_PORT4545/tests/subdir/mod2.ts")
+ .as_ref(),
+ );
+ let mime_file_name = format!("{}.mime", &filename);
+
+ let result = deno_dir.get_source_code(module_name, &filename);
+ println!("module_name {} filename {}", module_name, filename);
+ assert!(result.is_ok());
+ let r = result.unwrap();
+ assert_eq!(
+ r.source_code,
+ "export { printHello } from \"./print_hello.ts\";\n".as_bytes()
+ );
+ assert_eq!(&(r.media_type), &msg::MediaType::TypeScript);
+ // Should not create .mime file due to matching ext
+ assert!(fs::read_to_string(&mime_file_name).is_err());
+
+ // Modify .mime
+ let _ = fs::write(&mime_file_name, "text/javascript");
+ let result2 = deno_dir.get_source_code(module_name, &filename);
+ assert!(result2.is_ok());
+ let r2 = result2.unwrap();
+ assert_eq!(
+ r2.source_code,
+ "export { printHello } from \"./print_hello.ts\";\n".as_bytes()
+ );
+ // If get_source_code does not call remote, this should be JavaScript
+ // as we modified before! (we do not overwrite .mime due to no http fetch)
+ assert_eq!(&(r2.media_type), &msg::MediaType::JavaScript);
+ assert_eq!(
+ fs::read_to_string(&mime_file_name).unwrap(),
+ "text/javascript"
+ );
+
+ // Force self.reload
+ let deno_dir =
+ DenoDir::new(true, false, Some(temp_dir.path().to_path_buf()))
+ .expect("setup fail");
+ let result3 = deno_dir.get_source_code(module_name, &filename);
+ assert!(result3.is_ok());
+ let r3 = result3.unwrap();
+ let expected3 =
+ "export { printHello } from \"./print_hello.ts\";\n".as_bytes();
+ assert_eq!(r3.source_code, expected3);
+ // Now the old .mime file should have gone! Resolved back to TypeScript
+ assert_eq!(&(r3.media_type), &msg::MediaType::TypeScript);
+ assert!(fs::read_to_string(&mime_file_name).is_err());
+ });
+ }
+
+ #[test]
+ fn test_get_source_code_2() {
+ let (temp_dir, deno_dir) = test_setup(false, false);
+ // http_util::fetch_sync_string requires tokio
+ tokio_util::init(|| {
+ let module_name = "http://localhost:4545/tests/subdir/mismatch_ext.ts";
+ let filename = deno_fs::normalize_path(
+ deno_dir
+ .deps_http
+ .join("localhost_PORT4545/tests/subdir/mismatch_ext.ts")
+ .as_ref(),
+ );
+ let mime_file_name = format!("{}.mime", &filename);
+
+ let result = deno_dir.get_source_code(module_name, &filename);
+ println!("module_name {} filename {}", module_name, filename);
+ assert!(result.is_ok());
+ let r = result.unwrap();
+ let expected = "export const loaded = true;\n".as_bytes();
+ assert_eq!(r.source_code, expected);
+ // Mismatch ext with content type, create .mime
+ assert_eq!(&(r.media_type), &msg::MediaType::JavaScript);
+ assert_eq!(
+ fs::read_to_string(&mime_file_name).unwrap(),
+ "text/javascript"
+ );
+
+ // Modify .mime
+ let _ = fs::write(&mime_file_name, "text/typescript");
+ let result2 = deno_dir.get_source_code(module_name, &filename);
+ assert!(result2.is_ok());
+ let r2 = result2.unwrap();
+ let expected2 = "export const loaded = true;\n".as_bytes();
+ assert_eq!(r2.source_code, expected2);
+ // If get_source_code does not call remote, this should be TypeScript
+ // as we modified before! (we do not overwrite .mime due to no http fetch)
+ assert_eq!(&(r2.media_type), &msg::MediaType::TypeScript);
+ assert_eq!(
+ fs::read_to_string(&mime_file_name).unwrap(),
+ "text/typescript"
+ );
+
+ // Force self.reload
+ let deno_dir =
+ DenoDir::new(true, false, Some(temp_dir.path().to_path_buf()))
+ .expect("setup fail");
+ let result3 = deno_dir.get_source_code(module_name, &filename);
+ assert!(result3.is_ok());
+ let r3 = result3.unwrap();
+ let expected3 = "export const loaded = true;\n".as_bytes();
+ assert_eq!(r3.source_code, expected3);
+ // Now the old .mime file should be overwritten back to JavaScript!
+ // (due to http fetch)
+ assert_eq!(&(r3.media_type), &msg::MediaType::JavaScript);
+ assert_eq!(
+ fs::read_to_string(&mime_file_name).unwrap(),
+ "text/javascript"
+ );
+ });
+ }
+
+ #[test]
+ fn test_fetch_source_1() {
+ use crate::tokio_util;
+ // http_util::fetch_sync_string requires tokio
+ tokio_util::init(|| {
+ let (_temp_dir, deno_dir) = test_setup(false, false);
+ let module_name =
+ "http://localhost:4545/tests/subdir/mt_video_mp2t.t3.ts";
+ let filename = deno_fs::normalize_path(
+ deno_dir
+ .deps_http
+ .join("localhost_PORT4545/tests/subdir/mt_video_mp2t.t3.ts")
+ .as_ref(),
+ );
+ let mime_file_name = format!("{}.mime", &filename);
+
+ let result = deno_dir.fetch_remote_source(module_name, &filename);
+ assert!(result.is_ok());
+ let r = result.unwrap().unwrap();
+ assert_eq!(r.source_code, "export const loaded = true;\n".as_bytes());
+ assert_eq!(&(r.media_type), &msg::MediaType::TypeScript);
+ // matching ext, no .mime file created
+ assert!(fs::read_to_string(&mime_file_name).is_err());
+
+ // Modify .mime, make sure read from local
+ let _ = fs::write(&mime_file_name, "text/javascript");
+ let result2 = deno_dir.fetch_local_source(module_name, &filename);
+ assert!(result2.is_ok());
+ let r2 = result2.unwrap().unwrap();
+ assert_eq!(r2.source_code, "export const loaded = true;\n".as_bytes());
+ // Not MediaType::TypeScript due to .mime modification
+ assert_eq!(&(r2.media_type), &msg::MediaType::JavaScript);
+ });
+ }
+
+ #[test]
+ fn test_fetch_source_2() {
+ use crate::tokio_util;
+ // http_util::fetch_sync_string requires tokio
+ tokio_util::init(|| {
+ let (_temp_dir, deno_dir) = test_setup(false, false);
+ let module_name = "http://localhost:4545/tests/subdir/no_ext";
+ let filename = deno_fs::normalize_path(
+ deno_dir
+ .deps_http
+ .join("localhost_PORT4545/tests/subdir/no_ext")
+ .as_ref(),
+ );
+ let mime_file_name = format!("{}.mime", &filename);
+ let result = deno_dir.fetch_remote_source(module_name, &filename);
+ assert!(result.is_ok());
+ let r = result.unwrap().unwrap();
+ assert_eq!(r.source_code, "export const loaded = true;\n".as_bytes());
+ assert_eq!(&(r.media_type), &msg::MediaType::TypeScript);
+ // no ext, should create .mime file
+ assert_eq!(
+ fs::read_to_string(&mime_file_name).unwrap(),
+ "text/typescript"
+ );
+
+ let module_name_2 = "http://localhost:4545/tests/subdir/mismatch_ext.ts";
+ let filename_2 = deno_fs::normalize_path(
+ deno_dir
+ .deps_http
+ .join("localhost_PORT4545/tests/subdir/mismatch_ext.ts")
+ .as_ref(),
+ );
+ let mime_file_name_2 = format!("{}.mime", &filename_2);
+ let result_2 = deno_dir.fetch_remote_source(module_name_2, &filename_2);
+ assert!(result_2.is_ok());
+ let r2 = result_2.unwrap().unwrap();
+ assert_eq!(r2.source_code, "export const loaded = true;\n".as_bytes());
+ assert_eq!(&(r2.media_type), &msg::MediaType::JavaScript);
+ // mismatch ext, should create .mime file
+ assert_eq!(
+ fs::read_to_string(&mime_file_name_2).unwrap(),
+ "text/javascript"
+ );
+
+ // test unknown extension
+ let module_name_3 = "http://localhost:4545/tests/subdir/unknown_ext.deno";
+ let filename_3 = deno_fs::normalize_path(
+ deno_dir
+ .deps_http
+ .join("localhost_PORT4545/tests/subdir/unknown_ext.deno")
+ .as_ref(),
+ );
+ let mime_file_name_3 = format!("{}.mime", &filename_3);
+ let result_3 = deno_dir.fetch_remote_source(module_name_3, &filename_3);
+ assert!(result_3.is_ok());
+ let r3 = result_3.unwrap().unwrap();
+ assert_eq!(r3.source_code, "export const loaded = true;\n".as_bytes());
+ assert_eq!(&(r3.media_type), &msg::MediaType::TypeScript);
+ // unknown ext, should create .mime file
+ assert_eq!(
+ fs::read_to_string(&mime_file_name_3).unwrap(),
+ "text/typescript"
+ );
+ });
+ }
+
+ #[test]
+ fn test_fetch_source_3() {
+ // only local, no http_util::fetch_sync_string called
+ let (_temp_dir, deno_dir) = test_setup(false, false);
+ let cwd = std::env::current_dir().unwrap();
+ let cwd_string = cwd.to_str().unwrap();
+ let module_name = "http://example.com/mt_text_typescript.t1.ts"; // not used
+ let filename =
+ format!("{}/tests/subdir/mt_text_typescript.t1.ts", &cwd_string);
+
+ let result = deno_dir.fetch_local_source(module_name, &filename);
+ assert!(result.is_ok());
+ let r = result.unwrap().unwrap();
+ assert_eq!(r.source_code, "export const loaded = true;\n".as_bytes());
+ assert_eq!(&(r.media_type), &msg::MediaType::TypeScript);
+ }
+
+ #[test]
+ fn test_fetch_module_meta_data() {
+ let (_temp_dir, deno_dir) = test_setup(false, false);
+
+ let cwd = std::env::current_dir().unwrap();
+ let cwd_string = String::from(cwd.to_str().unwrap()) + "/";
+
+ // Test failure case.
+ let specifier = "hello.ts";
+ let referrer = add_root!("/baddir/badfile.ts");
+ let r = deno_dir.fetch_module_meta_data(specifier, referrer);
+ assert!(r.is_err());
+
+ // Assuming cwd is the deno repo root.
+ let specifier = "./js/main.ts";
+ let referrer = cwd_string.as_str();
+ let r = deno_dir.fetch_module_meta_data(specifier, referrer);
+ assert!(r.is_ok());
+ //let fetch_module_meta_data_output = r.unwrap();
+ //println!("fetch_module_meta_data_output {:?}", fetch_module_meta_data_output);
+ }
+
+ #[test]
+ fn test_fetch_module_meta_data_1() {
+ /*recompile ts file*/
+ let (_temp_dir, deno_dir) = test_setup(false, true);
+
+ let cwd = std::env::current_dir().unwrap();
+ let cwd_string = String::from(cwd.to_str().unwrap()) + "/";
+
+ // Test failure case.
+ let specifier = "hello.ts";
+ let referrer = add_root!("/baddir/badfile.ts");
+ let r = deno_dir.fetch_module_meta_data(specifier, referrer);
+ assert!(r.is_err());
+
+ // Assuming cwd is the deno repo root.
+ let specifier = "./js/main.ts";
+ let referrer = cwd_string.as_str();
+ let r = deno_dir.fetch_module_meta_data(specifier, referrer);
+ assert!(r.is_ok());
+ }
+
+ #[test]
+ fn test_src_file_to_url_1() {
+ let (_temp_dir, deno_dir) = test_setup(false, false);
+ assert_eq!("hello", deno_dir.src_file_to_url("hello"));
+ assert_eq!("/hello", deno_dir.src_file_to_url("/hello"));
+ let x = deno_dir.deps_http.join("hello/world.txt");
+ assert_eq!(
+ "http://hello/world.txt",
+ deno_dir.src_file_to_url(x.to_str().unwrap())
+ );
+ }
+
+ #[test]
+ fn test_src_file_to_url_2() {
+ let (_temp_dir, deno_dir) = test_setup(false, false);
+ assert_eq!("hello", deno_dir.src_file_to_url("hello"));
+ assert_eq!("/hello", deno_dir.src_file_to_url("/hello"));
+ let x = deno_dir.deps_https.join("hello/world.txt");
+ assert_eq!(
+ "https://hello/world.txt",
+ deno_dir.src_file_to_url(x.to_str().unwrap())
+ );
+ }
+
+ #[test]
+ fn test_src_file_to_url_3() {
+ let (_temp_dir, deno_dir) = test_setup(false, false);
+ let x = deno_dir.deps_http.join("localhost_PORT4545/world.txt");
+ assert_eq!(
+ "http://localhost:4545/world.txt",
+ deno_dir.src_file_to_url(x.to_str().unwrap())
+ );
+ }
+
+ #[test]
+ fn test_src_file_to_url_4() {
+ let (_temp_dir, deno_dir) = test_setup(false, false);
+ let x = deno_dir.deps_https.join("localhost_PORT4545/world.txt");
+ assert_eq!(
+ "https://localhost:4545/world.txt",
+ deno_dir.src_file_to_url(x.to_str().unwrap())
+ );
+ }
+
+ // https://github.com/denoland/deno/blob/golang/os_test.go#L16-L87
+ #[test]
+ fn test_resolve_module_1() {
+ let (_temp_dir, deno_dir) = test_setup(false, false);
+
+ let test_cases = [
+ (
+ "./subdir/print_hello.ts",
+ add_root!("/Users/rld/go/src/github.com/denoland/deno/testdata/006_url_imports.ts"),
+ file_url!("/Users/rld/go/src/github.com/denoland/deno/testdata/subdir/print_hello.ts"),
+ add_root!("/Users/rld/go/src/github.com/denoland/deno/testdata/subdir/print_hello.ts"),
+ ),
+ (
+ "testdata/001_hello.js",
+ add_root!("/Users/rld/go/src/github.com/denoland/deno/"),
+ file_url!("/Users/rld/go/src/github.com/denoland/deno/testdata/001_hello.js"),
+ add_root!("/Users/rld/go/src/github.com/denoland/deno/testdata/001_hello.js"),
+ ),
+ (
+ add_root!("/Users/rld/src/deno/hello.js"),
+ ".",
+ file_url!("/Users/rld/src/deno/hello.js"),
+ add_root!("/Users/rld/src/deno/hello.js"),
+ ),
+ (
+ add_root!("/this/module/got/imported.js"),
+ add_root!("/that/module/did/it.js"),
+ file_url!("/this/module/got/imported.js"),
+ add_root!("/this/module/got/imported.js"),
+ ),
+ ];
+ for &test in test_cases.iter() {
+ let specifier = String::from(test.0);
+ let referrer = String::from(test.1);
+ let (module_name, filename) =
+ deno_dir.resolve_module(&specifier, &referrer).unwrap();
+ assert_eq!(module_name, test.2);
+ assert_eq!(filename, test.3);
+ }
+ }
+
+ #[test]
+ fn test_resolve_module_2() {
+ let (_temp_dir, deno_dir) = test_setup(false, false);
+
+ let specifier = "http://localhost:4545/testdata/subdir/print_hello.ts";
+ let referrer = add_root!("/deno/testdata/006_url_imports.ts");
+
+ let expected_module_name =
+ "http://localhost:4545/testdata/subdir/print_hello.ts";
+ let expected_filename = deno_fs::normalize_path(
+ deno_dir
+ .deps_http
+ .join("localhost_PORT4545/testdata/subdir/print_hello.ts")
+ .as_ref(),
+ );
+
+ let (module_name, filename) =
+ deno_dir.resolve_module(specifier, referrer).unwrap();
+ assert_eq!(module_name, expected_module_name);
+ assert_eq!(filename, expected_filename);
+ }
+
+ #[test]
+ fn test_resolve_module_3() {
+ let (_temp_dir, deno_dir) = test_setup(false, false);
+
+ let specifier_ =
+ deno_dir.deps_http.join("unpkg.com/liltest@0.0.5/index.ts");
+ let specifier = specifier_.to_str().unwrap();
+ let referrer = ".";
+
+ let expected_module_name = "http://unpkg.com/liltest@0.0.5/index.ts";
+ let expected_filename = deno_fs::normalize_path(
+ deno_dir
+ .deps_http
+ .join("unpkg.com/liltest@0.0.5/index.ts")
+ .as_ref(),
+ );
+
+ let (module_name, filename) =
+ deno_dir.resolve_module(specifier, referrer).unwrap();
+ assert_eq!(module_name, expected_module_name);
+ assert_eq!(filename, expected_filename);
+ }
+
+ #[test]
+ fn test_resolve_module_4() {
+ let (_temp_dir, deno_dir) = test_setup(false, false);
+
+ let specifier = "./util";
+ let referrer_ = deno_dir.deps_http.join("unpkg.com/liltest@0.0.5/index.ts");
+ let referrer = referrer_.to_str().unwrap();
+
+ // http containing files -> load relative import with http
+ let expected_module_name = "http://unpkg.com/liltest@0.0.5/util";
+ let expected_filename = deno_fs::normalize_path(
+ deno_dir
+ .deps_http
+ .join("unpkg.com/liltest@0.0.5/util")
+ .as_ref(),
+ );
+
+ let (module_name, filename) =
+ deno_dir.resolve_module(specifier, referrer).unwrap();
+ assert_eq!(module_name, expected_module_name);
+ assert_eq!(filename, expected_filename);
+ }
+
+ #[test]
+ fn test_resolve_module_5() {
+ let (_temp_dir, deno_dir) = test_setup(false, false);
+
+ let specifier = "./util";
+ let referrer_ =
+ deno_dir.deps_https.join("unpkg.com/liltest@0.0.5/index.ts");
+ let referrer = referrer_.to_str().unwrap();
+
+ // https containing files -> load relative import with https
+ let expected_module_name = "https://unpkg.com/liltest@0.0.5/util";
+ let expected_filename = deno_fs::normalize_path(
+ deno_dir
+ .deps_https
+ .join("unpkg.com/liltest@0.0.5/util")
+ .as_ref(),
+ );
+
+ let (module_name, filename) =
+ deno_dir.resolve_module(specifier, referrer).unwrap();
+ assert_eq!(module_name, expected_module_name);
+ assert_eq!(filename, expected_filename);
+ }
+
+ #[test]
+ fn test_resolve_module_6() {
+ let (_temp_dir, deno_dir) = test_setup(false, false);
+
+ let specifier = "http://localhost:4545/tests/subdir/mod2.ts";
+ let referrer = add_root!("/deno/tests/006_url_imports.ts");
+ let expected_module_name = "http://localhost:4545/tests/subdir/mod2.ts";
+ let expected_filename = deno_fs::normalize_path(
+ deno_dir
+ .deps_http
+ .join("localhost_PORT4545/tests/subdir/mod2.ts")
+ .as_ref(),
+ );
+
+ let (module_name, filename) =
+ deno_dir.resolve_module(specifier, referrer).unwrap();
+ assert_eq!(module_name, expected_module_name);
+ assert_eq!(filename, expected_filename);
+ }
+
+ #[test]
+ fn test_resolve_module_7() {
+ let (_temp_dir, deno_dir) = test_setup(false, false);
+
+ let specifier = "http_test.ts";
+ let referrer = add_root!("/Users/rld/src/deno_net/");
+ let expected_module_name =
+ file_url!("/Users/rld/src/deno_net/http_test.ts");
+ let expected_filename = add_root!("/Users/rld/src/deno_net/http_test.ts");
+
+ let (module_name, filename) =
+ deno_dir.resolve_module(specifier, referrer).unwrap();
+ assert_eq!(module_name, expected_module_name);
+ assert_eq!(filename, expected_filename);
+ }
+
+ #[test]
+ fn test_resolve_module_referrer_dot() {
+ let (_temp_dir, deno_dir) = test_setup(false, false);
+
+ let specifier = "tests/001_hello.js";
+
+ let cwd = std::env::current_dir().unwrap();
+ let expected_path = cwd.join(specifier);
+ let expected_module_name =
+ Url::from_file_path(&expected_path).unwrap().to_string();
+ let expected_filename = deno_fs::normalize_path(&expected_path);
+
+ let (module_name, filename) =
+ deno_dir.resolve_module(specifier, ".").unwrap();
+ assert_eq!(module_name, expected_module_name);
+ assert_eq!(filename, expected_filename);
+
+ let (module_name, filename) =
+ deno_dir.resolve_module(specifier, "./").unwrap();
+ assert_eq!(module_name, expected_module_name);
+ assert_eq!(filename, expected_filename);
+ }
+
+ #[test]
+ fn test_resolve_module_referrer_dotdot() {
+ let (_temp_dir, deno_dir) = test_setup(false, false);
+
+ let specifier = "tests/001_hello.js";
+
+ let cwd = std::env::current_dir().unwrap();
+ let expected_path = cwd.join("..").join(specifier);
+ let expected_module_name =
+ Url::from_file_path(&expected_path).unwrap().to_string();
+ let expected_filename = deno_fs::normalize_path(&expected_path);
+
+ let (module_name, filename) =
+ deno_dir.resolve_module(specifier, "..").unwrap();
+ assert_eq!(module_name, expected_module_name);
+ assert_eq!(filename, expected_filename);
+
+ let (module_name, filename) =
+ deno_dir.resolve_module(specifier, "../").unwrap();
+ assert_eq!(module_name, expected_module_name);
+ assert_eq!(filename, expected_filename);
+ }
+
+ #[test]
+ fn test_map_file_extension() {
+ assert_eq!(
+ map_file_extension(Path::new("foo/bar.ts")),
+ msg::MediaType::TypeScript
+ );
+ assert_eq!(
+ map_file_extension(Path::new("foo/bar.d.ts")),
+ msg::MediaType::TypeScript
+ );
+ assert_eq!(
+ map_file_extension(Path::new("foo/bar.js")),
+ msg::MediaType::JavaScript
+ );
+ assert_eq!(
+ map_file_extension(Path::new("foo/bar.json")),
+ msg::MediaType::Json
+ );
+ assert_eq!(
+ map_file_extension(Path::new("foo/bar.txt")),
+ msg::MediaType::Unknown
+ );
+ assert_eq!(
+ map_file_extension(Path::new("foo/bar")),
+ msg::MediaType::Unknown
+ );
+ }
+
+ #[test]
+ fn test_map_content_type() {
+ // Extension only
+ assert_eq!(
+ map_content_type(Path::new("foo/bar.ts"), None),
+ msg::MediaType::TypeScript
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar.d.ts"), None),
+ msg::MediaType::TypeScript
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar.js"), None),
+ msg::MediaType::JavaScript
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar.json"), None),
+ msg::MediaType::Json
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar.txt"), None),
+ msg::MediaType::Unknown
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar"), None),
+ msg::MediaType::Unknown
+ );
+
+ // Media Type
+ assert_eq!(
+ map_content_type(Path::new("foo/bar"), Some("application/typescript")),
+ msg::MediaType::TypeScript
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar"), Some("text/typescript")),
+ msg::MediaType::TypeScript
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar"), Some("video/vnd.dlna.mpeg-tts")),
+ msg::MediaType::TypeScript
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar"), Some("video/mp2t")),
+ msg::MediaType::TypeScript
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar"), Some("application/x-typescript")),
+ msg::MediaType::TypeScript
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar"), Some("application/javascript")),
+ msg::MediaType::JavaScript
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar"), Some("text/javascript")),
+ msg::MediaType::JavaScript
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar"), Some("application/ecmascript")),
+ msg::MediaType::JavaScript
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar"), Some("text/ecmascript")),
+ msg::MediaType::JavaScript
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar"), Some("application/x-javascript")),
+ msg::MediaType::JavaScript
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar"), Some("application/json")),
+ msg::MediaType::Json
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar"), Some("text/json")),
+ msg::MediaType::Json
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar.ts"), Some("text/plain")),
+ msg::MediaType::TypeScript
+ );
+ assert_eq!(
+ map_content_type(Path::new("foo/bar.ts"), Some("foo/bar")),
+ msg::MediaType::Unknown
+ );
+ }
+
+ #[test]
+ fn test_filter_shebang() {
+ assert_eq!(filter_shebang("#!".as_bytes().to_owned()), "".as_bytes());
+ assert_eq!(
+ filter_shebang("#!\n\n".as_bytes().to_owned()),
+ "\n\n".as_bytes()
+ );
+ let code = "#!/usr/bin/env deno\nconsole.log('hello');\n"
+ .as_bytes()
+ .to_owned();
+ assert_eq!(filter_shebang(code), "\nconsole.log('hello');\n".as_bytes());
+ }
+}