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

10 11
pub fn init(i: &mut Isolate, s: &ThreadSafeState) {
  i.register_op("cache", s.core_op(json_op(s.stateful_op(op_cache))));
K
Kitson Kelly 已提交
12 13 14 15
  i.register_op(
    "resolve_modules",
    s.core_op(json_op(s.stateful_op(op_resolve_modules))),
  );
16 17 18 19 20 21
  i.register_op(
    "fetch_source_files",
    s.core_op(json_op(s.stateful_op(op_fetch_source_files))),
  );
}

B
Bartek Iwańczuk 已提交
22 23 24 25 26 27 28
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct CacheArgs {
  module_id: String,
  contents: String,
  extension: String,
}
B
Bartek Iwańczuk 已提交
29

30
fn op_cache(
B
Bartek Iwańczuk 已提交
31
  state: &ThreadSafeState,
B
Bartek Iwańczuk 已提交
32 33 34 35
  args: Value,
  _zero_copy: Option<PinnedBuf>,
) -> Result<JsonOp, ErrBox> {
  let args: CacheArgs = serde_json::from_value(args)?;
B
Bartek Iwańczuk 已提交
36

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

40
  state.global_state.ts_compiler.cache_compiler_output(
B
Bartek Iwańczuk 已提交
41
    &module_specifier,
B
Bartek Iwańczuk 已提交
42 43
    &args.extension,
    &args.contents,
B
Bartek Iwańczuk 已提交
44 45
  )?;

B
Bartek Iwańczuk 已提交
46 47 48
  Ok(JsonOp::Sync(json!({})))
}

K
Kitson Kelly 已提交
49 50
#[derive(Deserialize, Debug)]
struct SpecifiersReferrerArgs {
51
  specifiers: Vec<String>,
52
  referrer: Option<String>,
B
Bartek Iwańczuk 已提交
53 54
}

K
Kitson Kelly 已提交
55
fn op_resolve_modules(
B
Bartek Iwańczuk 已提交
56
  state: &ThreadSafeState,
B
Bartek Iwańczuk 已提交
57
  args: Value,
K
Kitson Kelly 已提交
58
  _data: Option<PinnedBuf>,
B
Bartek Iwańczuk 已提交
59
) -> Result<JsonOp, ErrBox> {
K
Kitson Kelly 已提交
60
  let args: SpecifiersReferrerArgs = serde_json::from_value(args)?;
B
Bartek Iwańczuk 已提交
61 62 63 64 65

  // TODO(ry) Maybe a security hole. Only the compiler worker should have access
  // to this. Need a test to demonstrate the hole.
  let is_dyn_import = false;

K
Kitson Kelly 已提交
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
  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 {
    let resolved_specifier =
      state.resolve(specifier, &referrer, is_main, is_dyn_import);
    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(
  state: &ThreadSafeState,
  args: Value,
  _data: Option<PinnedBuf>,
) -> Result<JsonOp, ErrBox> {
  let args: SpecifiersReferrerArgs = serde_json::from_value(args)?;

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

101 102 103
  let mut futures = vec![];
  for specifier in &args.specifiers {
    let resolved_specifier =
K
Kitson Kelly 已提交
104
      ModuleSpecifier::resolve_url(&specifier).expect("Invalid specifier");
105
    let fut = state
106
      .global_state
107
      .file_fetcher
108
      .fetch_source_file_async(&resolved_specifier, ref_specifier.clone());
109 110
    futures.push(fut);
  }
B
Bartek Iwańczuk 已提交
111

112 113
  let global_state = state.global_state.clone();

114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
  let future = Box::pin(async move {
    let files = try_join_all(futures).await?;

    // We want to get an array of futures that resolves to
    let v = files.into_iter().map(|file| {
      async {
        // 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
130
          }
131 132 133 134 135 136 137 138 139
          _ => 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 已提交
140
    });
141

142 143 144 145 146
    let v = try_join_all(v).await?;
    Ok(v.into())
  });

  Ok(JsonOp::Async(future))
B
Bartek Iwańczuk 已提交
147
}