compiler.rs 5.2 KB
Newer Older
R
Ry Dahl 已提交
1
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
2 3 4
use super::dispatch_json::Deserialize;
use super::dispatch_json::JsonOp;
use super::dispatch_json::Value;
B
Bartek Iwańczuk 已提交
5
use crate::futures::future::try_join_all;
6
use crate::msg;
7
use crate::ops::json_op;
8
use crate::state::State;
9 10
use deno_core::Loader;
use deno_core::*;
11
use futures::future::FutureExt;
B
Bartek Iwańczuk 已提交
12

13
pub fn init(i: &mut Isolate, s: &State) {
14
  i.register_op("cache", s.core_op(json_op(s.stateful_op(op_cache))));
K
Kitson Kelly 已提交
15 16 17 18
  i.register_op(
    "resolve_modules",
    s.core_op(json_op(s.stateful_op(op_resolve_modules))),
  );
19 20 21 22
  i.register_op(
    "fetch_source_files",
    s.core_op(json_op(s.stateful_op(op_fetch_source_files))),
  );
23 24 25 26
  i.register_op(
    "fetch_asset",
    s.core_op(json_op(s.stateful_op(op_fetch_asset))),
  );
27 28
}

B
Bartek Iwańczuk 已提交
29 30 31 32 33 34 35
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct CacheArgs {
  module_id: String,
  contents: String,
  extension: String,
}
B
Bartek Iwańczuk 已提交
36

37
fn op_cache(
38
  state: &State,
B
Bartek Iwańczuk 已提交
39
  args: Value,
R
Ryan Dahl 已提交
40
  _zero_copy: Option<ZeroCopyBuf>,
B
Bartek Iwańczuk 已提交
41 42
) -> Result<JsonOp, ErrBox> {
  let args: CacheArgs = serde_json::from_value(args)?;
B
Bartek Iwańczuk 已提交
43

B
Bartek Iwańczuk 已提交
44
  let module_specifier = ModuleSpecifier::resolve_url(&args.module_id)
B
Bartek Iwańczuk 已提交
45 46
    .expect("Should be valid module specifier");

47 48 49 50 51 52 53
  let state_ = &state.borrow().global_state;
  let ts_compiler = state_.ts_compiler.clone();
  let fut = ts_compiler.cache_compiler_output(
    &module_specifier,
    &args.extension,
    &args.contents,
  );
B
Bartek Iwańczuk 已提交
54

55
  futures::executor::block_on(fut)?;
B
Bartek Iwańczuk 已提交
56 57 58
  Ok(JsonOp::Sync(json!({})))
}

K
Kitson Kelly 已提交
59 60
#[derive(Deserialize, Debug)]
struct SpecifiersReferrerArgs {
61
  specifiers: Vec<String>,
62
  referrer: Option<String>,
B
Bartek Iwańczuk 已提交
63 64
}

K
Kitson Kelly 已提交
65
fn op_resolve_modules(
66
  state: &State,
B
Bartek Iwańczuk 已提交
67
  args: Value,
R
Ryan Dahl 已提交
68
  _data: Option<ZeroCopyBuf>,
B
Bartek Iwańczuk 已提交
69
) -> Result<JsonOp, ErrBox> {
K
Kitson Kelly 已提交
70 71 72 73 74 75 76 77 78 79
  let args: SpecifiersReferrerArgs = serde_json::from_value(args)?;
  let (referrer, is_main) = if let Some(referrer) = args.referrer {
    (referrer, false)
  } else {
    ("<unknown>".to_owned(), true)
  };

  let mut specifiers = vec![];

  for specifier in &args.specifiers {
80
    let resolved_specifier = state.resolve(specifier, &referrer, is_main);
K
Kitson Kelly 已提交
81 82 83 84 85 86 87 88 89 90
    match resolved_specifier {
      Ok(ms) => specifiers.push(ms.as_str().to_owned()),
      Err(err) => return Err(err),
    }
  }

  Ok(JsonOp::Sync(json!(specifiers)))
}

fn op_fetch_source_files(
91
  state: &State,
K
Kitson Kelly 已提交
92
  args: Value,
R
Ryan Dahl 已提交
93
  _data: Option<ZeroCopyBuf>,
K
Kitson Kelly 已提交
94 95 96 97
) -> Result<JsonOp, ErrBox> {
  let args: SpecifiersReferrerArgs = serde_json::from_value(args)?;

  let ref_specifier = if let Some(referrer) = args.referrer {
98 99
    let specifier = ModuleSpecifier::resolve_url(&referrer)
      .expect("Referrer is not a valid specifier");
K
Kitson Kelly 已提交
100
    Some(specifier)
101
  } else {
K
Kitson Kelly 已提交
102
    None
103 104
  };

105
  let global_state = state.borrow().global_state.clone();
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
  let file_fetcher = global_state.file_fetcher.clone();
  let specifiers = args.specifiers.clone();
  let future = async move {
    let file_futures: Vec<_> = specifiers
      .into_iter()
      .map(|specifier| {
        let file_fetcher_ = file_fetcher.clone();
        let ref_specifier_ = ref_specifier.clone();
        async move {
          let resolved_specifier = ModuleSpecifier::resolve_url(&specifier)
            .expect("Invalid specifier");
          file_fetcher_
            .fetch_source_file_async(&resolved_specifier, ref_specifier_)
            .await
        }
        .boxed_local()
      })
      .collect();

    let files = try_join_all(file_futures).await?;
126
    // We want to get an array of futures that resolves to
127
    let v = files.into_iter().map(|f| {
128
      async {
129 130 131 132 133 134 135 136 137 138 139 140
        // if the source file contains a `types_url` we need to replace
        // the module with the type definition when requested by the compiler
        let file = match f.types_url {
          Some(types_url) => {
            let types_specifier = ModuleSpecifier::from(types_url);
            global_state
              .file_fetcher
              .fetch_source_file_async(&types_specifier, ref_specifier.clone())
              .await?
          }
          _ => f,
        };
141 142 143 144 145 146 147 148 149 150
        // Special handling of Wasm files:
        // compile them into JS first!
        // This allows TS to do correct export types.
        let source_code = match file.media_type {
          msg::MediaType::Wasm => {
            global_state
              .wasm_compiler
              .compile_async(global_state.clone(), &file)
              .await?
              .code
151
          }
152 153 154 155 156 157 158 159 160
          _ => String::from_utf8(file.source_code).unwrap(),
        };
        Ok::<_, ErrBox>(json!({
          "url": file.url.to_string(),
          "filename": file.filename.to_str().unwrap(),
          "mediaType": file.media_type as i32,
          "sourceCode": source_code,
        }))
      }
K
Kitson Kelly 已提交
161
    });
162

163 164
    let v = try_join_all(v).await?;
    Ok(v.into())
165 166
  }
  .boxed_local();
167 168

  Ok(JsonOp::Async(future))
B
Bartek Iwańczuk 已提交
169
}
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192

#[derive(Deserialize, Debug)]
struct FetchRemoteAssetArgs {
  name: String,
}

fn op_fetch_asset(
  _state: &State,
  args: Value,
  _data: Option<ZeroCopyBuf>,
) -> Result<JsonOp, ErrBox> {
  let args: FetchRemoteAssetArgs = serde_json::from_value(args)?;
  debug!("args.name: {}", args.name);

  let source_code =
    if let Some(source_code) = deno_typescript::get_asset(&args.name) {
      source_code.to_string()
    } else {
      panic!("Asset not found: \"{}\"", args.name)
    };

  Ok(JsonOp::Sync(json!({ "sourceCode": source_code })))
}