mirror of
https://github.com/denoland/deno.git
synced 2024-11-25 15:29:32 -05:00
Merge branch 'main' into auto-config
This commit is contained in:
commit
a91fbcc4e7
106 changed files with 3795 additions and 3060 deletions
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
|
@ -53,6 +53,7 @@ jobs:
|
|||
CARGO_TERM_COLOR: always
|
||||
RUST_BACKTRACE: full
|
||||
RUSTC_FORCE_INCREMENTAL: 1
|
||||
RUSTFLAGS: -D warnings
|
||||
|
||||
steps:
|
||||
- name: Configure git
|
||||
|
@ -84,7 +85,7 @@ jobs:
|
|||
- name: Install Rust
|
||||
uses: hecrj/setup-rust-action@v1
|
||||
with:
|
||||
rust-version: 1.57.0
|
||||
rust-version: 1.58.0
|
||||
|
||||
- name: Install clippy and rustfmt
|
||||
if: matrix.job == 'lint'
|
||||
|
@ -146,11 +147,6 @@ jobs:
|
|||
service_account_key: ${{ secrets.GCP_SA_KEY }}
|
||||
export_default_credentials: true
|
||||
|
||||
- name: Error on warning
|
||||
# TODO(piscisaureus): enable this on Windows again.
|
||||
if: "!matrix.use_sysroot && !startsWith(matrix.os, 'windows')"
|
||||
run: echo "RUSTFLAGS=-D warnings" >> $GITHUB_ENV
|
||||
|
||||
- name: Configure canary build
|
||||
if: |
|
||||
matrix.job == 'test' &&
|
||||
|
|
2
.github/workflows/wpt_epoch.yml
vendored
2
.github/workflows/wpt_epoch.yml
vendored
|
@ -20,7 +20,7 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
deno-version: [v1.x, canary]
|
||||
os: [ubuntu-latest-xl]
|
||||
os: [ubuntu-20.04-xl]
|
||||
|
||||
steps:
|
||||
- name: Clone repository
|
||||
|
|
655
Cargo.lock
generated
655
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
12
Cargo.toml
12
Cargo.toml
|
@ -88,6 +88,12 @@ opt-level = 3
|
|||
opt-level = 3
|
||||
[profile.bench.package.tokio]
|
||||
opt-level = 3
|
||||
[profile.bench.package.zstd]
|
||||
opt-level = 3
|
||||
[profile.bench.package.lzzzz]
|
||||
opt-level = 3
|
||||
[profile.bench.package.zstd-sys]
|
||||
opt-level = 3
|
||||
|
||||
# NB: the `bench` and `release` profiles must remain EXACTLY the same.
|
||||
[profile.release.package.rand]
|
||||
|
@ -130,3 +136,9 @@ opt-level = 3
|
|||
opt-level = 3
|
||||
[profile.release.package.tokio]
|
||||
opt-level = 3
|
||||
[profile.release.package.zstd]
|
||||
opt-level = 3
|
||||
[profile.release.package.lzzzz]
|
||||
opt-level = 3
|
||||
[profile.release.package.zstd-sys]
|
||||
opt-level = 3
|
||||
|
|
12
Releases.md
12
Releases.md
|
@ -6,6 +6,18 @@ https://github.com/denoland/deno/releases
|
|||
We also have one-line install commands at:
|
||||
https://github.com/denoland/deno_install
|
||||
|
||||
### 1.17.3 / 2022.01.12
|
||||
|
||||
- fix: Get lib.deno_core.d.ts to parse correctly (#13238)
|
||||
- fix: expose "Deno.memoryUsage()" in worker context (#13293)
|
||||
- fix: install shim with `--allow-all` should not output each permission
|
||||
individually (#13325)
|
||||
- fix(compile): fix output flag behaviour on compile command (#13299)
|
||||
- fix(coverage): don't type check (#13324)
|
||||
- fix(coverage): merge coverage ranges (#13334)
|
||||
- fix(ext/web): handle no arguments in atob (#13341)
|
||||
- fix(serde_v8): support #[serde(default)] (#13300)
|
||||
|
||||
### 1.17.2 / 2022.01.05
|
||||
|
||||
- fix(cli): include JSON modules in bundle (#13188)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
||||
[package]
|
||||
name = "deno_bench_util"
|
||||
version = "0.25.0"
|
||||
version = "0.26.0"
|
||||
authors = ["the Deno authors"]
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
@ -14,7 +14,7 @@ description = "Bench and profiling utilities for deno crates"
|
|||
|
||||
[dependencies]
|
||||
bencher = "0.1"
|
||||
deno_core = { version = "0.113.0", path = "../core" }
|
||||
deno_core = { version = "0.114.0", path = "../core" }
|
||||
tokio = { version = "1.10.1", features = ["full"] }
|
||||
|
||||
[[bench]]
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno"
|
||||
version = "1.17.2"
|
||||
version = "1.17.3"
|
||||
authors = ["the Deno authors"]
|
||||
default-run = "deno"
|
||||
edition = "2021"
|
||||
|
@ -20,47 +20,50 @@ harness = false
|
|||
path = "./bench/main.rs"
|
||||
|
||||
[build-dependencies]
|
||||
deno_broadcast_channel = { version = "0.25.0", path = "../ext/broadcast_channel" }
|
||||
deno_console = { version = "0.31.0", path = "../ext/console" }
|
||||
deno_core = { version = "0.113.0", path = "../core" }
|
||||
deno_crypto = { version = "0.45.0", path = "../ext/crypto" }
|
||||
deno_fetch = { version = "0.54.0", path = "../ext/fetch" }
|
||||
deno_net = { version = "0.23.0", path = "../ext/net" }
|
||||
deno_url = { version = "0.31.0", path = "../ext/url" }
|
||||
deno_web = { version = "0.62.0", path = "../ext/web" }
|
||||
deno_webgpu = { version = "0.32.0", path = "../ext/webgpu" }
|
||||
deno_websocket = { version = "0.36.0", path = "../ext/websocket" }
|
||||
deno_webstorage = { version = "0.26.0", path = "../ext/webstorage" }
|
||||
deno_broadcast_channel = { version = "0.26.0", path = "../ext/broadcast_channel" }
|
||||
deno_console = { version = "0.32.0", path = "../ext/console" }
|
||||
deno_core = { version = "0.114.0", path = "../core" }
|
||||
deno_crypto = { version = "0.46.0", path = "../ext/crypto" }
|
||||
deno_fetch = { version = "0.55.0", path = "../ext/fetch" }
|
||||
deno_net = { version = "0.24.0", path = "../ext/net" }
|
||||
deno_url = { version = "0.32.0", path = "../ext/url" }
|
||||
deno_web = { version = "0.63.0", path = "../ext/web" }
|
||||
deno_webgpu = { version = "0.33.0", path = "../ext/webgpu" }
|
||||
deno_websocket = { version = "0.37.0", path = "../ext/websocket" }
|
||||
deno_webstorage = { version = "0.27.0", path = "../ext/webstorage" }
|
||||
regex = "=1.5.4"
|
||||
serde = { version = "=1.0.133", features = ["derive"] }
|
||||
zstd = '=0.9.2'
|
||||
|
||||
[target.'cfg(windows)'.build-dependencies]
|
||||
winapi = "=0.3.9"
|
||||
winres = "=0.1.11"
|
||||
|
||||
[dependencies]
|
||||
deno_ast = { version = "0.8.0", features = ["bundler", "codegen", "dep_graph", "module_specifier", "proposal", "react", "sourcemap", "transforms", "typescript", "view", "visit"] }
|
||||
deno_core = { version = "0.113.0", path = "../core" }
|
||||
deno_doc = "0.25.0"
|
||||
deno_graph = "0.17.0"
|
||||
deno_lint = { version = "0.21.0", features = ["docs"] }
|
||||
deno_runtime = { version = "0.39.0", path = "../runtime" }
|
||||
deno_ast = { version = "0.9.0", features = ["bundler", "codegen", "dep_graph", "module_specifier", "proposal", "react", "sourcemap", "transforms", "transpiling", "typescript", "view", "visit"] }
|
||||
deno_core = { version = "0.114.0", path = "../core" }
|
||||
deno_doc = "0.26.0"
|
||||
deno_graph = "0.18.0"
|
||||
deno_lint = { version = "0.22.0", features = ["docs"] }
|
||||
deno_runtime = { version = "0.40.0", path = "../runtime" }
|
||||
|
||||
atty = "=0.2.14"
|
||||
base64 = "=0.13.0"
|
||||
cache_control = "=0.2.0"
|
||||
chrono = "=0.4.19"
|
||||
clap = "=2.33.3"
|
||||
clap = "=3.0.7"
|
||||
clap_complete = "=3.0.3"
|
||||
clap_complete_fig = "=3.0.2"
|
||||
data-url = "=0.1.1"
|
||||
dissimilar = "=1.0.2"
|
||||
dprint-plugin-json = "=0.14.0"
|
||||
dprint-plugin-markdown = "=0.12.0"
|
||||
dprint-plugin-typescript = "=0.61.0"
|
||||
dprint-plugin-typescript = "=0.62.0"
|
||||
encoding_rs = "=0.8.29"
|
||||
env_logger = "=0.8.4"
|
||||
fancy-regex = "=0.7.1"
|
||||
http = "=0.2.4"
|
||||
import_map = "=0.4.0"
|
||||
import_map = "=0.6.0"
|
||||
jsonc-parser = { version = "=0.17.1", features = ["serde"] }
|
||||
libc = "=0.2.106"
|
||||
log = { version = "=0.4.14", features = ["serde"] }
|
||||
|
@ -83,8 +86,10 @@ tempfile = "=3.2.0"
|
|||
text-size = "=1.1.0"
|
||||
text_lines = "=0.4.1"
|
||||
tokio = { version = "=1.14", features = ["full"] }
|
||||
typed-arena = "2.0.1"
|
||||
uuid = { version = "=0.8.2", features = ["v4", "serde"] }
|
||||
walkdir = "=2.3.2"
|
||||
zstd = '=0.9.2'
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
fwdansi = "=1.1.0"
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
||||
use deno_ast::swc::bundler::Hook;
|
||||
use deno_ast::swc::bundler::ModuleRecord;
|
||||
use deno_ast::swc::common::Span;
|
||||
use deno_core::error::AnyError;
|
||||
|
||||
/// This contains the logic for Deno to rewrite the `import.meta` when bundling.
|
||||
pub struct BundleHook;
|
||||
|
||||
impl Hook for BundleHook {
|
||||
fn get_import_meta_props(
|
||||
&self,
|
||||
span: Span,
|
||||
module_record: &ModuleRecord,
|
||||
) -> Result<Vec<deno_ast::swc::ast::KeyValueProp>, AnyError> {
|
||||
use deno_ast::swc::ast;
|
||||
|
||||
Ok(vec![
|
||||
ast::KeyValueProp {
|
||||
key: ast::PropName::Ident(ast::Ident::new("url".into(), span)),
|
||||
value: Box::new(ast::Expr::Lit(ast::Lit::Str(ast::Str {
|
||||
span,
|
||||
value: module_record.file_name.to_string().into(),
|
||||
kind: ast::StrKind::Synthesized,
|
||||
has_escape: false,
|
||||
}))),
|
||||
},
|
||||
ast::KeyValueProp {
|
||||
key: ast::PropName::Ident(ast::Ident::new("main".into(), span)),
|
||||
value: Box::new(if module_record.is_entry {
|
||||
ast::Expr::Member(ast::MemberExpr {
|
||||
span,
|
||||
obj: ast::ExprOrSuper::Expr(Box::new(ast::Expr::MetaProp(
|
||||
ast::MetaPropExpr {
|
||||
meta: ast::Ident::new("import".into(), span),
|
||||
prop: ast::Ident::new("meta".into(), span),
|
||||
},
|
||||
))),
|
||||
prop: Box::new(ast::Expr::Ident(ast::Ident::new(
|
||||
"main".into(),
|
||||
span,
|
||||
))),
|
||||
computed: false,
|
||||
})
|
||||
} else {
|
||||
ast::Expr::Lit(ast::Lit::Bool(ast::Bool { span, value: false }))
|
||||
}),
|
||||
},
|
||||
])
|
||||
}
|
||||
}
|
919
cli/ast/mod.rs
919
cli/ast/mod.rs
|
@ -1,919 +0,0 @@
|
|||
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use crate::config_file;
|
||||
use crate::text_encoding::strip_bom;
|
||||
|
||||
use deno_ast::get_syntax;
|
||||
use deno_ast::swc::ast::Module;
|
||||
use deno_ast::swc::ast::Program;
|
||||
use deno_ast::swc::codegen::text_writer::JsWriter;
|
||||
use deno_ast::swc::codegen::Node;
|
||||
use deno_ast::swc::common::chain;
|
||||
use deno_ast::swc::common::comments::SingleThreadedComments;
|
||||
use deno_ast::swc::common::errors::Diagnostic as SwcDiagnostic;
|
||||
use deno_ast::swc::common::BytePos;
|
||||
use deno_ast::swc::common::FileName;
|
||||
use deno_ast::swc::common::Globals;
|
||||
use deno_ast::swc::common::Mark;
|
||||
use deno_ast::swc::common::SourceMap;
|
||||
use deno_ast::swc::common::Spanned;
|
||||
use deno_ast::swc::parser::error::Error as SwcError;
|
||||
use deno_ast::swc::parser::error::SyntaxError;
|
||||
use deno_ast::swc::parser::lexer::Lexer;
|
||||
use deno_ast::swc::parser::StringInput;
|
||||
use deno_ast::swc::transforms::fixer;
|
||||
use deno_ast::swc::transforms::helpers;
|
||||
use deno_ast::swc::transforms::hygiene;
|
||||
use deno_ast::swc::transforms::pass::Optional;
|
||||
use deno_ast::swc::transforms::proposals;
|
||||
use deno_ast::swc::transforms::react;
|
||||
use deno_ast::swc::transforms::resolver_with_mark;
|
||||
use deno_ast::swc::transforms::typescript;
|
||||
use deno_ast::swc::visit::FoldWith;
|
||||
use deno_ast::Diagnostic;
|
||||
use deno_ast::LineAndColumnDisplay;
|
||||
use deno_ast::MediaType;
|
||||
use deno_ast::ParsedSource;
|
||||
use deno_core::anyhow::anyhow;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::resolve_url_or_path;
|
||||
use deno_core::serde_json;
|
||||
use deno_core::ModuleSpecifier;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
|
||||
mod bundle_hook;
|
||||
mod transforms;
|
||||
|
||||
pub use bundle_hook::BundleHook;
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct Location {
|
||||
pub specifier: String,
|
||||
pub line: usize,
|
||||
pub col: usize,
|
||||
}
|
||||
|
||||
impl Location {
|
||||
pub fn from_pos(parsed_source: &ParsedSource, pos: BytePos) -> Self {
|
||||
Location::from_line_and_column(
|
||||
parsed_source.specifier().to_string(),
|
||||
parsed_source.source().line_and_column_index(pos),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn from_line_and_column(
|
||||
specifier: String,
|
||||
line_and_column: deno_ast::LineAndColumnIndex,
|
||||
) -> Self {
|
||||
Location {
|
||||
specifier,
|
||||
line: line_and_column.line_index + 1,
|
||||
col: line_and_column.column_index,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<deno_ast::swc::common::Loc> for Location {
|
||||
fn from(swc_loc: deno_ast::swc::common::Loc) -> Self {
|
||||
use deno_ast::swc::common::FileName::*;
|
||||
|
||||
let filename = match &swc_loc.file.name {
|
||||
Real(path_buf) => path_buf.to_string_lossy().to_string(),
|
||||
Custom(str_) => str_.to_string(),
|
||||
Url(url) => url.to_string(),
|
||||
_ => panic!("invalid filename"),
|
||||
};
|
||||
|
||||
Location {
|
||||
specifier: filename,
|
||||
line: swc_loc.line,
|
||||
col: swc_loc.col.0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Location> for ModuleSpecifier {
|
||||
fn from(loc: Location) -> Self {
|
||||
resolve_url_or_path(&loc.specifier).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Location {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(f, "{}:{}:{}", self.specifier, self.line, self.col)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Diagnostics(pub Vec<Diagnostic>);
|
||||
|
||||
impl std::error::Error for Diagnostics {}
|
||||
|
||||
impl fmt::Display for Diagnostics {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
for (i, diagnostic) in self.0.iter().enumerate() {
|
||||
if i > 0 {
|
||||
write!(f, "\n\n")?;
|
||||
}
|
||||
|
||||
write!(f, "{}", diagnostic)?
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ImportsNotUsedAsValues {
|
||||
Remove,
|
||||
Preserve,
|
||||
Error,
|
||||
}
|
||||
|
||||
/// Options which can be adjusted when transpiling a module.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EmitOptions {
|
||||
/// When emitting a legacy decorator, also emit experimental decorator meta
|
||||
/// data. Defaults to `false`.
|
||||
pub emit_metadata: bool,
|
||||
/// What to do with import statements that only import types i.e. whether to
|
||||
/// remove them (`Remove`), keep them as side-effect imports (`Preserve`)
|
||||
/// or error (`Error`). Defaults to `Remove`.
|
||||
pub imports_not_used_as_values: ImportsNotUsedAsValues,
|
||||
/// Should the source map be inlined in the emitted code file, or provided
|
||||
/// as a separate file. Defaults to `true`.
|
||||
pub inline_source_map: bool,
|
||||
/// Should the sources be inlined in the source map. Defaults to `true`.
|
||||
pub inline_sources: bool,
|
||||
/// Should a corresponding .map file be created for the output. This should be
|
||||
/// false if inline_source_map is true. Defaults to `false`.
|
||||
pub source_map: bool,
|
||||
/// `true` if the program should use an implicit JSX import source/the "new"
|
||||
/// JSX transforms.
|
||||
pub jsx_automatic: bool,
|
||||
/// If JSX is automatic, if it is in development mode, meaning that it should
|
||||
/// import `jsx-dev-runtime` and transform JSX using `jsxDEV` import from the
|
||||
/// JSX import source as well as provide additional debug information to the
|
||||
/// JSX factory.
|
||||
pub jsx_development: bool,
|
||||
/// When transforming JSX, what value should be used for the JSX factory.
|
||||
/// Defaults to `React.createElement`.
|
||||
pub jsx_factory: String,
|
||||
/// When transforming JSX, what value should be used for the JSX fragment
|
||||
/// factory. Defaults to `React.Fragment`.
|
||||
pub jsx_fragment_factory: String,
|
||||
/// The string module specifier to implicitly import JSX factories from when
|
||||
/// transpiling JSX.
|
||||
pub jsx_import_source: Option<String>,
|
||||
/// Should JSX be transformed or preserved. Defaults to `true`.
|
||||
pub transform_jsx: bool,
|
||||
/// Should import declarations be transformed to variable declarations.
|
||||
/// This should only be set to true for the REPL. Defaults to `false`.
|
||||
pub repl_imports: bool,
|
||||
}
|
||||
|
||||
impl Default for EmitOptions {
|
||||
fn default() -> Self {
|
||||
EmitOptions {
|
||||
emit_metadata: false,
|
||||
imports_not_used_as_values: ImportsNotUsedAsValues::Remove,
|
||||
inline_source_map: true,
|
||||
inline_sources: true,
|
||||
source_map: false,
|
||||
jsx_automatic: false,
|
||||
jsx_development: false,
|
||||
jsx_factory: "React.createElement".into(),
|
||||
jsx_fragment_factory: "React.Fragment".into(),
|
||||
jsx_import_source: None,
|
||||
transform_jsx: true,
|
||||
repl_imports: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<config_file::TsConfig> for EmitOptions {
|
||||
fn from(config: config_file::TsConfig) -> Self {
|
||||
let options: config_file::EmitConfigOptions =
|
||||
serde_json::from_value(config.0).unwrap();
|
||||
let imports_not_used_as_values =
|
||||
match options.imports_not_used_as_values.as_str() {
|
||||
"preserve" => ImportsNotUsedAsValues::Preserve,
|
||||
"error" => ImportsNotUsedAsValues::Error,
|
||||
_ => ImportsNotUsedAsValues::Remove,
|
||||
};
|
||||
let (transform_jsx, jsx_automatic, jsx_development) =
|
||||
match options.jsx.as_str() {
|
||||
"react" => (true, false, false),
|
||||
"react-jsx" => (true, true, false),
|
||||
"react-jsxdev" => (true, true, true),
|
||||
_ => (false, false, false),
|
||||
};
|
||||
EmitOptions {
|
||||
emit_metadata: options.emit_decorator_metadata,
|
||||
imports_not_used_as_values,
|
||||
inline_source_map: options.inline_source_map,
|
||||
inline_sources: options.inline_sources,
|
||||
source_map: options.source_map,
|
||||
jsx_automatic,
|
||||
jsx_development,
|
||||
jsx_factory: options.jsx_factory,
|
||||
jsx_fragment_factory: options.jsx_fragment_factory,
|
||||
jsx_import_source: options.jsx_import_source,
|
||||
transform_jsx,
|
||||
repl_imports: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn strip_config_from_emit_options(
|
||||
options: &EmitOptions,
|
||||
) -> typescript::strip::Config {
|
||||
typescript::strip::Config {
|
||||
pragma: Some(options.jsx_factory.clone()),
|
||||
pragma_frag: Some(options.jsx_fragment_factory.clone()),
|
||||
import_not_used_as_values: match options.imports_not_used_as_values {
|
||||
ImportsNotUsedAsValues::Remove => {
|
||||
typescript::strip::ImportsNotUsedAsValues::Remove
|
||||
}
|
||||
ImportsNotUsedAsValues::Preserve => {
|
||||
typescript::strip::ImportsNotUsedAsValues::Preserve
|
||||
}
|
||||
// `Error` only affects the type-checking stage. Fall back to `Remove` here.
|
||||
ImportsNotUsedAsValues::Error => {
|
||||
typescript::strip::ImportsNotUsedAsValues::Remove
|
||||
}
|
||||
},
|
||||
use_define_for_class_fields: true,
|
||||
// TODO(bartlomieju): this could be changed to `false` to provide `export {}`
|
||||
// in Typescript files without manual changes
|
||||
no_empty_export: true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Implements a configuration trait for source maps that reflects the logic
|
||||
/// to embed sources in the source map or not.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct SourceMapConfig {
|
||||
pub inline_sources: bool,
|
||||
}
|
||||
|
||||
impl deno_ast::swc::common::source_map::SourceMapGenConfig for SourceMapConfig {
|
||||
fn file_name_to_source(&self, f: &FileName) -> String {
|
||||
f.to_string()
|
||||
}
|
||||
|
||||
fn inline_sources_content(&self, f: &FileName) -> bool {
|
||||
match f {
|
||||
FileName::Real(..) | FileName::Custom(..) => false,
|
||||
FileName::Url(..) => self.inline_sources,
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Transform a TypeScript file into a JavaScript file, based on the supplied
|
||||
/// options.
|
||||
///
|
||||
/// The result is a tuple of the code and optional source map as strings.
|
||||
pub fn transpile(
|
||||
parsed_source: &ParsedSource,
|
||||
options: &EmitOptions,
|
||||
) -> Result<(String, Option<String>), AnyError> {
|
||||
ensure_no_fatal_diagnostics(parsed_source.diagnostics().iter())?;
|
||||
let program: Program = (*parsed_source.program()).clone();
|
||||
let source_map = Rc::new(SourceMap::default());
|
||||
let source_map_config = SourceMapConfig {
|
||||
inline_sources: options.inline_sources,
|
||||
};
|
||||
let specifier = resolve_url_or_path(parsed_source.specifier())?;
|
||||
let file_name = FileName::Url(specifier);
|
||||
source_map
|
||||
.new_source_file(file_name, parsed_source.source().text().to_string());
|
||||
let comments = parsed_source.comments().as_single_threaded(); // needs to be mutable
|
||||
let globals = Globals::new();
|
||||
deno_ast::swc::common::GLOBALS.set(&globals, || {
|
||||
let top_level_mark = Mark::fresh(Mark::root());
|
||||
let module = fold_program(
|
||||
program,
|
||||
options,
|
||||
source_map.clone(),
|
||||
&comments,
|
||||
top_level_mark,
|
||||
)?;
|
||||
|
||||
let mut src_map_buf = vec![];
|
||||
let mut buf = vec![];
|
||||
{
|
||||
let writer = Box::new(JsWriter::new(
|
||||
source_map.clone(),
|
||||
"\n",
|
||||
&mut buf,
|
||||
Some(&mut src_map_buf),
|
||||
));
|
||||
let config = deno_ast::swc::codegen::Config { minify: false };
|
||||
let mut emitter = deno_ast::swc::codegen::Emitter {
|
||||
cfg: config,
|
||||
comments: Some(&comments),
|
||||
cm: source_map.clone(),
|
||||
wr: writer,
|
||||
};
|
||||
module.emit_with(&mut emitter)?;
|
||||
}
|
||||
let mut src = String::from_utf8(buf)?;
|
||||
let mut map: Option<String> = None;
|
||||
{
|
||||
let mut buf = Vec::new();
|
||||
source_map
|
||||
.build_source_map_with_config(&mut src_map_buf, None, source_map_config)
|
||||
.to_writer(&mut buf)?;
|
||||
|
||||
if options.inline_source_map {
|
||||
src.push_str("//# sourceMappingURL=data:application/json;base64,");
|
||||
let encoded_map = base64::encode(buf);
|
||||
src.push_str(&encoded_map);
|
||||
} else {
|
||||
map = Some(String::from_utf8(buf)?);
|
||||
}
|
||||
}
|
||||
Ok((src, map))
|
||||
})
|
||||
}
|
||||
|
||||
/// A low level function which transpiles a source module into an swc
|
||||
/// SourceFile.
|
||||
pub fn transpile_module(
|
||||
specifier: &ModuleSpecifier,
|
||||
source: &str,
|
||||
media_type: MediaType,
|
||||
options: &EmitOptions,
|
||||
cm: Rc<SourceMap>,
|
||||
) -> Result<(Rc<deno_ast::swc::common::SourceFile>, Module), AnyError> {
|
||||
let source = strip_bom(source);
|
||||
let source = if media_type == MediaType::Json {
|
||||
format!(
|
||||
"export default JSON.parse(`{}`);",
|
||||
source.replace("${", "\\${").replace('`', "\\`")
|
||||
)
|
||||
} else {
|
||||
source.to_string()
|
||||
};
|
||||
let source_file =
|
||||
cm.new_source_file(FileName::Url(specifier.clone()), source);
|
||||
let input = StringInput::from(&*source_file);
|
||||
let comments = SingleThreadedComments::default();
|
||||
let syntax = if media_type == MediaType::Json {
|
||||
get_syntax(MediaType::JavaScript)
|
||||
} else {
|
||||
get_syntax(media_type)
|
||||
};
|
||||
let lexer = Lexer::new(syntax, deno_ast::ES_VERSION, input, Some(&comments));
|
||||
let mut parser = deno_ast::swc::parser::Parser::new_from(lexer);
|
||||
let module = parser
|
||||
.parse_module()
|
||||
.map_err(|e| swc_err_to_diagnostic(&cm, specifier, e))?;
|
||||
let diagnostics = parser
|
||||
.take_errors()
|
||||
.into_iter()
|
||||
.map(|e| swc_err_to_diagnostic(&cm, specifier, e))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
ensure_no_fatal_diagnostics(diagnostics.iter())?;
|
||||
|
||||
let top_level_mark = Mark::fresh(Mark::root());
|
||||
let program = fold_program(
|
||||
Program::Module(module),
|
||||
options,
|
||||
cm,
|
||||
&comments,
|
||||
top_level_mark,
|
||||
)?;
|
||||
let module = match program {
|
||||
Program::Module(module) => module,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
Ok((source_file, module))
|
||||
}
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
struct DiagnosticCollector {
|
||||
diagnostics_cell: Rc<RefCell<Vec<SwcDiagnostic>>>,
|
||||
}
|
||||
|
||||
impl DiagnosticCollector {
|
||||
pub fn into_handler(self) -> deno_ast::swc::common::errors::Handler {
|
||||
deno_ast::swc::common::errors::Handler::with_emitter(
|
||||
true,
|
||||
false,
|
||||
Box::new(self),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl deno_ast::swc::common::errors::Emitter for DiagnosticCollector {
|
||||
fn emit(
|
||||
&mut self,
|
||||
db: &deno_ast::swc::common::errors::DiagnosticBuilder<'_>,
|
||||
) {
|
||||
use std::ops::Deref;
|
||||
self.diagnostics_cell.borrow_mut().push(db.deref().clone());
|
||||
}
|
||||
}
|
||||
|
||||
fn fold_program(
|
||||
program: Program,
|
||||
options: &EmitOptions,
|
||||
source_map: Rc<SourceMap>,
|
||||
comments: &SingleThreadedComments,
|
||||
top_level_mark: Mark,
|
||||
) -> Result<Program, AnyError> {
|
||||
let jsx_pass = react::react(
|
||||
source_map.clone(),
|
||||
Some(comments),
|
||||
react::Options {
|
||||
pragma: options.jsx_factory.clone(),
|
||||
pragma_frag: options.jsx_fragment_factory.clone(),
|
||||
// this will use `Object.assign()` instead of the `_extends` helper
|
||||
// when spreading props.
|
||||
use_builtins: true,
|
||||
runtime: if options.jsx_automatic {
|
||||
Some(react::Runtime::Automatic)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
development: options.jsx_development,
|
||||
import_source: options.jsx_import_source.clone().unwrap_or_default(),
|
||||
..Default::default()
|
||||
},
|
||||
top_level_mark,
|
||||
);
|
||||
let mut passes = chain!(
|
||||
Optional::new(transforms::DownlevelImportsFolder, options.repl_imports),
|
||||
Optional::new(transforms::StripExportsFolder, options.repl_imports),
|
||||
proposals::decorators::decorators(proposals::decorators::Config {
|
||||
legacy: true,
|
||||
emit_metadata: options.emit_metadata
|
||||
}),
|
||||
helpers::inject_helpers(),
|
||||
resolver_with_mark(top_level_mark),
|
||||
Optional::new(
|
||||
typescript::strip::strip_with_config(
|
||||
strip_config_from_emit_options(options),
|
||||
top_level_mark
|
||||
),
|
||||
!options.transform_jsx
|
||||
),
|
||||
Optional::new(
|
||||
typescript::strip::strip_with_jsx(
|
||||
source_map.clone(),
|
||||
strip_config_from_emit_options(options),
|
||||
comments,
|
||||
top_level_mark
|
||||
),
|
||||
options.transform_jsx
|
||||
),
|
||||
Optional::new(jsx_pass, options.transform_jsx),
|
||||
fixer(Some(comments)),
|
||||
hygiene(),
|
||||
);
|
||||
|
||||
let emitter = DiagnosticCollector::default();
|
||||
let diagnostics_cell = emitter.diagnostics_cell.clone();
|
||||
let handler = emitter.into_handler();
|
||||
let result = deno_ast::swc::utils::HANDLER.set(&handler, || {
|
||||
helpers::HELPERS.set(&helpers::Helpers::new(false), || {
|
||||
program.fold_with(&mut passes)
|
||||
})
|
||||
});
|
||||
|
||||
let diagnostics = diagnostics_cell.borrow();
|
||||
ensure_no_fatal_swc_diagnostics(&source_map, diagnostics.iter())?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn ensure_no_fatal_swc_diagnostics<'a>(
|
||||
source_map: &SourceMap,
|
||||
diagnostics: impl Iterator<Item = &'a SwcDiagnostic>,
|
||||
) -> Result<(), AnyError> {
|
||||
let fatal_diagnostics = diagnostics
|
||||
.filter(|d| is_fatal_swc_diagnostic(d))
|
||||
.collect::<Vec<_>>();
|
||||
if !fatal_diagnostics.is_empty() {
|
||||
Err(anyhow!(
|
||||
"{}",
|
||||
fatal_diagnostics
|
||||
.iter()
|
||||
.map(|d| format_swc_diagnostic(source_map, d))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n\n")
|
||||
))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn is_fatal_swc_diagnostic(diagnostic: &SwcDiagnostic) -> bool {
|
||||
use deno_ast::swc::common::errors::Level;
|
||||
match diagnostic.level {
|
||||
Level::Bug
|
||||
| Level::Cancelled
|
||||
| Level::FailureNote
|
||||
| Level::Fatal
|
||||
| Level::PhaseFatal
|
||||
| Level::Error => true,
|
||||
Level::Help | Level::Note | Level::Warning => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn format_swc_diagnostic(
|
||||
source_map: &SourceMap,
|
||||
diagnostic: &SwcDiagnostic,
|
||||
) -> String {
|
||||
if let Some(span) = &diagnostic.span.primary_span() {
|
||||
let file_name = source_map.span_to_filename(*span);
|
||||
let loc = source_map.lookup_char_pos(span.lo);
|
||||
format!(
|
||||
"{} at {}:{}:{}",
|
||||
diagnostic.message(),
|
||||
file_name.to_string(),
|
||||
loc.line,
|
||||
loc.col_display + 1,
|
||||
)
|
||||
} else {
|
||||
diagnostic.message()
|
||||
}
|
||||
}
|
||||
|
||||
fn swc_err_to_diagnostic(
|
||||
source_map: &SourceMap,
|
||||
specifier: &ModuleSpecifier,
|
||||
err: SwcError,
|
||||
) -> Diagnostic {
|
||||
let location = source_map.lookup_char_pos(err.span().lo);
|
||||
Diagnostic {
|
||||
specifier: specifier.to_string(),
|
||||
span: err.span(),
|
||||
display_position: LineAndColumnDisplay {
|
||||
line_number: location.line,
|
||||
column_number: location.col_display + 1,
|
||||
},
|
||||
kind: err.into_kind(),
|
||||
}
|
||||
}
|
||||
|
||||
fn ensure_no_fatal_diagnostics<'a>(
|
||||
diagnostics: impl Iterator<Item = &'a Diagnostic>,
|
||||
) -> Result<(), Diagnostics> {
|
||||
let fatal_diagnostics = diagnostics
|
||||
.filter(|d| is_fatal_syntax_error(&d.kind))
|
||||
.map(ToOwned::to_owned)
|
||||
.collect::<Vec<_>>();
|
||||
if !fatal_diagnostics.is_empty() {
|
||||
Err(Diagnostics(fatal_diagnostics))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn is_fatal_syntax_error(error_kind: &SyntaxError) -> bool {
|
||||
matches!(
|
||||
error_kind,
|
||||
// expected identifier
|
||||
SyntaxError::TS1003 |
|
||||
// expected semi-colon
|
||||
SyntaxError::TS1005 |
|
||||
// expected expression
|
||||
SyntaxError::TS1109 |
|
||||
// unterminated string literal
|
||||
SyntaxError::UnterminatedStrLit
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use deno_ast::parse_module;
|
||||
use deno_ast::ParseParams;
|
||||
use deno_ast::SourceTextInfo;
|
||||
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
#[test]
|
||||
fn test_transpile() {
|
||||
let specifier = resolve_url_or_path("https://deno.land/x/mod.ts").unwrap();
|
||||
let source = r#"
|
||||
enum D {
|
||||
A,
|
||||
B,
|
||||
}
|
||||
|
||||
namespace N {
|
||||
export enum D {
|
||||
A = "value"
|
||||
}
|
||||
export const Value = 5;
|
||||
}
|
||||
|
||||
export class A {
|
||||
private b: string;
|
||||
protected c: number = 1;
|
||||
e: "foo";
|
||||
constructor (public d = D.A) {
|
||||
const e = "foo" as const;
|
||||
this.e = e;
|
||||
console.log(N.Value);
|
||||
}
|
||||
}
|
||||
"#;
|
||||
let module = deno_ast::parse_module(ParseParams {
|
||||
specifier: specifier.as_str().to_string(),
|
||||
source: SourceTextInfo::from_string(source.to_string()),
|
||||
media_type: deno_ast::MediaType::TypeScript,
|
||||
capture_tokens: false,
|
||||
maybe_syntax: None,
|
||||
scope_analysis: false,
|
||||
})
|
||||
.unwrap();
|
||||
let (code, maybe_map) =
|
||||
transpile(&module, &EmitOptions::default()).unwrap();
|
||||
let expected_text = r#"var D;
|
||||
(function(D) {
|
||||
D[D["A"] = 0] = "A";
|
||||
D[D["B"] = 1] = "B";
|
||||
})(D || (D = {}));
|
||||
var N;
|
||||
(function(N1) {
|
||||
let D;
|
||||
(function(D) {
|
||||
D["A"] = "value";
|
||||
})(D = N1.D || (N1.D = {}));
|
||||
var Value = N1.Value = 5;
|
||||
})(N || (N = {}));
|
||||
export class A {
|
||||
d;
|
||||
b;
|
||||
c = 1;
|
||||
e;
|
||||
constructor(d = D.A){
|
||||
this.d = d;
|
||||
const e = "foo";
|
||||
this.e = e;
|
||||
console.log(N.Value);
|
||||
}
|
||||
}
|
||||
"#;
|
||||
assert_eq!(&code[..expected_text.len()], expected_text);
|
||||
assert!(
|
||||
code.contains("\n//# sourceMappingURL=data:application/json;base64,")
|
||||
);
|
||||
assert!(maybe_map.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transpile_tsx() {
|
||||
let specifier = resolve_url_or_path("https://deno.land/x/mod.ts").unwrap();
|
||||
let source = r#"
|
||||
export class A {
|
||||
render() {
|
||||
return <div><span></span></div>
|
||||
}
|
||||
}
|
||||
"#;
|
||||
let module = parse_module(ParseParams {
|
||||
specifier: specifier.as_str().to_string(),
|
||||
source: SourceTextInfo::from_string(source.to_string()),
|
||||
media_type: deno_ast::MediaType::Tsx,
|
||||
capture_tokens: false,
|
||||
maybe_syntax: None,
|
||||
scope_analysis: true, // ensure scope analysis doesn't conflict with a second resolver pass
|
||||
})
|
||||
.unwrap();
|
||||
let (code, _) = transpile(&module, &EmitOptions::default()).unwrap();
|
||||
assert!(code.contains("React.createElement(\"div\", null"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transpile_jsx_pragma() {
|
||||
let specifier = resolve_url_or_path("https://deno.land/x/mod.ts").unwrap();
|
||||
let source = r#"
|
||||
/** @jsx h */
|
||||
/** @jsxFrag Fragment */
|
||||
import { h, Fragment } from "https://deno.land/x/mod.ts";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div><></></div>
|
||||
);
|
||||
}"#;
|
||||
let module = parse_module(ParseParams {
|
||||
specifier: specifier.as_str().to_string(),
|
||||
source: SourceTextInfo::from_string(source.to_string()),
|
||||
media_type: deno_ast::MediaType::Jsx,
|
||||
capture_tokens: false,
|
||||
maybe_syntax: None,
|
||||
scope_analysis: true,
|
||||
})
|
||||
.unwrap();
|
||||
let (code, _) = transpile(&module, &EmitOptions::default()).unwrap();
|
||||
let expected = r#"/** @jsx h */ /** @jsxFrag Fragment */ import { h, Fragment } from "https://deno.land/x/mod.ts";
|
||||
function App() {
|
||||
return(/*#__PURE__*/ h("div", null, /*#__PURE__*/ h(Fragment, null)));
|
||||
}"#;
|
||||
assert_eq!(&code[..expected.len()], expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transpile_jsx_import_source_pragma() {
|
||||
let specifier = resolve_url_or_path("https://deno.land/x/mod.tsx").unwrap();
|
||||
let source = r#"
|
||||
/** @jsxImportSource jsx_lib */
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div><></></div>
|
||||
);
|
||||
}"#;
|
||||
let module = parse_module(ParseParams {
|
||||
specifier: specifier.as_str().to_string(),
|
||||
source: SourceTextInfo::from_string(source.to_string()),
|
||||
media_type: deno_ast::MediaType::Jsx,
|
||||
capture_tokens: false,
|
||||
maybe_syntax: None,
|
||||
scope_analysis: true,
|
||||
})
|
||||
.unwrap();
|
||||
let (code, _) = transpile(&module, &EmitOptions::default()).unwrap();
|
||||
let expected = r#"import { jsx as _jsx, Fragment as _Fragment } from "jsx_lib/jsx-runtime";
|
||||
/** @jsxImportSource jsx_lib */ function App() {
|
||||
return(/*#__PURE__*/ _jsx("div", {
|
||||
children: /*#__PURE__*/ _jsx(_Fragment, {})
|
||||
}));
|
||||
"#;
|
||||
assert_eq!(&code[..expected.len()], expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_transpile_jsx_import_source_no_pragma() {
|
||||
let specifier = resolve_url_or_path("https://deno.land/x/mod.tsx").unwrap();
|
||||
let source = r#"
|
||||
function App() {
|
||||
return (
|
||||
<div><></></div>
|
||||
);
|
||||
}"#;
|
||||
let module = parse_module(ParseParams {
|
||||
specifier: specifier.as_str().to_string(),
|
||||
source: SourceTextInfo::from_string(source.to_string()),
|
||||
media_type: deno_ast::MediaType::Jsx,
|
||||
capture_tokens: false,
|
||||
maybe_syntax: None,
|
||||
scope_analysis: true,
|
||||
})
|
||||
.unwrap();
|
||||
let emit_options = EmitOptions {
|
||||
jsx_automatic: true,
|
||||
jsx_import_source: Some("jsx_lib".to_string()),
|
||||
..Default::default()
|
||||
};
|
||||
let (code, _) = transpile(&module, &emit_options).unwrap();
|
||||
let expected = r#"import { jsx as _jsx, Fragment as _Fragment } from "jsx_lib/jsx-runtime";
|
||||
function App() {
|
||||
return(/*#__PURE__*/ _jsx("div", {
|
||||
children: /*#__PURE__*/ _jsx(_Fragment, {})
|
||||
}));
|
||||
}
|
||||
"#;
|
||||
assert_eq!(&code[..expected.len()], expected);
|
||||
}
|
||||
|
||||
// TODO(@kitsonk) https://github.com/swc-project/swc/issues/2656
|
||||
// #[test]
|
||||
// fn test_transpile_jsx_import_source_no_pragma_dev() {
|
||||
// let specifier = resolve_url_or_path("https://deno.land/x/mod.tsx").unwrap();
|
||||
// let source = r#"
|
||||
// function App() {
|
||||
// return (
|
||||
// <div><></></div>
|
||||
// );
|
||||
// }"#;
|
||||
// let module = parse_module(ParseParams {
|
||||
// specifier: specifier.as_str().to_string(),
|
||||
// source: SourceTextInfo::from_string(source.to_string()),
|
||||
// media_type: deno_ast::MediaType::Jsx,
|
||||
// capture_tokens: false,
|
||||
// maybe_syntax: None,
|
||||
// scope_analysis: true,
|
||||
// })
|
||||
// .unwrap();
|
||||
// let emit_options = EmitOptions {
|
||||
// jsx_automatic: true,
|
||||
// jsx_import_source: Some("jsx_lib".to_string()),
|
||||
// jsx_development: true,
|
||||
// ..Default::default()
|
||||
// };
|
||||
// let (code, _) = transpile(&module, &emit_options).unwrap();
|
||||
// let expected = r#"import { jsx as _jsx, Fragment as _Fragment } from "jsx_lib/jsx-dev-runtime";
|
||||
// function App() {
|
||||
// return(/*#__PURE__*/ _jsx("div", {
|
||||
// children: /*#__PURE__*/ _jsx(_Fragment, {
|
||||
// })
|
||||
// }));
|
||||
// }
|
||||
// "#;
|
||||
// assert_eq!(&code[..expected.len()], expected);
|
||||
// }
|
||||
|
||||
#[test]
|
||||
fn test_transpile_decorators() {
|
||||
let specifier = resolve_url_or_path("https://deno.land/x/mod.ts").unwrap();
|
||||
let source = r#"
|
||||
function enumerable(value: boolean) {
|
||||
return function (
|
||||
_target: any,
|
||||
_propertyKey: string,
|
||||
descriptor: PropertyDescriptor,
|
||||
) {
|
||||
descriptor.enumerable = value;
|
||||
};
|
||||
}
|
||||
|
||||
export class A {
|
||||
@enumerable(false)
|
||||
a() {
|
||||
Test.value;
|
||||
}
|
||||
}
|
||||
"#;
|
||||
let module = parse_module(ParseParams {
|
||||
specifier: specifier.as_str().to_string(),
|
||||
source: SourceTextInfo::from_string(source.to_string()),
|
||||
media_type: deno_ast::MediaType::TypeScript,
|
||||
capture_tokens: false,
|
||||
maybe_syntax: None,
|
||||
scope_analysis: false,
|
||||
})
|
||||
.unwrap();
|
||||
let (code, _) = transpile(&module, &EmitOptions::default()).unwrap();
|
||||
assert!(code.contains("_applyDecoratedDescriptor("));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transpile_handle_code_nested_in_ts_nodes_with_jsx_pass() {
|
||||
// from issue 12409
|
||||
let specifier = resolve_url_or_path("https://deno.land/x/mod.ts").unwrap();
|
||||
let source = r#"
|
||||
export function g() {
|
||||
let algorithm: any
|
||||
algorithm = {}
|
||||
|
||||
return <Promise>(
|
||||
test(algorithm, false, keyUsages)
|
||||
)
|
||||
}
|
||||
"#;
|
||||
let module = parse_module(ParseParams {
|
||||
specifier: specifier.as_str().to_string(),
|
||||
source: SourceTextInfo::from_string(source.to_string()),
|
||||
media_type: deno_ast::MediaType::TypeScript,
|
||||
capture_tokens: false,
|
||||
maybe_syntax: None,
|
||||
scope_analysis: false,
|
||||
})
|
||||
.unwrap();
|
||||
let emit_options = EmitOptions {
|
||||
transform_jsx: true,
|
||||
..Default::default()
|
||||
};
|
||||
let (code, _) = transpile(&module, &emit_options).unwrap();
|
||||
let expected = r#"export function g() {
|
||||
let algorithm;
|
||||
algorithm = {};
|
||||
return test(algorithm, false, keyUsages);
|
||||
}"#;
|
||||
assert_eq!(&code[..expected.len()], expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn diagnostic_jsx_spread_instead_of_panic() {
|
||||
let specifier = resolve_url_or_path("https://deno.land/x/mod.ts").unwrap();
|
||||
let source = r#"const A = () => {
|
||||
return <div>{...[]}</div>;
|
||||
};"#;
|
||||
let parsed_source = parse_module(ParseParams {
|
||||
specifier: specifier.as_str().to_string(),
|
||||
source: SourceTextInfo::from_string(source.to_string()),
|
||||
media_type: deno_ast::MediaType::Tsx,
|
||||
capture_tokens: false,
|
||||
maybe_syntax: None,
|
||||
scope_analysis: false,
|
||||
})
|
||||
.unwrap();
|
||||
let err = transpile(&parsed_source, &Default::default())
|
||||
.err()
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(err.to_string(), "Spread children are not supported in React. at https://deno.land/x/mod.ts:2:15");
|
||||
}
|
||||
}
|
|
@ -1,524 +0,0 @@
|
|||
use deno_ast::swc::ast as swc_ast;
|
||||
use deno_ast::swc::common::DUMMY_SP;
|
||||
use deno_ast::swc::visit::noop_fold_type;
|
||||
use deno_ast::swc::visit::Fold;
|
||||
|
||||
/// Transforms import declarations to variable declarations
|
||||
/// with a dynamic import. This is used to provide import
|
||||
/// declaration support in the REPL.
|
||||
pub struct DownlevelImportsFolder;
|
||||
|
||||
impl Fold for DownlevelImportsFolder {
|
||||
noop_fold_type!(); // skip typescript specific nodes
|
||||
|
||||
fn fold_module_item(
|
||||
&mut self,
|
||||
module_item: swc_ast::ModuleItem,
|
||||
) -> swc_ast::ModuleItem {
|
||||
use deno_ast::swc::ast::*;
|
||||
|
||||
match module_item {
|
||||
ModuleItem::ModuleDecl(ModuleDecl::Import(import_decl)) => {
|
||||
// Handle type only imports
|
||||
if import_decl.type_only {
|
||||
// should have no side effects
|
||||
return create_empty_stmt();
|
||||
}
|
||||
|
||||
// The initializer (ex. `await import('./mod.ts')`)
|
||||
let initializer =
|
||||
create_await_import_expr(&import_decl.src.value, import_decl.asserts);
|
||||
|
||||
// Handle imports for the side effects
|
||||
// ex. `import "module.ts"` -> `await import("module.ts");`
|
||||
if import_decl.specifiers.is_empty() {
|
||||
return ModuleItem::Stmt(Stmt::Expr(ExprStmt {
|
||||
span: DUMMY_SP,
|
||||
expr: initializer,
|
||||
}));
|
||||
}
|
||||
|
||||
// Collect the specifiers and create the variable statement
|
||||
let named_import_props = import_decl
|
||||
.specifiers
|
||||
.iter()
|
||||
.filter_map(|specifier| match specifier {
|
||||
ImportSpecifier::Default(specifier) => Some(create_key_value(
|
||||
"default".to_string(),
|
||||
specifier.local.sym.to_string(),
|
||||
)),
|
||||
ImportSpecifier::Named(specifier) => {
|
||||
Some(match specifier.imported.as_ref() {
|
||||
Some(name) => create_key_value(
|
||||
match name {
|
||||
ModuleExportName::Ident(ident) => ident.sym.to_string(),
|
||||
ModuleExportName::Str(str) => str.value.to_string(),
|
||||
},
|
||||
specifier.local.sym.to_string(),
|
||||
),
|
||||
None => create_assignment(specifier.local.sym.to_string()),
|
||||
})
|
||||
}
|
||||
ImportSpecifier::Namespace(_) => None,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let namespace_import_name =
|
||||
import_decl
|
||||
.specifiers
|
||||
.iter()
|
||||
.find_map(|specifier| match specifier {
|
||||
ImportSpecifier::Namespace(specifier) => {
|
||||
Some(create_binding_ident(specifier.local.sym.to_string()))
|
||||
}
|
||||
_ => None,
|
||||
});
|
||||
|
||||
ModuleItem::Stmt(Stmt::Decl(Decl::Var(VarDecl {
|
||||
span: DUMMY_SP,
|
||||
kind: VarDeclKind::Const,
|
||||
declare: false,
|
||||
decls: {
|
||||
let mut decls = Vec::new();
|
||||
|
||||
if !named_import_props.is_empty() {
|
||||
decls.push(VarDeclarator {
|
||||
span: DUMMY_SP,
|
||||
name: Pat::Object(ObjectPat {
|
||||
span: DUMMY_SP,
|
||||
optional: false,
|
||||
props: named_import_props,
|
||||
type_ann: None,
|
||||
}),
|
||||
definite: false,
|
||||
init: Some(initializer.clone()),
|
||||
});
|
||||
}
|
||||
if let Some(namespace_import) = namespace_import_name {
|
||||
decls.push(VarDeclarator {
|
||||
span: DUMMY_SP,
|
||||
name: Pat::Ident(namespace_import),
|
||||
definite: false,
|
||||
init: Some(initializer),
|
||||
});
|
||||
}
|
||||
|
||||
decls
|
||||
},
|
||||
})))
|
||||
}
|
||||
_ => module_item,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Strips export declarations and exports on named exports for the REPL.
|
||||
pub struct StripExportsFolder;
|
||||
|
||||
impl Fold for StripExportsFolder {
|
||||
noop_fold_type!(); // skip typescript specific nodes
|
||||
|
||||
fn fold_module_item(
|
||||
&mut self,
|
||||
module_item: swc_ast::ModuleItem,
|
||||
) -> swc_ast::ModuleItem {
|
||||
use deno_ast::swc::ast::*;
|
||||
|
||||
match module_item {
|
||||
ModuleItem::ModuleDecl(ModuleDecl::ExportAll(export_all)) => {
|
||||
ModuleItem::Stmt(Stmt::Expr(ExprStmt {
|
||||
span: DUMMY_SP,
|
||||
expr: create_await_import_expr(
|
||||
&export_all.src.value,
|
||||
export_all.asserts,
|
||||
),
|
||||
}))
|
||||
}
|
||||
ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(export_named)) => {
|
||||
if let Some(src) = export_named.src {
|
||||
ModuleItem::Stmt(Stmt::Expr(ExprStmt {
|
||||
span: DUMMY_SP,
|
||||
expr: create_await_import_expr(&src.value, export_named.asserts),
|
||||
}))
|
||||
} else {
|
||||
create_empty_stmt()
|
||||
}
|
||||
}
|
||||
ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultExpr(default_expr)) => {
|
||||
// transform a default export expression to its expression
|
||||
ModuleItem::Stmt(Stmt::Expr(ExprStmt {
|
||||
span: DUMMY_SP,
|
||||
expr: default_expr.expr,
|
||||
}))
|
||||
}
|
||||
ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(export_decl)) => {
|
||||
// strip the export keyword on an exported declaration
|
||||
ModuleItem::Stmt(Stmt::Decl(export_decl.decl))
|
||||
}
|
||||
ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultDecl(default_decl)) => {
|
||||
// only keep named default exports
|
||||
match default_decl.decl {
|
||||
DefaultDecl::Fn(FnExpr {
|
||||
ident: Some(ident),
|
||||
function,
|
||||
}) => ModuleItem::Stmt(Stmt::Decl(Decl::Fn(FnDecl {
|
||||
declare: false,
|
||||
ident,
|
||||
function,
|
||||
}))),
|
||||
DefaultDecl::Class(ClassExpr {
|
||||
ident: Some(ident),
|
||||
class,
|
||||
}) => ModuleItem::Stmt(Stmt::Decl(Decl::Class(ClassDecl {
|
||||
declare: false,
|
||||
ident,
|
||||
class,
|
||||
}))),
|
||||
_ => create_empty_stmt(),
|
||||
}
|
||||
}
|
||||
_ => module_item,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn create_empty_stmt() -> swc_ast::ModuleItem {
|
||||
use swc_ast::*;
|
||||
ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP }))
|
||||
}
|
||||
|
||||
fn create_binding_ident(name: String) -> swc_ast::BindingIdent {
|
||||
swc_ast::BindingIdent {
|
||||
id: create_ident(name),
|
||||
type_ann: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn create_ident(name: String) -> swc_ast::Ident {
|
||||
swc_ast::Ident {
|
||||
span: DUMMY_SP,
|
||||
sym: name.into(),
|
||||
optional: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn create_key_value(key: String, value: String) -> swc_ast::ObjectPatProp {
|
||||
swc_ast::ObjectPatProp::KeyValue(swc_ast::KeyValuePatProp {
|
||||
// use a string literal because it will work in more scenarios than an identifier
|
||||
key: swc_ast::PropName::Str(swc_ast::Str {
|
||||
span: DUMMY_SP,
|
||||
value: key.into(),
|
||||
has_escape: false,
|
||||
kind: swc_ast::StrKind::Synthesized,
|
||||
}),
|
||||
value: Box::new(swc_ast::Pat::Ident(swc_ast::BindingIdent {
|
||||
id: swc_ast::Ident {
|
||||
span: DUMMY_SP,
|
||||
sym: value.into(),
|
||||
optional: false,
|
||||
},
|
||||
type_ann: None,
|
||||
})),
|
||||
})
|
||||
}
|
||||
|
||||
fn create_await_import_expr(
|
||||
module_specifier: &str,
|
||||
maybe_asserts: Option<swc_ast::ObjectLit>,
|
||||
) -> Box<swc_ast::Expr> {
|
||||
use swc_ast::*;
|
||||
let mut args = vec![ExprOrSpread {
|
||||
spread: None,
|
||||
expr: Box::new(Expr::Lit(Lit::Str(Str {
|
||||
span: DUMMY_SP,
|
||||
has_escape: false,
|
||||
kind: StrKind::Normal {
|
||||
contains_quote: false,
|
||||
},
|
||||
value: module_specifier.into(),
|
||||
}))),
|
||||
}];
|
||||
|
||||
// add assert object if it exists
|
||||
if let Some(asserts) = maybe_asserts {
|
||||
args.push(ExprOrSpread {
|
||||
spread: None,
|
||||
expr: Box::new(Expr::Object(ObjectLit {
|
||||
span: DUMMY_SP,
|
||||
props: vec![PropOrSpread::Prop(Box::new(Prop::KeyValue(
|
||||
KeyValueProp {
|
||||
key: PropName::Ident(create_ident("assert".to_string())),
|
||||
value: Box::new(Expr::Object(asserts)),
|
||||
},
|
||||
)))],
|
||||
})),
|
||||
})
|
||||
}
|
||||
|
||||
Box::new(Expr::Await(AwaitExpr {
|
||||
span: DUMMY_SP,
|
||||
arg: Box::new(Expr::Call(CallExpr {
|
||||
span: DUMMY_SP,
|
||||
callee: ExprOrSuper::Expr(Box::new(Expr::Ident(Ident {
|
||||
span: DUMMY_SP,
|
||||
sym: "import".into(),
|
||||
optional: false,
|
||||
}))),
|
||||
args,
|
||||
type_args: None,
|
||||
})),
|
||||
}))
|
||||
}
|
||||
|
||||
fn create_assignment(key: String) -> swc_ast::ObjectPatProp {
|
||||
swc_ast::ObjectPatProp::Assign(swc_ast::AssignPatProp {
|
||||
span: DUMMY_SP,
|
||||
key: create_ident(key),
|
||||
value: None,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use deno_ast::swc::ast::Module;
|
||||
use deno_ast::swc::codegen::text_writer::JsWriter;
|
||||
use deno_ast::swc::codegen::Node;
|
||||
use deno_ast::swc::common::FileName;
|
||||
use deno_ast::swc::common::SourceMap;
|
||||
use deno_ast::swc::parser::Parser;
|
||||
use deno_ast::swc::parser::StringInput;
|
||||
use deno_ast::swc::parser::Syntax;
|
||||
use deno_ast::swc::parser::TsConfig;
|
||||
use deno_ast::swc::visit::Fold;
|
||||
use deno_ast::swc::visit::FoldWith;
|
||||
use deno_ast::ModuleSpecifier;
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::rc::Rc;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_downlevel_imports_type_only() {
|
||||
test_transform(
|
||||
DownlevelImportsFolder,
|
||||
r#"import type { test } from "./mod.ts";"#,
|
||||
";",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_downlevel_imports_specifier_only() {
|
||||
test_transform(
|
||||
DownlevelImportsFolder,
|
||||
r#"import "./mod.ts";"#,
|
||||
r#"await import("./mod.ts");"#,
|
||||
);
|
||||
|
||||
test_transform(
|
||||
DownlevelImportsFolder,
|
||||
r#"import {} from "./mod.ts";"#,
|
||||
r#"await import("./mod.ts");"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_downlevel_imports_default() {
|
||||
test_transform(
|
||||
DownlevelImportsFolder,
|
||||
r#"import mod from "./mod.ts";"#,
|
||||
r#"const { "default": mod } = await import("./mod.ts");"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_downlevel_imports_named() {
|
||||
test_transform(
|
||||
DownlevelImportsFolder,
|
||||
r#"import { A } from "./mod.ts";"#,
|
||||
r#"const { A } = await import("./mod.ts");"#,
|
||||
);
|
||||
|
||||
test_transform(
|
||||
DownlevelImportsFolder,
|
||||
r#"import { A, B, C } from "./mod.ts";"#,
|
||||
r#"const { A , B , C } = await import("./mod.ts");"#,
|
||||
);
|
||||
|
||||
test_transform(
|
||||
DownlevelImportsFolder,
|
||||
r#"import { A as LocalA, B, C as LocalC } from "./mod.ts";"#,
|
||||
r#"const { "A": LocalA , B , "C": LocalC } = await import("./mod.ts");"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_downlevel_imports_namespace() {
|
||||
test_transform(
|
||||
DownlevelImportsFolder,
|
||||
r#"import * as mod from "./mod.ts";"#,
|
||||
r#"const mod = await import("./mod.ts");"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_downlevel_imports_mixed() {
|
||||
test_transform(
|
||||
DownlevelImportsFolder,
|
||||
r#"import myDefault, { A, B as LocalB } from "./mod.ts";"#,
|
||||
r#"const { "default": myDefault , A , "B": LocalB } = await import("./mod.ts");"#,
|
||||
);
|
||||
|
||||
test_transform(
|
||||
DownlevelImportsFolder,
|
||||
r#"import myDefault, * as mod from "./mod.ts";"#,
|
||||
r#"const { "default": myDefault } = await import("./mod.ts"), mod = await import("./mod.ts");"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_downlevel_imports_assertions() {
|
||||
test_transform(
|
||||
DownlevelImportsFolder,
|
||||
r#"import data from "./mod.json" assert { type: "json" };"#,
|
||||
"const { \"default\": data } = await import(\"./mod.json\", {\n assert: {\n type: \"json\"\n }\n});",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_strip_exports_export_all() {
|
||||
test_transform(
|
||||
StripExportsFolder,
|
||||
r#"export * from "./test.ts";"#,
|
||||
r#"await import("./test.ts");"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_strip_exports_export_named() {
|
||||
test_transform(
|
||||
StripExportsFolder,
|
||||
r#"export { test } from "./test.ts";"#,
|
||||
r#"await import("./test.ts");"#,
|
||||
);
|
||||
|
||||
test_transform(StripExportsFolder, r#"export { test };"#, ";");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_strip_exports_assertions() {
|
||||
test_transform(
|
||||
StripExportsFolder,
|
||||
r#"export { default as data } from "./mod.json" assert { type: "json" };"#,
|
||||
"await import(\"./mod.json\", {\n assert: {\n type: \"json\"\n }\n});",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_strip_exports_export_all_assertions() {
|
||||
// even though this doesn't really make sense for someone to do
|
||||
test_transform(
|
||||
StripExportsFolder,
|
||||
r#"export * from "./mod.json" assert { type: "json" };"#,
|
||||
"await import(\"./mod.json\", {\n assert: {\n type: \"json\"\n }\n});",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_strip_exports_export_default_expr() {
|
||||
test_transform(StripExportsFolder, "export default 5;", "5;");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_strip_exports_export_default_decl_name() {
|
||||
test_transform(
|
||||
StripExportsFolder,
|
||||
"export default class Test {}",
|
||||
"class Test {\n}",
|
||||
);
|
||||
|
||||
test_transform(
|
||||
StripExportsFolder,
|
||||
"export default function test() {}",
|
||||
"function test() {}",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_strip_exports_export_default_decl_no_name() {
|
||||
test_transform(StripExportsFolder, "export default class {}", ";");
|
||||
|
||||
test_transform(StripExportsFolder, "export default function() {}", ";");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_strip_exports_export_named_decls() {
|
||||
test_transform(
|
||||
StripExportsFolder,
|
||||
"export class Test {}",
|
||||
"class Test {\n}",
|
||||
);
|
||||
|
||||
test_transform(
|
||||
StripExportsFolder,
|
||||
"export function test() {}",
|
||||
"function test() {}",
|
||||
);
|
||||
|
||||
test_transform(StripExportsFolder, "export enum Test {}", "enum Test {\n}");
|
||||
|
||||
test_transform(
|
||||
StripExportsFolder,
|
||||
"export namespace Test {}",
|
||||
"module Test {\n}",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_strip_exports_not_in_namespace() {
|
||||
test_transform(
|
||||
StripExportsFolder,
|
||||
"namespace Test { export class Test {} }",
|
||||
"module Test {\n export class Test {\n }\n}",
|
||||
);
|
||||
}
|
||||
|
||||
fn test_transform(
|
||||
mut transform: impl Fold,
|
||||
src: &str,
|
||||
expected_output: &str,
|
||||
) {
|
||||
let (source_map, module) = parse(src);
|
||||
let output = print(source_map, module.fold_with(&mut transform));
|
||||
assert_eq!(output, format!("{}\n", expected_output));
|
||||
}
|
||||
|
||||
fn parse(src: &str) -> (Rc<SourceMap>, Module) {
|
||||
let source_map = Rc::new(SourceMap::default());
|
||||
let source_file = source_map.new_source_file(
|
||||
FileName::Url(ModuleSpecifier::parse("file:///test.ts").unwrap()),
|
||||
src.to_string(),
|
||||
);
|
||||
let input = StringInput::from(&*source_file);
|
||||
let syntax = Syntax::Typescript(TsConfig {
|
||||
..Default::default()
|
||||
});
|
||||
let mut parser = Parser::new(syntax, input, None);
|
||||
(source_map, parser.parse_module().unwrap())
|
||||
}
|
||||
|
||||
fn print(source_map: Rc<SourceMap>, module: Module) -> String {
|
||||
let mut buf = vec![];
|
||||
{
|
||||
let writer =
|
||||
Box::new(JsWriter::new(source_map.clone(), "\n", &mut buf, None));
|
||||
let config = deno_ast::swc::codegen::Config { minify: false };
|
||||
let mut emitter = deno_ast::swc::codegen::Emitter {
|
||||
cfg: config,
|
||||
comments: None,
|
||||
cm: source_map,
|
||||
wr: writer,
|
||||
};
|
||||
module.emit_with(&mut emitter).unwrap();
|
||||
}
|
||||
String::from_utf8(buf).unwrap()
|
||||
}
|
||||
}
|
|
@ -78,7 +78,7 @@ function benchRead128k() {
|
|||
return benchAsync(
|
||||
"read_128k",
|
||||
5e4,
|
||||
() => Deno.readFile("./cli/bench/fixtures/128k.bin"),
|
||||
() => Deno.readFile("./cli/bench/testdata/128k.bin"),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,11 +13,11 @@ use std::time::Duration;
|
|||
use test_util::lsp::LspClient;
|
||||
use test_util::lsp::LspResponseError;
|
||||
|
||||
static FIXTURE_CODE_LENS_TS: &str = include_str!("fixtures/code_lens.ts");
|
||||
static FIXTURE_DB_TS: &str = include_str!("fixtures/db.ts");
|
||||
static FIXTURE_DB_MESSAGES: &[u8] = include_bytes!("fixtures/db_messages.json");
|
||||
static FIXTURE_CODE_LENS_TS: &str = include_str!("testdata/code_lens.ts");
|
||||
static FIXTURE_DB_TS: &str = include_str!("testdata/db.ts");
|
||||
static FIXTURE_DB_MESSAGES: &[u8] = include_bytes!("testdata/db_messages.json");
|
||||
static FIXTURE_INIT_JSON: &[u8] =
|
||||
include_bytes!("fixtures/initialize_params.json");
|
||||
include_bytes!("testdata/initialize_params.json");
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
enum FixtureType {
|
||||
|
@ -57,7 +57,7 @@ fn bench_big_file_edits(deno_exe: &Path) -> Result<Duration, AnyError> {
|
|||
"textDocument/didOpen",
|
||||
json!({
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"languageId": "typescript",
|
||||
"version": 1,
|
||||
"text": FIXTURE_DB_TS
|
||||
|
@ -137,7 +137,7 @@ fn bench_code_lens(deno_exe: &Path) -> Result<Duration, AnyError> {
|
|||
"textDocument/didOpen",
|
||||
json!({
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/code_lens.ts",
|
||||
"uri": "file:///testdata/code_lens.ts",
|
||||
"languageId": "typescript",
|
||||
"version": 1,
|
||||
"text": FIXTURE_CODE_LENS_TS
|
||||
|
@ -167,7 +167,7 @@ fn bench_code_lens(deno_exe: &Path) -> Result<Duration, AnyError> {
|
|||
"textDocument/codeLens",
|
||||
json!({
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/code_lens.ts"
|
||||
"uri": "file:///testdata/code_lens.ts"
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 2
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -28,7 +28,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 3
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -53,7 +53,7 @@
|
|||
"type": "completion",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"position": {
|
||||
"line": 8330,
|
||||
|
@ -68,7 +68,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 4
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -93,7 +93,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 5
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -118,7 +118,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 6
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -143,7 +143,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 7
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -168,7 +168,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 8
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -193,7 +193,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 9
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -218,7 +218,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 10
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -243,7 +243,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 11
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -268,7 +268,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 12
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -293,7 +293,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -314,7 +314,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 13
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -339,7 +339,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -360,7 +360,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -381,7 +381,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 14
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -406,7 +406,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 15
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -431,7 +431,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 16
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -456,7 +456,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 17
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -481,7 +481,7 @@
|
|||
"type": "completion",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"position": {
|
||||
"line": 8331,
|
||||
|
@ -496,7 +496,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 18
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -521,7 +521,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 19
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -546,7 +546,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 20
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -571,7 +571,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 21
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -596,7 +596,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -617,7 +617,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -638,7 +638,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -659,7 +659,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -680,7 +680,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 22
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -705,7 +705,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 23
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -730,7 +730,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 24
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -755,7 +755,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 25
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -780,7 +780,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 26
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -805,7 +805,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 27
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -830,7 +830,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 28
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -855,7 +855,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 29
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -880,7 +880,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -901,7 +901,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 30
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -926,7 +926,7 @@
|
|||
"type": "completion",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"position": {
|
||||
"line": 8331,
|
||||
|
@ -942,7 +942,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -963,7 +963,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -984,7 +984,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1005,7 +1005,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1026,7 +1026,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1047,7 +1047,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1068,7 +1068,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1089,7 +1089,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1110,7 +1110,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1131,7 +1131,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1152,7 +1152,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1173,7 +1173,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1194,7 +1194,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1215,7 +1215,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1236,7 +1236,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1257,7 +1257,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1278,7 +1278,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1299,7 +1299,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1320,7 +1320,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1341,7 +1341,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1362,7 +1362,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1383,7 +1383,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1404,7 +1404,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 31
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -1429,7 +1429,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1450,7 +1450,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 32
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -1475,7 +1475,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1496,7 +1496,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1517,7 +1517,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1538,7 +1538,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 33
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -1563,7 +1563,7 @@
|
|||
"type": "completion",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"position": {
|
||||
"line": 8331,
|
||||
|
@ -1579,7 +1579,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1600,7 +1600,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1621,7 +1621,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 34
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -1646,7 +1646,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1667,7 +1667,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1688,7 +1688,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 35
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -1713,7 +1713,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1734,7 +1734,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1755,7 +1755,7 @@
|
|||
"type": "hover",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"position": {
|
||||
"line": 8331,
|
||||
|
@ -1767,7 +1767,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1809,7 +1809,7 @@
|
|||
"type": "hover",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"position": {
|
||||
"line": 8331,
|
||||
|
@ -1821,7 +1821,7 @@
|
|||
"type": "hover",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"position": {
|
||||
"line": 8331,
|
||||
|
@ -1833,7 +1833,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1875,7 +1875,7 @@
|
|||
"type": "hover",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"position": {
|
||||
"line": 8331,
|
||||
|
@ -1887,7 +1887,7 @@
|
|||
"type": "hover",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"position": {
|
||||
"line": 8331,
|
||||
|
@ -1899,7 +1899,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -1941,7 +1941,7 @@
|
|||
"type": "hover",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"position": {
|
||||
"line": 8331,
|
||||
|
@ -1953,7 +1953,7 @@
|
|||
"type": "hover",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"position": {
|
||||
"line": 8331,
|
||||
|
@ -1965,7 +1965,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -2007,7 +2007,7 @@
|
|||
"type": "hover",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"position": {
|
||||
"line": 8331,
|
||||
|
@ -2019,7 +2019,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -2061,7 +2061,7 @@
|
|||
"type": "highlight",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"position": {
|
||||
"line": 8331,
|
||||
|
@ -2073,7 +2073,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -2112,7 +2112,7 @@
|
|||
"type": "hover",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"position": {
|
||||
"line": 8331,
|
||||
|
@ -2124,7 +2124,7 @@
|
|||
"type": "change",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts",
|
||||
"uri": "file:///testdata/db.ts",
|
||||
"version": 36
|
||||
},
|
||||
"contentChanges": [
|
||||
|
@ -2149,7 +2149,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -2188,7 +2188,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
||||
|
@ -2227,7 +2227,7 @@
|
|||
"type": "action",
|
||||
"params": {
|
||||
"textDocument": {
|
||||
"uri": "file:///fixtures/db.ts"
|
||||
"uri": "file:///testdata/db.ts"
|
||||
},
|
||||
"range": {
|
||||
"start": {
|
25
cli/build.rs
25
cli/build.rs
|
@ -38,7 +38,30 @@ fn create_snapshot(
|
|||
let snapshot = js_runtime.snapshot();
|
||||
let snapshot_slice: &[u8] = &*snapshot;
|
||||
println!("Snapshot size: {}", snapshot_slice.len());
|
||||
std::fs::write(&snapshot_path, snapshot_slice).unwrap();
|
||||
|
||||
let compressed_snapshot_with_size = {
|
||||
let mut vec = vec![];
|
||||
|
||||
vec.extend_from_slice(
|
||||
&u32::try_from(snapshot.len())
|
||||
.expect("snapshot larger than 4gb")
|
||||
.to_le_bytes(),
|
||||
);
|
||||
|
||||
vec.extend_from_slice(
|
||||
&zstd::block::compress(snapshot_slice, 22)
|
||||
.expect("snapshot compression failed"),
|
||||
);
|
||||
|
||||
vec
|
||||
};
|
||||
|
||||
println!(
|
||||
"Snapshot compressed size: {}",
|
||||
compressed_snapshot_with_size.len()
|
||||
);
|
||||
|
||||
std::fs::write(&snapshot_path, compressed_snapshot_with_size).unwrap();
|
||||
println!("Snapshot written to: {} ", snapshot_path.display());
|
||||
}
|
||||
|
||||
|
|
|
@ -149,7 +149,7 @@ impl Loader for FetchCacher {
|
|||
let file_fetcher = self.file_fetcher.clone();
|
||||
|
||||
async move {
|
||||
let load_result = file_fetcher
|
||||
file_fetcher
|
||||
.fetch(&specifier, &mut permissions)
|
||||
.await
|
||||
.map_or_else(
|
||||
|
@ -170,9 +170,7 @@ impl Loader for FetchCacher {
|
|||
content: file.source,
|
||||
}))
|
||||
},
|
||||
);
|
||||
|
||||
(specifier, load_result)
|
||||
)
|
||||
}
|
||||
.boxed()
|
||||
}
|
||||
|
@ -295,7 +293,7 @@ impl Loader for MemoryCacher {
|
|||
maybe_headers: None,
|
||||
content: c.to_owned(),
|
||||
});
|
||||
Box::pin(future::ready((specifier.clone(), Ok(response))))
|
||||
Box::pin(future::ready(Ok(response)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1193,7 +1193,7 @@ mod tests {
|
|||
let cwd = testdir("basic");
|
||||
let main = Url::from_file_path(cwd.join("main.js")).unwrap();
|
||||
let expected =
|
||||
Url::parse("https://deno.land/std@0.120.0/node/http.ts").unwrap();
|
||||
Url::parse("https://deno.land/std@0.121.0/node/http.ts").unwrap();
|
||||
|
||||
let actual = node_resolve("http", main.as_str(), &cwd).unwrap();
|
||||
println!("actual {}", actual);
|
||||
|
|
|
@ -16,7 +16,7 @@ pub(crate) use esm_resolver::NodeEsmResolver;
|
|||
// each release, a better mechanism is preferable, but it's a quick and dirty
|
||||
// solution to avoid printing `X-Deno-Warning` headers when the compat layer is
|
||||
// downloaded
|
||||
static STD_URL_STR: &str = "https://deno.land/std@0.120.0/";
|
||||
static STD_URL_STR: &str = "https://deno.land/std@0.121.0/";
|
||||
|
||||
static SUPPORTED_MODULES: &[&str] = &[
|
||||
"assert",
|
||||
|
|
|
@ -409,7 +409,7 @@ impl fmt::Display for Diagnostics {
|
|||
if i > 0 {
|
||||
write!(f, "\n\n")?;
|
||||
}
|
||||
write!(f, "{}", item.to_string())?;
|
||||
write!(f, "{}", item)?;
|
||||
i += 1;
|
||||
}
|
||||
|
||||
|
|
24
cli/dts/lib.deno.unstable.d.ts
vendored
24
cli/dts/lib.deno.unstable.d.ts
vendored
|
@ -126,6 +126,8 @@ declare namespace Deno {
|
|||
Result extends NativeType = NativeType,
|
||||
NonBlocking extends boolean = boolean,
|
||||
> {
|
||||
/** Name of the symbol, defaults to the key name in symbols object. */
|
||||
name?: string;
|
||||
parameters: Parameters;
|
||||
result: Result;
|
||||
/** When true, function calls will run on a dedicated blocking thread and will return a Promise resolving to the `result`. */
|
||||
|
@ -149,7 +151,7 @@ declare namespace Deno {
|
|||
|
||||
type StaticForeignFunctionParameter<T> = T extends "void" ? void
|
||||
: T extends StaticNativeNumberType ? number
|
||||
: T extends "pointer" ? Deno.UnsafePointer | Deno.TypedArray
|
||||
: T extends "pointer" ? Deno.UnsafePointer | Deno.TypedArray | null
|
||||
: unknown;
|
||||
|
||||
/** Infers a foreign function parameter list. */
|
||||
|
@ -248,6 +250,26 @@ declare namespace Deno {
|
|||
copyInto(destination: TypedArray, offset?: number): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* **UNSTABLE**: Unsafe and new API, beware!
|
||||
*
|
||||
* An unsafe pointer to a function, for calling functions that are not
|
||||
* present as symbols.
|
||||
*/
|
||||
export class UnsafeFnPointer<Fn extends ForeignFunction> {
|
||||
pointer: UnsafePointer;
|
||||
definition: Fn;
|
||||
|
||||
constructor(pointer: UnsafePointer, definition: Fn);
|
||||
|
||||
call(
|
||||
...args: StaticForeignFunctionParameters<Fn["parameters"]>
|
||||
): ConditionalAsync<
|
||||
Fn["nonblocking"],
|
||||
StaticForeignFunctionResult<Fn["result"]>
|
||||
>;
|
||||
}
|
||||
|
||||
/** A dynamic library resource */
|
||||
export interface DynamicLibrary<S extends ForeignFunctionInterface> {
|
||||
/** All of the registered symbols along with functions for calling them */
|
||||
|
|
199
cli/emit.rs
199
cli/emit.rs
|
@ -4,10 +4,10 @@
|
|||
//! populate a cache, emit files, and transform a graph into the structures for
|
||||
//! loading into an isolate.
|
||||
|
||||
use crate::ast;
|
||||
use crate::cache::CacheType;
|
||||
use crate::cache::Cacher;
|
||||
use crate::colors;
|
||||
use crate::config_file;
|
||||
use crate::config_file::ConfigFile;
|
||||
use crate::config_file::IgnoredCompilerOptions;
|
||||
use crate::config_file::TsConfig;
|
||||
|
@ -15,10 +15,25 @@ use crate::diagnostics::Diagnostics;
|
|||
use crate::flags;
|
||||
use crate::graph_util::GraphData;
|
||||
use crate::graph_util::ModuleEntry;
|
||||
use crate::text_encoding::strip_bom;
|
||||
use crate::tsc;
|
||||
use crate::version;
|
||||
|
||||
use deno_ast::get_syntax;
|
||||
use deno_ast::swc;
|
||||
use deno_ast::swc::bundler::Hook;
|
||||
use deno_ast::swc::bundler::ModuleRecord;
|
||||
use deno_ast::swc::common::comments::SingleThreadedComments;
|
||||
use deno_ast::swc::common::FileName;
|
||||
use deno_ast::swc::common::Mark;
|
||||
use deno_ast::swc::common::SourceMap;
|
||||
use deno_ast::swc::common::Span;
|
||||
use deno_ast::swc::common::Spanned;
|
||||
use deno_ast::swc::parser::error::Error as SwcError;
|
||||
use deno_ast::swc::parser::lexer::Lexer;
|
||||
use deno_ast::swc::parser::StringInput;
|
||||
use deno_ast::Diagnostic;
|
||||
use deno_ast::LineAndColumnDisplay;
|
||||
use deno_core::anyhow::anyhow;
|
||||
use deno_core::anyhow::Context;
|
||||
use deno_core::error::AnyError;
|
||||
|
@ -27,6 +42,7 @@ use deno_core::serde::Deserialize;
|
|||
use deno_core::serde::Deserializer;
|
||||
use deno_core::serde::Serialize;
|
||||
use deno_core::serde::Serializer;
|
||||
use deno_core::serde_json;
|
||||
use deno_core::serde_json::json;
|
||||
use deno_core::serde_json::Value;
|
||||
use deno_core::ModuleSpecifier;
|
||||
|
@ -42,6 +58,13 @@ use std::result;
|
|||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
|
||||
const IGNORE_DIRECTIVES: &[&str] = &[
|
||||
"// deno-fmt-ignore-file",
|
||||
"// deno-lint-ignore-file",
|
||||
"// This code was bundled using `deno bundle` and it's not recommended to edit it manually",
|
||||
""
|
||||
];
|
||||
|
||||
/// Represents the "default" type library that should be used when type
|
||||
/// checking the code in the module graph. Note that a user provided config
|
||||
/// of `"lib"` would override this value.
|
||||
|
@ -503,13 +526,14 @@ impl From<BundleType> for swc::bundler::ModuleType {
|
|||
pub(crate) struct BundleOptions {
|
||||
pub bundle_type: BundleType,
|
||||
pub ts_config: TsConfig,
|
||||
pub emit_ignore_directives: bool,
|
||||
}
|
||||
|
||||
/// A module loader for swc which does the appropriate retrieval and transpiling
|
||||
/// of modules from the graph.
|
||||
struct BundleLoader<'a> {
|
||||
cm: Rc<swc::common::SourceMap>,
|
||||
emit_options: &'a ast::EmitOptions,
|
||||
emit_options: &'a deno_ast::EmitOptions,
|
||||
graph: &'a ModuleGraph,
|
||||
}
|
||||
|
||||
|
@ -521,7 +545,7 @@ impl swc::bundler::Load for BundleLoader<'_> {
|
|||
match file_name {
|
||||
swc::common::FileName::Url(specifier) => {
|
||||
if let Some(m) = self.graph.get(specifier) {
|
||||
let (fm, module) = ast::transpile_module(
|
||||
let (fm, module) = transpile_module(
|
||||
specifier,
|
||||
m.maybe_source().unwrap_or(""),
|
||||
*m.media_type(),
|
||||
|
@ -548,6 +572,77 @@ impl swc::bundler::Load for BundleLoader<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Transpiles a source module into an swc SourceFile.
|
||||
fn transpile_module(
|
||||
specifier: &ModuleSpecifier,
|
||||
source: &str,
|
||||
media_type: MediaType,
|
||||
options: &deno_ast::EmitOptions,
|
||||
cm: Rc<swc::common::SourceMap>,
|
||||
) -> Result<(Rc<swc::common::SourceFile>, swc::ast::Module), AnyError> {
|
||||
let source = strip_bom(source);
|
||||
let source = if media_type == MediaType::Json {
|
||||
format!(
|
||||
"export default JSON.parse(`{}`);",
|
||||
source.replace("${", "\\${").replace('`', "\\`")
|
||||
)
|
||||
} else {
|
||||
source.to_string()
|
||||
};
|
||||
let source_file =
|
||||
cm.new_source_file(FileName::Url(specifier.clone()), source);
|
||||
let input = StringInput::from(&*source_file);
|
||||
let comments = SingleThreadedComments::default();
|
||||
let syntax = if media_type == MediaType::Json {
|
||||
get_syntax(MediaType::JavaScript)
|
||||
} else {
|
||||
get_syntax(media_type)
|
||||
};
|
||||
let lexer = Lexer::new(syntax, deno_ast::ES_VERSION, input, Some(&comments));
|
||||
let mut parser = swc::parser::Parser::new_from(lexer);
|
||||
let module = parser
|
||||
.parse_module()
|
||||
.map_err(|e| swc_err_to_diagnostic(&cm, specifier, e))?;
|
||||
let diagnostics = parser
|
||||
.take_errors()
|
||||
.into_iter()
|
||||
.map(|e| swc_err_to_diagnostic(&cm, specifier, e))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let top_level_mark = Mark::fresh(Mark::root());
|
||||
let program = deno_ast::fold_program(
|
||||
swc::ast::Program::Module(module),
|
||||
options,
|
||||
cm,
|
||||
&comments,
|
||||
top_level_mark,
|
||||
&diagnostics,
|
||||
)?;
|
||||
let module = match program {
|
||||
swc::ast::Program::Module(module) => module,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
Ok((source_file, module))
|
||||
}
|
||||
|
||||
fn swc_err_to_diagnostic(
|
||||
source_map: &SourceMap,
|
||||
specifier: &ModuleSpecifier,
|
||||
err: SwcError,
|
||||
) -> Diagnostic {
|
||||
let location = source_map.lookup_char_pos(err.span().lo);
|
||||
Diagnostic {
|
||||
specifier: specifier.to_string(),
|
||||
span: err.span(),
|
||||
display_position: LineAndColumnDisplay {
|
||||
line_number: location.line,
|
||||
column_number: location.col_display + 1,
|
||||
},
|
||||
kind: err.into_kind(),
|
||||
}
|
||||
}
|
||||
|
||||
/// A resolver implementation for swc that resolves specifiers from the graph.
|
||||
struct BundleResolver<'a>(&'a ModuleGraph);
|
||||
|
||||
|
@ -589,8 +684,8 @@ pub(crate) fn bundle(
|
|||
) -> Result<(String, Option<String>), AnyError> {
|
||||
let globals = swc::common::Globals::new();
|
||||
deno_ast::swc::common::GLOBALS.set(&globals, || {
|
||||
let emit_options: ast::EmitOptions = options.ts_config.into();
|
||||
let source_map_config = ast::SourceMapConfig {
|
||||
let emit_options: deno_ast::EmitOptions = options.ts_config.into();
|
||||
let source_map_config = deno_ast::SourceMapConfig {
|
||||
inline_sources: emit_options.inline_sources,
|
||||
};
|
||||
|
||||
|
@ -609,7 +704,7 @@ pub(crate) fn bundle(
|
|||
};
|
||||
// This hook will rewrite the `import.meta` when bundling to give a consistent
|
||||
// behavior between bundled and unbundled code.
|
||||
let hook = Box::new(ast::BundleHook);
|
||||
let hook = Box::new(BundleHook);
|
||||
let mut bundler = swc::bundler::Bundler::new(
|
||||
&globals,
|
||||
cm.clone(),
|
||||
|
@ -630,12 +725,21 @@ pub(crate) fn bundle(
|
|||
let mut srcmap = Vec::new();
|
||||
{
|
||||
let cfg = swc::codegen::Config { minify: false };
|
||||
let wr = Box::new(swc::codegen::text_writer::JsWriter::new(
|
||||
let mut wr = Box::new(swc::codegen::text_writer::JsWriter::new(
|
||||
cm.clone(),
|
||||
"\n",
|
||||
&mut buf,
|
||||
Some(&mut srcmap),
|
||||
));
|
||||
|
||||
if options.emit_ignore_directives {
|
||||
// write leading comments in bundled file
|
||||
use swc::codegen::text_writer::WriteJs;
|
||||
use swc::common::source_map::DUMMY_SP;
|
||||
let cmt = IGNORE_DIRECTIVES.join("\n") + "\n";
|
||||
wr.write_comment(DUMMY_SP, &cmt)?;
|
||||
}
|
||||
|
||||
let mut emitter = swc::codegen::Emitter {
|
||||
cfg,
|
||||
cm: cm.clone(),
|
||||
|
@ -705,11 +809,10 @@ pub(crate) fn emit(
|
|||
if is_valid && !needs_reload {
|
||||
continue;
|
||||
}
|
||||
let (emit, maybe_map) =
|
||||
ast::transpile(&module.parsed_source, &emit_options)?;
|
||||
let transpiled_source = module.parsed_source.transpile(&emit_options)?;
|
||||
emit_count += 1;
|
||||
cache.set(CacheType::Emit, &module.specifier, emit)?;
|
||||
if let Some(map) = maybe_map {
|
||||
cache.set(CacheType::Emit, &module.specifier, transpiled_source.text)?;
|
||||
if let Some(map) = transpiled_source.source_map {
|
||||
cache.set(CacheType::SourceMap, &module.specifier, map)?;
|
||||
}
|
||||
if !is_valid {
|
||||
|
@ -844,6 +947,80 @@ pub(crate) fn to_file_map(
|
|||
files
|
||||
}
|
||||
|
||||
/// This contains the logic for Deno to rewrite the `import.meta` when bundling.
|
||||
pub struct BundleHook;
|
||||
|
||||
impl Hook for BundleHook {
|
||||
fn get_import_meta_props(
|
||||
&self,
|
||||
span: Span,
|
||||
module_record: &ModuleRecord,
|
||||
) -> Result<Vec<deno_ast::swc::ast::KeyValueProp>, AnyError> {
|
||||
use deno_ast::swc::ast;
|
||||
|
||||
Ok(vec![
|
||||
ast::KeyValueProp {
|
||||
key: ast::PropName::Ident(ast::Ident::new("url".into(), span)),
|
||||
value: Box::new(ast::Expr::Lit(ast::Lit::Str(ast::Str {
|
||||
span,
|
||||
value: module_record.file_name.to_string().into(),
|
||||
kind: ast::StrKind::Synthesized,
|
||||
has_escape: false,
|
||||
}))),
|
||||
},
|
||||
ast::KeyValueProp {
|
||||
key: ast::PropName::Ident(ast::Ident::new("main".into(), span)),
|
||||
value: Box::new(if module_record.is_entry {
|
||||
ast::Expr::Member(ast::MemberExpr {
|
||||
span,
|
||||
obj: Box::new(ast::Expr::MetaProp(ast::MetaPropExpr {
|
||||
span,
|
||||
kind: ast::MetaPropKind::ImportMeta,
|
||||
})),
|
||||
prop: ast::MemberProp::Ident(ast::Ident::new("main".into(), span)),
|
||||
})
|
||||
} else {
|
||||
ast::Expr::Lit(ast::Lit::Bool(ast::Bool { span, value: false }))
|
||||
}),
|
||||
},
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
impl From<config_file::TsConfig> for deno_ast::EmitOptions {
|
||||
fn from(config: config_file::TsConfig) -> Self {
|
||||
let options: config_file::EmitConfigOptions =
|
||||
serde_json::from_value(config.0).unwrap();
|
||||
let imports_not_used_as_values =
|
||||
match options.imports_not_used_as_values.as_str() {
|
||||
"preserve" => deno_ast::ImportsNotUsedAsValues::Preserve,
|
||||
"error" => deno_ast::ImportsNotUsedAsValues::Error,
|
||||
_ => deno_ast::ImportsNotUsedAsValues::Remove,
|
||||
};
|
||||
let (transform_jsx, jsx_automatic, jsx_development) =
|
||||
match options.jsx.as_str() {
|
||||
"react" => (true, false, false),
|
||||
"react-jsx" => (true, true, false),
|
||||
"react-jsxdev" => (true, true, true),
|
||||
_ => (false, false, false),
|
||||
};
|
||||
deno_ast::EmitOptions {
|
||||
emit_metadata: options.emit_decorator_metadata,
|
||||
imports_not_used_as_values,
|
||||
inline_source_map: options.inline_source_map,
|
||||
inline_sources: options.inline_sources,
|
||||
source_map: options.source_map,
|
||||
jsx_automatic,
|
||||
jsx_development,
|
||||
jsx_factory: options.jsx_factory,
|
||||
jsx_fragment_factory: options.jsx_fragment_factory,
|
||||
jsx_import_source: options.jsx_import_source,
|
||||
transform_jsx,
|
||||
var_decl_imports: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
@ -60,7 +60,7 @@ where
|
|||
{
|
||||
let result = watch_future.await;
|
||||
if let Err(err) = result {
|
||||
let msg = format!("{}: {}", colors::red_bold("error"), err.to_string(),);
|
||||
let msg = format!("{}: {}", colors::red_bold("error"), err);
|
||||
eprintln!("{}", msg);
|
||||
}
|
||||
}
|
||||
|
|
555
cli/flags.rs
555
cli/flags.rs
File diff suppressed because it is too large
Load diff
|
@ -26,7 +26,7 @@ impl FromStr for BarePort {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn validator(host_and_port: String) -> Result<(), String> {
|
||||
pub fn validator(host_and_port: &str) -> Result<(), String> {
|
||||
if Url::parse(&format!("deno://{}", host_and_port)).is_ok()
|
||||
|| host_and_port.parse::<IpAddr>().is_ok()
|
||||
|| host_and_port.parse::<BarePort>().is_ok()
|
||||
|
@ -53,9 +53,9 @@ pub fn parse(paths: Vec<String>) -> clap::Result<Vec<String>> {
|
|||
out.push(format!("{}:{}", host, port.0));
|
||||
}
|
||||
} else {
|
||||
return Err(clap::Error::with_description(
|
||||
&format!("Bad host:port pair: {}", host_and_port),
|
||||
return Err(clap::Error::raw(
|
||||
clap::ErrorKind::InvalidValue,
|
||||
format!("Bad host:port pair: {}", host_and_port),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ fn format_frame(frame: &JsStackFrame) -> String {
|
|||
if frame.is_promise_all {
|
||||
result += &italic_bold(&format!(
|
||||
"Promise.all (index {})",
|
||||
frame.promise_index.unwrap_or_default().to_string()
|
||||
frame.promise_index.unwrap_or_default()
|
||||
))
|
||||
.to_string();
|
||||
return result;
|
||||
|
|
|
@ -348,6 +348,20 @@ pub fn specifier_parent(specifier: &ModuleSpecifier) -> ModuleSpecifier {
|
|||
specifier
|
||||
}
|
||||
|
||||
/// This function checks if input path has trailing slash or not. If input path
|
||||
/// has trailing slash it will return true else it will return false.
|
||||
pub fn path_has_trailing_slash(path: &Path) -> bool {
|
||||
if let Some(path_str) = path.to_str() {
|
||||
if cfg!(windows) {
|
||||
path_str.ends_with('\\')
|
||||
} else {
|
||||
path_str.ends_with('/')
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -691,4 +705,29 @@ mod tests {
|
|||
assert_eq!(result.to_string(), expected);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_path_has_trailing_slash() {
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
run_test("/Users/johndoe/Desktop/deno-project/target/", true);
|
||||
run_test(r"/Users/johndoe/deno-project/target//", true);
|
||||
run_test("/Users/johndoe/Desktop/deno-project", false);
|
||||
run_test(r"/Users/johndoe/deno-project\", false);
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
{
|
||||
run_test(r"C:\test\deno-project\", true);
|
||||
run_test(r"C:\test\deno-project\\", true);
|
||||
run_test(r"C:\test\file.txt", false);
|
||||
run_test(r"C:\test\file.txt/", false);
|
||||
}
|
||||
|
||||
fn run_test(path_str: &str, expected: bool) {
|
||||
let path = Path::new(path_str);
|
||||
let result = path_has_trailing_slash(path);
|
||||
assert_eq!(result, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -288,7 +288,7 @@ impl GraphData {
|
|||
if !range.specifier.as_str().contains("$deno") {
|
||||
return Some(Err(custom_error(
|
||||
get_error_class_name(&error.clone().into()),
|
||||
format!("{}\n at {}", error.to_string(), range),
|
||||
format!("{}\n at {}", error, range),
|
||||
)));
|
||||
}
|
||||
return Some(Err(error.clone().into()));
|
||||
|
@ -307,7 +307,7 @@ impl GraphData {
|
|||
if !range.specifier.as_str().contains("$deno") {
|
||||
return Some(Err(custom_error(
|
||||
get_error_class_name(&error.clone().into()),
|
||||
format!("{}\n at {}", error.to_string(), range),
|
||||
format!("{}\n at {}", error, range),
|
||||
)));
|
||||
}
|
||||
return Some(Err(error.clone().into()));
|
||||
|
@ -323,7 +323,7 @@ impl GraphData {
|
|||
if !range.specifier.as_str().contains("$deno") {
|
||||
return Some(Err(custom_error(
|
||||
get_error_class_name(&error.clone().into()),
|
||||
format!("{}\n at {}", error.to_string(), range),
|
||||
format!("{}\n at {}", error, range),
|
||||
)));
|
||||
}
|
||||
return Some(Err(error.clone().into()));
|
||||
|
|
|
@ -80,6 +80,7 @@ impl CacheServer {
|
|||
maybe_resolver,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
|
||||
|
|
|
@ -157,7 +157,7 @@ impl DenoTestCollector {
|
|||
|
||||
impl Visit for DenoTestCollector {
|
||||
fn visit_call_expr(&mut self, node: &ast::CallExpr) {
|
||||
if let ast::ExprOrSuper::Expr(callee_expr) = &node.callee {
|
||||
if let ast::Callee::Expr(callee_expr) = &node.callee {
|
||||
match callee_expr.as_ref() {
|
||||
ast::Expr::Ident(ident) => {
|
||||
if self.test_vars.contains(&ident.sym.to_string()) {
|
||||
|
@ -165,13 +165,11 @@ impl Visit for DenoTestCollector {
|
|||
}
|
||||
}
|
||||
ast::Expr::Member(member_expr) => {
|
||||
if let ast::Expr::Ident(ns_prop_ident) = member_expr.prop.as_ref() {
|
||||
if let ast::MemberProp::Ident(ns_prop_ident) = &member_expr.prop {
|
||||
if ns_prop_ident.sym.to_string() == "test" {
|
||||
if let ast::ExprOrSuper::Expr(obj_expr) = &member_expr.obj {
|
||||
if let ast::Expr::Ident(ident) = obj_expr.as_ref() {
|
||||
if ident.sym.to_string() == "Deno" {
|
||||
self.check_call_expr(node, &ns_prop_ident.span);
|
||||
}
|
||||
if let ast::Expr::Ident(ident) = member_expr.obj.as_ref() {
|
||||
if ident.sym.to_string() == "Deno" {
|
||||
self.check_call_expr(node, &ns_prop_ident.span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -219,16 +217,12 @@ impl Visit for DenoTestCollector {
|
|||
}
|
||||
// Identify variable assignments where the init is `Deno.test`
|
||||
ast::Expr::Member(member_expr) => {
|
||||
if let ast::ExprOrSuper::Expr(expr) = &member_expr.obj {
|
||||
if let ast::Expr::Ident(obj_ident) = expr.as_ref() {
|
||||
if obj_ident.sym.to_string() == "Deno" {
|
||||
if let ast::Expr::Ident(prop_ident) =
|
||||
&member_expr.prop.as_ref()
|
||||
{
|
||||
if prop_ident.sym.to_string() == "test" {
|
||||
if let ast::Pat::Ident(binding_ident) = &decl.name {
|
||||
self.test_vars.insert(binding_ident.id.sym.to_string());
|
||||
}
|
||||
if let ast::Expr::Ident(obj_ident) = member_expr.obj.as_ref() {
|
||||
if obj_ident.sym.to_string() == "Deno" {
|
||||
if let ast::MemberProp::Ident(prop_ident) = &member_expr.prop {
|
||||
if prop_ident.sym.to_string() == "test" {
|
||||
if let ast::Pat::Ident(binding_ident) = &decl.name {
|
||||
self.test_vars.insert(binding_ident.id.sym.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -428,18 +428,10 @@ fn relative_specifier(
|
|||
}
|
||||
}
|
||||
if parts.is_empty() {
|
||||
format!(
|
||||
"./{}{}",
|
||||
last_a,
|
||||
specifier[Position::AfterPath..].to_string()
|
||||
)
|
||||
format!("./{}{}", last_a, &specifier[Position::AfterPath..])
|
||||
} else {
|
||||
parts.push(last_a);
|
||||
format!(
|
||||
"{}{}",
|
||||
parts.join("/"),
|
||||
specifier[Position::AfterPath..].to_string()
|
||||
)
|
||||
format!("{}{}", parts.join("/"), &specifier[Position::AfterPath..])
|
||||
}
|
||||
} else {
|
||||
specifier[Position::BeforePath..].into()
|
||||
|
|
|
@ -588,8 +588,8 @@ pub(crate) fn to_hover_text(
|
|||
"blob" => "_(a blob url)_".to_string(),
|
||||
_ => format!(
|
||||
"{}​{}",
|
||||
specifier[..url::Position::AfterScheme].to_string(),
|
||||
specifier[url::Position::AfterScheme..].to_string()
|
||||
&specifier[..url::Position::AfterScheme],
|
||||
&specifier[url::Position::AfterScheme..],
|
||||
)
|
||||
.replace('@', "​@"),
|
||||
},
|
||||
|
|
|
@ -62,6 +62,7 @@ use crate::file_fetcher::get_source_from_data_url;
|
|||
use crate::fs_util;
|
||||
use crate::logger;
|
||||
use crate::lsp::logging::lsp_log;
|
||||
use crate::proc_state::import_map_from_text;
|
||||
use crate::tools::fmt::format_file;
|
||||
use crate::tools::fmt::format_parsed_source;
|
||||
|
||||
|
@ -495,12 +496,9 @@ impl Inner {
|
|||
)
|
||||
})?
|
||||
};
|
||||
let import_map = Arc::new(ImportMap::from_json(
|
||||
&import_map_url.to_string(),
|
||||
&import_map_json,
|
||||
)?);
|
||||
let import_map = import_map_from_text(&import_map_url, &import_map_json)?;
|
||||
self.maybe_import_map_uri = Some(import_map_url);
|
||||
self.maybe_import_map = Some(import_map);
|
||||
self.maybe_import_map = Some(Arc::new(import_map));
|
||||
} else {
|
||||
self.maybe_import_map = None;
|
||||
}
|
||||
|
|
27
cli/main.rs
27
cli/main.rs
|
@ -1,6 +1,5 @@
|
|||
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
mod ast;
|
||||
mod auth_tokens;
|
||||
mod cache;
|
||||
mod checksum;
|
||||
|
@ -378,7 +377,14 @@ async fn compile_command(
|
|||
let ps = ProcState::build(flags.clone()).await?;
|
||||
let deno_dir = &ps.dir;
|
||||
|
||||
let output = compile_flags.output.or_else(|| {
|
||||
let output = compile_flags.output.and_then(|output| {
|
||||
if fs_util::path_has_trailing_slash(&output) {
|
||||
let infer_file_name = infer_name_from_url(&module_specifier).map(PathBuf::from)?;
|
||||
Some(output.join(infer_file_name))
|
||||
} else {
|
||||
Some(output)
|
||||
}
|
||||
}).or_else(|| {
|
||||
infer_name_from_url(&module_specifier).map(PathBuf::from)
|
||||
}).ok_or_else(|| generic_error(
|
||||
"An executable name was not provided. One could not be inferred from the URL. Aborting.",
|
||||
|
@ -468,6 +474,7 @@ async fn info_command(
|
|||
maybe_resolver,
|
||||
maybe_locker,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
|
||||
|
@ -647,6 +654,7 @@ async fn create_graph_and_maybe_check(
|
|||
maybe_resolver,
|
||||
maybe_locker,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await,
|
||||
);
|
||||
|
@ -725,6 +733,7 @@ fn bundle_module_graph(
|
|||
emit::BundleOptions {
|
||||
bundle_type: emit::BundleType::Module,
|
||||
ts_config,
|
||||
emit_ignore_directives: true,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
@ -991,6 +1000,7 @@ async fn run_with_watch(flags: Flags, script: String) -> Result<i32, AnyError> {
|
|||
maybe_resolver,
|
||||
maybe_locker,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
let check_js = ps
|
||||
|
@ -1366,7 +1376,11 @@ fn unwrap_or_exit<T>(result: Result<T, AnyError>) -> T {
|
|||
match result {
|
||||
Ok(value) => value,
|
||||
Err(error) => {
|
||||
eprintln!("{}: {:?}", colors::red_bold("error"), error);
|
||||
eprintln!(
|
||||
"{}: {}",
|
||||
colors::red_bold("error"),
|
||||
format!("{:?}", error).trim_start_matches("error: ")
|
||||
);
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
|
@ -1394,11 +1408,10 @@ pub fn main() {
|
|||
let flags = match flags::flags_from_vec(args) {
|
||||
Ok(flags) => flags,
|
||||
Err(err @ clap::Error { .. })
|
||||
if err.kind == clap::ErrorKind::HelpDisplayed
|
||||
|| err.kind == clap::ErrorKind::VersionDisplayed =>
|
||||
if err.kind == clap::ErrorKind::DisplayHelp
|
||||
|| err.kind == clap::ErrorKind::DisplayVersion =>
|
||||
{
|
||||
err.write_to(&mut std::io::stdout()).unwrap();
|
||||
std::io::stdout().write_all(b"\n").unwrap();
|
||||
err.print().unwrap();
|
||||
std::process::exit(0);
|
||||
}
|
||||
Err(err) => unwrap_or_exit(Err(AnyError::from(err))),
|
||||
|
|
|
@ -7,6 +7,7 @@ use crate::emit;
|
|||
use crate::errors::get_error_class_name;
|
||||
use crate::flags;
|
||||
use crate::graph_util::graph_valid;
|
||||
use crate::proc_state::import_map_from_text;
|
||||
use crate::proc_state::ProcState;
|
||||
use crate::resolver::ImportMapResolver;
|
||||
use crate::resolver::JsxResolver;
|
||||
|
@ -24,7 +25,6 @@ use deno_core::Extension;
|
|||
use deno_core::ModuleSpecifier;
|
||||
use deno_core::OpState;
|
||||
use deno_runtime::permissions::Permissions;
|
||||
use import_map::ImportMap;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::cell::RefCell;
|
||||
|
@ -174,8 +174,8 @@ async fn op_emit(
|
|||
.with_context(|| {
|
||||
format!("Bad URL (\"{}\") for import map.", import_map_str)
|
||||
})?;
|
||||
let import_map = if let Some(value) = args.import_map {
|
||||
ImportMap::from_json(import_map_specifier.as_str(), &value.to_string())?
|
||||
let import_map_source = if let Some(value) = args.import_map {
|
||||
Arc::new(value.to_string())
|
||||
} else {
|
||||
let file = ps
|
||||
.file_fetcher
|
||||
|
@ -187,8 +187,10 @@ async fn op_emit(
|
|||
import_map_specifier, e
|
||||
))
|
||||
})?;
|
||||
ImportMap::from_json(import_map_specifier.as_str(), &file.source)?
|
||||
file.source
|
||||
};
|
||||
let import_map =
|
||||
import_map_from_text(&import_map_specifier, &import_map_source)?;
|
||||
Some(ImportMapResolver::new(Arc::new(import_map)))
|
||||
} else if args.import_map.is_some() {
|
||||
return Err(generic_error("An importMap was specified, but no importMapPath was provided, which is required."));
|
||||
|
@ -217,6 +219,7 @@ async fn op_emit(
|
|||
maybe_resolver,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await,
|
||||
);
|
||||
|
@ -285,6 +288,7 @@ async fn op_emit(
|
|||
emit::BundleOptions {
|
||||
bundle_type: bundle.into(),
|
||||
ts_config,
|
||||
emit_ignore_directives: true,
|
||||
},
|
||||
)?;
|
||||
let mut files = HashMap::new();
|
||||
|
|
|
@ -51,6 +51,7 @@ use deno_runtime::deno_web::BlobStore;
|
|||
use deno_runtime::inspector_server::InspectorServer;
|
||||
use deno_runtime::permissions::Permissions;
|
||||
use import_map::ImportMap;
|
||||
use log::warn;
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
|
@ -225,7 +226,7 @@ impl ProcState {
|
|||
import_map_specifier
|
||||
))?;
|
||||
let import_map =
|
||||
ImportMap::from_json(import_map_specifier.as_str(), &file.source)?;
|
||||
import_map_from_text(&import_map_specifier, &file.source)?;
|
||||
Some(Arc::new(import_map))
|
||||
}
|
||||
};
|
||||
|
@ -377,10 +378,9 @@ impl ProcState {
|
|||
let graph_data = self.graph_data.read();
|
||||
let found_specifier = graph_data.follow_redirect(specifier);
|
||||
match graph_data.get(&found_specifier) {
|
||||
Some(_) if !self.reload => Box::pin(futures::future::ready((
|
||||
specifier.clone(),
|
||||
Err(anyhow!("")),
|
||||
))),
|
||||
Some(_) if !self.reload => {
|
||||
Box::pin(futures::future::ready(Err(anyhow!(""))))
|
||||
}
|
||||
_ => self.inner.load(specifier, is_dynamic),
|
||||
}
|
||||
}
|
||||
|
@ -398,6 +398,7 @@ impl ProcState {
|
|||
maybe_resolver,
|
||||
maybe_locker,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
// If there was a locker, validate the integrity of all the modules in the
|
||||
|
@ -671,6 +672,25 @@ impl SourceMapGetter for ProcState {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn import_map_from_text(
|
||||
specifier: &Url,
|
||||
json_text: &str,
|
||||
) -> Result<ImportMap, AnyError> {
|
||||
let result = ImportMap::from_json_with_diagnostics(specifier, json_text)?;
|
||||
if !result.diagnostics.is_empty() {
|
||||
warn!(
|
||||
"Import map diagnostics:\n{}",
|
||||
result
|
||||
.diagnostics
|
||||
.into_iter()
|
||||
.map(|d| format!(" - {}", d))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n")
|
||||
)
|
||||
}
|
||||
Ok(result.import_map)
|
||||
}
|
||||
|
||||
fn source_map_from_code(code: String) -> Option<Vec<u8>> {
|
||||
let lines: Vec<&str> = code.split('\n').collect();
|
||||
if let Some(last_line) = lines.last() {
|
||||
|
|
|
@ -31,7 +31,7 @@ impl Resolver for ImportMapResolver {
|
|||
) -> Result<ModuleSpecifier, AnyError> {
|
||||
self
|
||||
.0
|
||||
.resolve(specifier, referrer.as_str())
|
||||
.resolve(specifier, referrer)
|
||||
.map_err(|err| err.into())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -442,3 +442,8 @@ itest!(bundle_export_specifier_with_alias {
|
|||
args: "bundle bundle/file_tests-fixture16.ts",
|
||||
output: "bundle/fixture16.out",
|
||||
});
|
||||
|
||||
itest!(bundle_ignore_directives {
|
||||
args: "bundle subdir/mod1.ts",
|
||||
output: "bundle_ignore_directives.test.out",
|
||||
});
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use std::fs::File;
|
||||
use std::process::Command;
|
||||
use tempfile::TempDir;
|
||||
use test_util as util;
|
||||
|
@ -129,7 +130,7 @@ fn standalone_error() {
|
|||
.unwrap();
|
||||
assert!(!output.status.success());
|
||||
assert_eq!(output.stdout, b"");
|
||||
let expected_stderr = "error: Error: boom!\n at boom (file://$deno$/bundle.js:2:11)\n at foo (file://$deno$/bundle.js:5:5)\n at file://$deno$/bundle.js:7:1\n";
|
||||
let expected_stderr = "error: Error: boom!\n at boom (file://$deno$/bundle.js:6:11)\n at foo (file://$deno$/bundle.js:9:5)\n at file://$deno$/bundle.js:11:1\n";
|
||||
let stderr = String::from_utf8(output.stderr).unwrap();
|
||||
assert_eq!(stderr, expected_stderr);
|
||||
}
|
||||
|
@ -233,6 +234,73 @@ fn standalone_compiler_ops() {
|
|||
assert_eq!(output.stdout, b"Hello, Compiler API!\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compile_with_directory_output_flag() {
|
||||
let dir = TempDir::new().expect("tempdir fail");
|
||||
let output_path = if cfg!(windows) {
|
||||
dir.path().join(r"args\random\")
|
||||
} else {
|
||||
dir.path().join("args/random/")
|
||||
};
|
||||
let output = util::deno_cmd()
|
||||
.current_dir(util::testdata_path())
|
||||
.arg("compile")
|
||||
.arg("--unstable")
|
||||
.arg("--output")
|
||||
.arg(&output_path)
|
||||
.arg("./standalone_compiler_ops.ts")
|
||||
.stdout(std::process::Stdio::piped())
|
||||
.spawn()
|
||||
.unwrap()
|
||||
.wait_with_output()
|
||||
.unwrap();
|
||||
assert!(output.status.success());
|
||||
let exe = if cfg!(windows) {
|
||||
output_path.join("standalone_compiler_ops.exe")
|
||||
} else {
|
||||
output_path.join("standalone_compiler_ops")
|
||||
};
|
||||
assert!(&exe.exists());
|
||||
let output = Command::new(exe)
|
||||
.stdout(std::process::Stdio::piped())
|
||||
.stderr(std::process::Stdio::piped())
|
||||
.spawn()
|
||||
.unwrap()
|
||||
.wait_with_output()
|
||||
.unwrap();
|
||||
assert!(output.status.success());
|
||||
assert_eq!(output.stdout, b"Hello, Compiler API!\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compile_with_file_exists_error() {
|
||||
let dir = TempDir::new().expect("tempdir fail");
|
||||
let output_path = if cfg!(windows) {
|
||||
dir.path().join(r"args\")
|
||||
} else {
|
||||
dir.path().join("args/")
|
||||
};
|
||||
let file_path = dir.path().join("args");
|
||||
File::create(&file_path).expect("cannot create file");
|
||||
let output = util::deno_cmd()
|
||||
.current_dir(util::testdata_path())
|
||||
.arg("compile")
|
||||
.arg("--unstable")
|
||||
.arg("--output")
|
||||
.arg(&output_path)
|
||||
.arg("./028_args.ts")
|
||||
.stderr(std::process::Stdio::piped())
|
||||
.spawn()
|
||||
.unwrap()
|
||||
.wait_with_output()
|
||||
.unwrap();
|
||||
assert!(!output.status.success());
|
||||
let expected_stderr =
|
||||
format!("Could not compile: {:?} is a file.\n", &file_path);
|
||||
let stderr = String::from_utf8(output.stderr).unwrap();
|
||||
assert!(stderr.contains(&expected_stderr));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn compile_with_directory_exists_error() {
|
||||
let dir = TempDir::new().expect("tempdir fail");
|
||||
|
|
|
@ -97,3 +97,83 @@ fn run_coverage_text(test_name: &str, extension: &str) {
|
|||
|
||||
assert!(output.status.success());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multifile_coverage() {
|
||||
let deno_dir = TempDir::new().expect("tempdir fail");
|
||||
let tempdir = TempDir::new().expect("tempdir fail");
|
||||
let tempdir = tempdir.path().join("cov");
|
||||
|
||||
let status = util::deno_cmd_with_deno_dir(deno_dir.path())
|
||||
.current_dir(util::testdata_path())
|
||||
.arg("test")
|
||||
.arg("--quiet")
|
||||
.arg("--unstable")
|
||||
.arg(format!("--coverage={}", tempdir.to_str().unwrap()))
|
||||
.arg("coverage/multifile/")
|
||||
.stdout(std::process::Stdio::piped())
|
||||
.stderr(std::process::Stdio::inherit())
|
||||
.status()
|
||||
.expect("failed to spawn test runner");
|
||||
|
||||
assert!(status.success());
|
||||
|
||||
let output = util::deno_cmd_with_deno_dir(deno_dir.path())
|
||||
.current_dir(util::testdata_path())
|
||||
.arg("coverage")
|
||||
.arg("--unstable")
|
||||
.arg(format!("{}/", tempdir.to_str().unwrap()))
|
||||
.stdout(std::process::Stdio::piped())
|
||||
.stderr(std::process::Stdio::piped())
|
||||
.output()
|
||||
.expect("failed to spawn coverage reporter");
|
||||
|
||||
// Verify there's no "Check" being printed
|
||||
assert!(output.stderr.is_empty());
|
||||
|
||||
let actual =
|
||||
util::strip_ansi_codes(std::str::from_utf8(&output.stdout).unwrap())
|
||||
.to_string();
|
||||
|
||||
let expected = fs::read_to_string(
|
||||
util::testdata_path().join("coverage/multifile/expected.out"),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
if !util::wildcard_match(&expected, &actual) {
|
||||
println!("OUTPUT\n{}\nOUTPUT", actual);
|
||||
println!("EXPECTED\n{}\nEXPECTED", expected);
|
||||
panic!("pattern match failed");
|
||||
}
|
||||
|
||||
assert!(output.status.success());
|
||||
|
||||
let output = util::deno_cmd_with_deno_dir(deno_dir.path())
|
||||
.current_dir(util::testdata_path())
|
||||
.arg("coverage")
|
||||
.arg("--quiet")
|
||||
.arg("--unstable")
|
||||
.arg("--lcov")
|
||||
.arg(format!("{}/", tempdir.to_str().unwrap()))
|
||||
.stdout(std::process::Stdio::piped())
|
||||
.stderr(std::process::Stdio::inherit())
|
||||
.output()
|
||||
.expect("failed to spawn coverage reporter");
|
||||
|
||||
let actual =
|
||||
util::strip_ansi_codes(std::str::from_utf8(&output.stdout).unwrap())
|
||||
.to_string();
|
||||
|
||||
let expected = fs::read_to_string(
|
||||
util::testdata_path().join("coverage/multifile/expected.lcov"),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
if !util::wildcard_match(&expected, &actual) {
|
||||
println!("OUTPUT\n{}\nOUTPUT", actual);
|
||||
println!("EXPECTED\n{}\nEXPECTED", expected);
|
||||
panic!("pattern match failed");
|
||||
}
|
||||
|
||||
assert!(output.status.success());
|
||||
}
|
||||
|
|
|
@ -1087,6 +1087,34 @@ fn typecheck_declarations_unstable() {
|
|||
assert!(output.status.success());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn typecheck_core() {
|
||||
let deno_dir = TempDir::new().expect("tempdir fail");
|
||||
let test_file = deno_dir.path().join("test_deno_core_types.ts");
|
||||
std::fs::write(
|
||||
&test_file,
|
||||
format!(
|
||||
"import \"{}\";",
|
||||
deno_core::resolve_path(
|
||||
util::root_path()
|
||||
.join("core/lib.deno_core.d.ts")
|
||||
.to_str()
|
||||
.unwrap()
|
||||
)
|
||||
.unwrap()
|
||||
),
|
||||
)
|
||||
.unwrap();
|
||||
let output = util::deno_cmd_with_deno_dir(deno_dir.path())
|
||||
.arg("run")
|
||||
.arg(test_file.to_str().unwrap())
|
||||
.output()
|
||||
.unwrap();
|
||||
println!("stdout: {}", String::from_utf8(output.stdout).unwrap());
|
||||
println!("stderr: {}", String::from_utf8(output.stderr).unwrap());
|
||||
assert!(output.status.success());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn js_unit_tests_lint() {
|
||||
let status = util::deno_cmd()
|
||||
|
|
6
cli/tests/testdata/bundle_ignore_directives.test.out
vendored
Normal file
6
cli/tests/testdata/bundle_ignore_directives.test.out
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
[WILDCARD]
|
||||
// deno-fmt-ignore-file
|
||||
// deno-lint-ignore-file
|
||||
// This code was bundled using `deno bundle` and it's not recommended to edit it manually
|
||||
|
||||
[WILDCARD]
|
2
cli/tests/testdata/compat/import_map.json
vendored
2
cli/tests/testdata/compat/import_map.json
vendored
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"imports": {
|
||||
"std/": "https://deno.land/std@0.120.0/"
|
||||
"std/": "https://deno.land/std@0.121.0/"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { sortBy } from "std/collections/sort_by.ts";
|
||||
import { findSingle } from "https://deno.land/std@0.120.0/collections/find_single.ts";
|
||||
import { findSingle } from "https://deno.land/std@0.121.0/collections/find_single.ts";
|
||||
import os from "node:os";
|
||||
|
||||
console.log(sortBy([2, 3, 1], (it) => it));
|
||||
|
|
13
cli/tests/testdata/compiler_api_test.ts
vendored
13
cli/tests/testdata/compiler_api_test.ts
vendored
|
@ -418,10 +418,21 @@ Deno.test({
|
|||
"/b.ts": `export const b = "b";`,
|
||||
},
|
||||
});
|
||||
const ignoreDirecives = [
|
||||
"// deno-fmt-ignore-file",
|
||||
"// deno-lint-ignore-file",
|
||||
"// This code was bundled using `deno bundle` and it's not recommended to edit it manually",
|
||||
"",
|
||||
"",
|
||||
].join("\n");
|
||||
assert(diagnostics);
|
||||
assertEquals(diagnostics.length, 0);
|
||||
assertEquals(Object.keys(files).length, 2);
|
||||
assert(files["deno:///bundle.js"].startsWith("(function() {\n"));
|
||||
assert(
|
||||
files["deno:///bundle.js"].startsWith(
|
||||
ignoreDirecives + "(function() {\n",
|
||||
),
|
||||
);
|
||||
assert(files["deno:///bundle.js"].endsWith("})();\n"));
|
||||
assert(files["deno:///bundle.js.map"]);
|
||||
},
|
||||
|
|
8
cli/tests/testdata/coverage/multifile/a_test.js
vendored
Normal file
8
cli/tests/testdata/coverage/multifile/a_test.js
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
import { test } from "./mod.js";
|
||||
|
||||
Deno.test({
|
||||
name: "bugrepo a",
|
||||
fn: () => {
|
||||
test(true);
|
||||
},
|
||||
});
|
8
cli/tests/testdata/coverage/multifile/b_test.js
vendored
Normal file
8
cli/tests/testdata/coverage/multifile/b_test.js
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
import { test } from "./mod.js";
|
||||
|
||||
Deno.test({
|
||||
name: "bugrepo b",
|
||||
fn: () => {
|
||||
test(false);
|
||||
},
|
||||
});
|
18
cli/tests/testdata/coverage/multifile/expected.lcov
vendored
Normal file
18
cli/tests/testdata/coverage/multifile/expected.lcov
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
SF:[WILDCARD]mod.js
|
||||
FN:1,test
|
||||
FNDA:2,test
|
||||
FNF:1
|
||||
FNH:1
|
||||
BRDA:2,1,0,1
|
||||
BRF:1
|
||||
BRH:1
|
||||
DA:1,2
|
||||
DA:2,4
|
||||
DA:3,5
|
||||
DA:4,5
|
||||
DA:5,5
|
||||
DA:6,4
|
||||
DA:7,1
|
||||
LH:7
|
||||
LF:7
|
||||
end_of_record
|
1
cli/tests/testdata/coverage/multifile/expected.out
vendored
Normal file
1
cli/tests/testdata/coverage/multifile/expected.out
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
cover [WILDCARD]/multifile/mod.js ... 100.000% (7/7)
|
6
cli/tests/testdata/coverage/multifile/mod.js
vendored
Normal file
6
cli/tests/testdata/coverage/multifile/mod.js
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
export function test(a) {
|
||||
if (a) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
|
@ -1444,6 +1444,15 @@ Deno.test(async function testAesGcmEncrypt() {
|
|||
// deno-fmt-ignore
|
||||
new Uint8Array([50,223,112,178,166,156,255,110,125,138,95,141,82,47,14,164,134,247,22]),
|
||||
);
|
||||
|
||||
const plainText = await crypto.subtle.decrypt(
|
||||
{ name: "AES-GCM", iv, additionalData: new Uint8Array() },
|
||||
key,
|
||||
cipherText,
|
||||
);
|
||||
assert(plainText instanceof ArrayBuffer);
|
||||
assertEquals(plainText.byteLength, 3);
|
||||
assertEquals(new Uint8Array(plainText), data);
|
||||
});
|
||||
|
||||
async function roundTripSecretJwk(
|
||||
|
@ -1561,3 +1570,61 @@ Deno.test(async function testSecretJwkBase64Url() {
|
|||
},
|
||||
);
|
||||
});
|
||||
|
||||
Deno.test(async function testAESWrapKey() {
|
||||
const key = await crypto.subtle.generateKey(
|
||||
{
|
||||
name: "AES-KW",
|
||||
length: 128,
|
||||
},
|
||||
true,
|
||||
["wrapKey", "unwrapKey"],
|
||||
);
|
||||
|
||||
const hmacKey = await crypto.subtle.generateKey(
|
||||
{
|
||||
name: "HMAC",
|
||||
hash: "SHA-256",
|
||||
length: 128,
|
||||
},
|
||||
true,
|
||||
["sign"],
|
||||
);
|
||||
|
||||
//round-trip
|
||||
// wrap-unwrap-export compare
|
||||
const wrappedKey = await crypto.subtle.wrapKey(
|
||||
"raw",
|
||||
hmacKey,
|
||||
key,
|
||||
{
|
||||
name: "AES-KW",
|
||||
},
|
||||
);
|
||||
|
||||
assert(wrappedKey instanceof ArrayBuffer);
|
||||
assertEquals(wrappedKey.byteLength, 16 + 8); // 8 = 'auth tag'
|
||||
|
||||
const unwrappedKey = await crypto.subtle.unwrapKey(
|
||||
"raw",
|
||||
wrappedKey,
|
||||
key,
|
||||
{
|
||||
name: "AES-KW",
|
||||
},
|
||||
{
|
||||
name: "HMAC",
|
||||
hash: "SHA-256",
|
||||
},
|
||||
true,
|
||||
["sign"],
|
||||
);
|
||||
|
||||
assert(unwrappedKey instanceof CryptoKey);
|
||||
assertEquals((unwrappedKey.algorithm as HmacKeyAlgorithm).length, 128);
|
||||
|
||||
const hmacKeyBytes = await crypto.subtle.exportKey("raw", hmacKey);
|
||||
const unwrappedKeyBytes = await crypto.subtle.exportKey("raw", unwrappedKey);
|
||||
|
||||
assertEquals(new Uint8Array(hmacKeyBytes), new Uint8Array(unwrappedKeyBytes));
|
||||
});
|
||||
|
|
58
cli/tools/coverage/json_types.rs
Normal file
58
cli/tools/coverage/json_types.rs
Normal file
|
@ -0,0 +1,58 @@
|
|||
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CoverageRange {
|
||||
/// Start byte index.
|
||||
pub start_offset: usize,
|
||||
/// End byte index.
|
||||
pub end_offset: usize,
|
||||
pub count: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FunctionCoverage {
|
||||
pub function_name: String,
|
||||
pub ranges: Vec<CoverageRange>,
|
||||
pub is_block_coverage: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Serialize, Deserialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ScriptCoverage {
|
||||
pub script_id: String,
|
||||
pub url: String,
|
||||
pub functions: Vec<FunctionCoverage>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct StartPreciseCoverageParameters {
|
||||
pub call_count: bool,
|
||||
pub detailed: bool,
|
||||
pub allow_triggered_updates: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct StartPreciseCoverageReturnObject {
|
||||
pub timestamp: f64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct TakePreciseCoverageReturnObject {
|
||||
pub result: Vec<ScriptCoverage>,
|
||||
pub timestamp: f64,
|
||||
}
|
||||
|
||||
// TODO(bartlomieju): remove me
|
||||
#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ProcessCoverage {
|
||||
pub result: Vec<ScriptCoverage>,
|
||||
}
|
840
cli/tools/coverage/merge.rs
Normal file
840
cli/tools/coverage/merge.rs
Normal file
|
@ -0,0 +1,840 @@
|
|||
// Forked from https://github.com/demurgos/v8-coverage/tree/d0ca18da8740198681e0bc68971b0a6cdb11db3e/rust
|
||||
// Copyright 2021 Charles Samborski. All rights reserved. MIT license.
|
||||
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use super::json_types::CoverageRange;
|
||||
use super::json_types::FunctionCoverage;
|
||||
use super::json_types::ProcessCoverage;
|
||||
use super::json_types::ScriptCoverage;
|
||||
use super::range_tree::RangeTree;
|
||||
use super::range_tree::RangeTreeArena;
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::BTreeSet;
|
||||
use std::collections::HashMap;
|
||||
use std::iter::Peekable;
|
||||
|
||||
pub fn merge_processes(
|
||||
mut processes: Vec<ProcessCoverage>,
|
||||
) -> Option<ProcessCoverage> {
|
||||
if processes.len() <= 1 {
|
||||
return processes.pop();
|
||||
}
|
||||
let mut url_to_scripts: BTreeMap<String, Vec<ScriptCoverage>> =
|
||||
BTreeMap::new();
|
||||
for process_cov in processes {
|
||||
for script_cov in process_cov.result {
|
||||
url_to_scripts
|
||||
.entry(script_cov.url.clone())
|
||||
.or_insert_with(Vec::new)
|
||||
.push(script_cov);
|
||||
}
|
||||
}
|
||||
|
||||
let result: Vec<ScriptCoverage> = url_to_scripts
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(script_id, (_, scripts))| (script_id, scripts))
|
||||
.map(|(script_id, scripts)| {
|
||||
let mut merged: ScriptCoverage = merge_scripts(scripts.to_vec()).unwrap();
|
||||
merged.script_id = script_id.to_string();
|
||||
merged
|
||||
})
|
||||
.collect();
|
||||
|
||||
Some(ProcessCoverage { result })
|
||||
}
|
||||
|
||||
pub fn merge_scripts(
|
||||
mut scripts: Vec<ScriptCoverage>,
|
||||
) -> Option<ScriptCoverage> {
|
||||
if scripts.len() <= 1 {
|
||||
return scripts.pop();
|
||||
}
|
||||
let (script_id, url) = {
|
||||
let first: &ScriptCoverage = &scripts[0];
|
||||
(first.script_id.clone(), first.url.clone())
|
||||
};
|
||||
let mut range_to_funcs: BTreeMap<Range, Vec<FunctionCoverage>> =
|
||||
BTreeMap::new();
|
||||
for script_cov in scripts {
|
||||
for func_cov in script_cov.functions {
|
||||
let root_range = {
|
||||
let root_range_cov: &CoverageRange = &func_cov.ranges[0];
|
||||
Range {
|
||||
start: root_range_cov.start_offset,
|
||||
end: root_range_cov.end_offset,
|
||||
}
|
||||
};
|
||||
range_to_funcs
|
||||
.entry(root_range)
|
||||
.or_insert_with(Vec::new)
|
||||
.push(func_cov);
|
||||
}
|
||||
}
|
||||
|
||||
let functions: Vec<FunctionCoverage> = range_to_funcs
|
||||
.into_iter()
|
||||
.map(|(_, funcs)| merge_functions(funcs).unwrap())
|
||||
.collect();
|
||||
|
||||
Some(ScriptCoverage {
|
||||
script_id,
|
||||
url,
|
||||
functions,
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)]
|
||||
struct Range {
|
||||
start: usize,
|
||||
end: usize,
|
||||
}
|
||||
|
||||
impl Ord for Range {
|
||||
fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
|
||||
if self.start != other.start {
|
||||
self.start.cmp(&other.start)
|
||||
} else {
|
||||
other.end.cmp(&self.end)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Range {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<::std::cmp::Ordering> {
|
||||
if self.start != other.start {
|
||||
self.start.partial_cmp(&other.start)
|
||||
} else {
|
||||
other.end.partial_cmp(&self.end)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn merge_functions(
|
||||
mut funcs: Vec<FunctionCoverage>,
|
||||
) -> Option<FunctionCoverage> {
|
||||
if funcs.len() <= 1 {
|
||||
return funcs.pop();
|
||||
}
|
||||
let function_name = funcs[0].function_name.clone();
|
||||
let rta_capacity: usize =
|
||||
funcs.iter().fold(0, |acc, func| acc + func.ranges.len());
|
||||
let rta = RangeTreeArena::with_capacity(rta_capacity);
|
||||
let mut trees: Vec<&mut RangeTree> = Vec::new();
|
||||
for func in funcs {
|
||||
if let Some(tree) = RangeTree::from_sorted_ranges(&rta, &func.ranges) {
|
||||
trees.push(tree);
|
||||
}
|
||||
}
|
||||
let merged =
|
||||
RangeTree::normalize(&rta, merge_range_trees(&rta, trees).unwrap());
|
||||
let ranges = merged.to_ranges();
|
||||
let is_block_coverage: bool = !(ranges.len() == 1 && ranges[0].count == 0);
|
||||
|
||||
Some(FunctionCoverage {
|
||||
function_name,
|
||||
ranges,
|
||||
is_block_coverage,
|
||||
})
|
||||
}
|
||||
|
||||
fn merge_range_trees<'a>(
|
||||
rta: &'a RangeTreeArena<'a>,
|
||||
mut trees: Vec<&'a mut RangeTree<'a>>,
|
||||
) -> Option<&'a mut RangeTree<'a>> {
|
||||
if trees.len() <= 1 {
|
||||
return trees.pop();
|
||||
}
|
||||
let (start, end) = {
|
||||
let first = &trees[0];
|
||||
(first.start, first.end)
|
||||
};
|
||||
let delta: i64 = trees.iter().fold(0, |acc, tree| acc + tree.delta);
|
||||
let children = merge_range_tree_children(rta, trees);
|
||||
|
||||
Some(rta.alloc(RangeTree::new(start, end, delta, children)))
|
||||
}
|
||||
|
||||
struct StartEvent<'a> {
|
||||
offset: usize,
|
||||
trees: Vec<(usize, &'a mut RangeTree<'a>)>,
|
||||
}
|
||||
|
||||
fn into_start_events<'a>(trees: Vec<&'a mut RangeTree<'a>>) -> Vec<StartEvent> {
|
||||
let mut result: BTreeMap<usize, Vec<(usize, &'a mut RangeTree<'a>)>> =
|
||||
BTreeMap::new();
|
||||
for (parent_index, tree) in trees.into_iter().enumerate() {
|
||||
for child in tree.children.drain(..) {
|
||||
result
|
||||
.entry(child.start)
|
||||
.or_insert_with(Vec::new)
|
||||
.push((parent_index, child));
|
||||
}
|
||||
}
|
||||
result
|
||||
.into_iter()
|
||||
.map(|(offset, trees)| StartEvent { offset, trees })
|
||||
.collect()
|
||||
}
|
||||
|
||||
struct StartEventQueue<'a> {
|
||||
pending: Option<StartEvent<'a>>,
|
||||
queue: Peekable<::std::vec::IntoIter<StartEvent<'a>>>,
|
||||
}
|
||||
|
||||
impl<'a> StartEventQueue<'a> {
|
||||
pub fn new(queue: Vec<StartEvent<'a>>) -> StartEventQueue<'a> {
|
||||
StartEventQueue {
|
||||
pending: None,
|
||||
queue: queue.into_iter().peekable(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn set_pending_offset(&mut self, offset: usize) {
|
||||
self.pending = Some(StartEvent {
|
||||
offset,
|
||||
trees: Vec::new(),
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn push_pending_tree(
|
||||
&mut self,
|
||||
tree: (usize, &'a mut RangeTree<'a>),
|
||||
) {
|
||||
self.pending = self.pending.take().map(|mut start_event| {
|
||||
start_event.trees.push(tree);
|
||||
start_event
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for StartEventQueue<'a> {
|
||||
type Item = StartEvent<'a>;
|
||||
|
||||
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
|
||||
let pending_offset: Option<usize> = match &self.pending {
|
||||
Some(ref start_event) if !start_event.trees.is_empty() => {
|
||||
Some(start_event.offset)
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
match pending_offset {
|
||||
Some(pending_offset) => {
|
||||
let queue_offset =
|
||||
self.queue.peek().map(|start_event| start_event.offset);
|
||||
match queue_offset {
|
||||
None => self.pending.take(),
|
||||
Some(queue_offset) => {
|
||||
if pending_offset < queue_offset {
|
||||
self.pending.take()
|
||||
} else {
|
||||
let mut result = self.queue.next().unwrap();
|
||||
if pending_offset == queue_offset {
|
||||
let pending_trees = self.pending.take().unwrap().trees;
|
||||
result.trees.extend(pending_trees.into_iter())
|
||||
}
|
||||
Some(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None => self.queue.next(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn merge_range_tree_children<'a>(
|
||||
rta: &'a RangeTreeArena<'a>,
|
||||
parent_trees: Vec<&'a mut RangeTree<'a>>,
|
||||
) -> Vec<&'a mut RangeTree<'a>> {
|
||||
let mut flat_children: Vec<Vec<&'a mut RangeTree<'a>>> =
|
||||
Vec::with_capacity(parent_trees.len());
|
||||
let mut wrapped_children: Vec<Vec<&'a mut RangeTree<'a>>> =
|
||||
Vec::with_capacity(parent_trees.len());
|
||||
let mut open_range: Option<Range> = None;
|
||||
|
||||
for _parent_tree in parent_trees.iter() {
|
||||
flat_children.push(Vec::new());
|
||||
wrapped_children.push(Vec::new());
|
||||
}
|
||||
|
||||
let mut start_event_queue =
|
||||
StartEventQueue::new(into_start_events(parent_trees));
|
||||
|
||||
let mut parent_to_nested: HashMap<usize, Vec<&'a mut RangeTree<'a>>> =
|
||||
HashMap::new();
|
||||
|
||||
while let Some(event) = start_event_queue.next() {
|
||||
open_range = if let Some(open_range) = open_range {
|
||||
if open_range.end <= event.offset {
|
||||
for (parent_index, nested) in parent_to_nested {
|
||||
wrapped_children[parent_index].push(rta.alloc(RangeTree::new(
|
||||
open_range.start,
|
||||
open_range.end,
|
||||
0,
|
||||
nested,
|
||||
)));
|
||||
}
|
||||
parent_to_nested = HashMap::new();
|
||||
None
|
||||
} else {
|
||||
Some(open_range)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
match open_range {
|
||||
Some(open_range) => {
|
||||
for (parent_index, tree) in event.trees {
|
||||
let child = if tree.end > open_range.end {
|
||||
let (left, right) = RangeTree::split(rta, tree, open_range.end);
|
||||
start_event_queue.push_pending_tree((parent_index, right));
|
||||
left
|
||||
} else {
|
||||
tree
|
||||
};
|
||||
parent_to_nested
|
||||
.entry(parent_index)
|
||||
.or_insert_with(Vec::new)
|
||||
.push(child);
|
||||
}
|
||||
}
|
||||
None => {
|
||||
let mut open_range_end: usize = event.offset + 1;
|
||||
for (_, ref tree) in &event.trees {
|
||||
open_range_end = if tree.end > open_range_end {
|
||||
tree.end
|
||||
} else {
|
||||
open_range_end
|
||||
};
|
||||
}
|
||||
for (parent_index, tree) in event.trees {
|
||||
if tree.end == open_range_end {
|
||||
flat_children[parent_index].push(tree);
|
||||
continue;
|
||||
}
|
||||
parent_to_nested
|
||||
.entry(parent_index)
|
||||
.or_insert_with(Vec::new)
|
||||
.push(tree);
|
||||
}
|
||||
start_event_queue.set_pending_offset(open_range_end);
|
||||
open_range = Some(Range {
|
||||
start: event.offset,
|
||||
end: open_range_end,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(open_range) = open_range {
|
||||
for (parent_index, nested) in parent_to_nested {
|
||||
wrapped_children[parent_index].push(rta.alloc(RangeTree::new(
|
||||
open_range.start,
|
||||
open_range.end,
|
||||
0,
|
||||
nested,
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
let child_forests: Vec<Vec<&'a mut RangeTree<'a>>> = flat_children
|
||||
.into_iter()
|
||||
.zip(wrapped_children.into_iter())
|
||||
.map(|(flat, wrapped)| merge_children_lists(flat, wrapped))
|
||||
.collect();
|
||||
|
||||
let events = get_child_events_from_forests(&child_forests);
|
||||
|
||||
let mut child_forests: Vec<
|
||||
Peekable<::std::vec::IntoIter<&'a mut RangeTree<'a>>>,
|
||||
> = child_forests
|
||||
.into_iter()
|
||||
.map(|forest| forest.into_iter().peekable())
|
||||
.collect();
|
||||
|
||||
let mut result: Vec<&'a mut RangeTree<'a>> = Vec::new();
|
||||
for event in events.iter() {
|
||||
let mut matching_trees: Vec<&'a mut RangeTree<'a>> = Vec::new();
|
||||
for (_parent_index, children) in child_forests.iter_mut().enumerate() {
|
||||
let next_tree: Option<&'a mut RangeTree<'a>> = {
|
||||
if children.peek().map_or(false, |tree| tree.start == *event) {
|
||||
children.next()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
};
|
||||
if let Some(next_tree) = next_tree {
|
||||
matching_trees.push(next_tree);
|
||||
}
|
||||
}
|
||||
if let Some(merged) = merge_range_trees(rta, matching_trees) {
|
||||
result.push(merged);
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn get_child_events_from_forests<'a>(
|
||||
forests: &[Vec<&'a mut RangeTree<'a>>],
|
||||
) -> BTreeSet<usize> {
|
||||
let mut event_set: BTreeSet<usize> = BTreeSet::new();
|
||||
for forest in forests {
|
||||
for tree in forest {
|
||||
event_set.insert(tree.start);
|
||||
event_set.insert(tree.end);
|
||||
}
|
||||
}
|
||||
event_set
|
||||
}
|
||||
|
||||
// TODO: itertools?
|
||||
// https://play.integer32.com/?gist=ad2cd20d628e647a5dbdd82e68a15cb6&version=stable&mode=debug&edition=2015
|
||||
fn merge_children_lists<'a>(
|
||||
a: Vec<&'a mut RangeTree<'a>>,
|
||||
b: Vec<&'a mut RangeTree<'a>>,
|
||||
) -> Vec<&'a mut RangeTree<'a>> {
|
||||
let mut merged: Vec<&'a mut RangeTree<'a>> = Vec::new();
|
||||
let mut a = a.into_iter();
|
||||
let mut b = b.into_iter();
|
||||
let mut next_a = a.next();
|
||||
let mut next_b = b.next();
|
||||
loop {
|
||||
match (next_a, next_b) {
|
||||
(Some(tree_a), Some(tree_b)) => {
|
||||
if tree_a.start < tree_b.start {
|
||||
merged.push(tree_a);
|
||||
next_a = a.next();
|
||||
next_b = Some(tree_b);
|
||||
} else {
|
||||
merged.push(tree_b);
|
||||
next_a = Some(tree_a);
|
||||
next_b = b.next();
|
||||
}
|
||||
}
|
||||
(Some(tree_a), None) => {
|
||||
merged.push(tree_a);
|
||||
merged.extend(a);
|
||||
break;
|
||||
}
|
||||
(None, Some(tree_b)) => {
|
||||
merged.push(tree_b);
|
||||
merged.extend(b);
|
||||
break;
|
||||
}
|
||||
(None, None) => break,
|
||||
}
|
||||
}
|
||||
|
||||
merged
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
// use test_generator::test_resources;
|
||||
|
||||
#[test]
|
||||
fn empty() {
|
||||
let inputs: Vec<ProcessCoverage> = Vec::new();
|
||||
let expected: Option<ProcessCoverage> = None;
|
||||
|
||||
assert_eq!(merge_processes(inputs), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn two_flat_trees() {
|
||||
let inputs: Vec<ProcessCoverage> = vec![
|
||||
ProcessCoverage {
|
||||
result: vec![ScriptCoverage {
|
||||
script_id: String::from("0"),
|
||||
url: String::from("/lib.js"),
|
||||
functions: vec![FunctionCoverage {
|
||||
function_name: String::from("lib"),
|
||||
is_block_coverage: true,
|
||||
ranges: vec![CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 9,
|
||||
count: 1,
|
||||
}],
|
||||
}],
|
||||
}],
|
||||
},
|
||||
ProcessCoverage {
|
||||
result: vec![ScriptCoverage {
|
||||
script_id: String::from("0"),
|
||||
url: String::from("/lib.js"),
|
||||
functions: vec![FunctionCoverage {
|
||||
function_name: String::from("lib"),
|
||||
is_block_coverage: true,
|
||||
ranges: vec![CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 9,
|
||||
count: 2,
|
||||
}],
|
||||
}],
|
||||
}],
|
||||
},
|
||||
];
|
||||
let expected: Option<ProcessCoverage> = Some(ProcessCoverage {
|
||||
result: vec![ScriptCoverage {
|
||||
script_id: String::from("0"),
|
||||
url: String::from("/lib.js"),
|
||||
functions: vec![FunctionCoverage {
|
||||
function_name: String::from("lib"),
|
||||
is_block_coverage: true,
|
||||
ranges: vec![CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 9,
|
||||
count: 3,
|
||||
}],
|
||||
}],
|
||||
}],
|
||||
});
|
||||
|
||||
assert_eq!(merge_processes(inputs), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn two_trees_with_matching_children() {
|
||||
let inputs: Vec<ProcessCoverage> = vec![
|
||||
ProcessCoverage {
|
||||
result: vec![ScriptCoverage {
|
||||
script_id: String::from("0"),
|
||||
url: String::from("/lib.js"),
|
||||
functions: vec![FunctionCoverage {
|
||||
function_name: String::from("lib"),
|
||||
is_block_coverage: true,
|
||||
ranges: vec![
|
||||
CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 9,
|
||||
count: 10,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 3,
|
||||
end_offset: 6,
|
||||
count: 1,
|
||||
},
|
||||
],
|
||||
}],
|
||||
}],
|
||||
},
|
||||
ProcessCoverage {
|
||||
result: vec![ScriptCoverage {
|
||||
script_id: String::from("0"),
|
||||
url: String::from("/lib.js"),
|
||||
functions: vec![FunctionCoverage {
|
||||
function_name: String::from("lib"),
|
||||
is_block_coverage: true,
|
||||
ranges: vec![
|
||||
CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 9,
|
||||
count: 20,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 3,
|
||||
end_offset: 6,
|
||||
count: 2,
|
||||
},
|
||||
],
|
||||
}],
|
||||
}],
|
||||
},
|
||||
];
|
||||
let expected: Option<ProcessCoverage> = Some(ProcessCoverage {
|
||||
result: vec![ScriptCoverage {
|
||||
script_id: String::from("0"),
|
||||
url: String::from("/lib.js"),
|
||||
functions: vec![FunctionCoverage {
|
||||
function_name: String::from("lib"),
|
||||
is_block_coverage: true,
|
||||
ranges: vec![
|
||||
CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 9,
|
||||
count: 30,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 3,
|
||||
end_offset: 6,
|
||||
count: 3,
|
||||
},
|
||||
],
|
||||
}],
|
||||
}],
|
||||
});
|
||||
|
||||
assert_eq!(merge_processes(inputs), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn two_trees_with_partially_overlapping_children() {
|
||||
let inputs: Vec<ProcessCoverage> = vec![
|
||||
ProcessCoverage {
|
||||
result: vec![ScriptCoverage {
|
||||
script_id: String::from("0"),
|
||||
url: String::from("/lib.js"),
|
||||
functions: vec![FunctionCoverage {
|
||||
function_name: String::from("lib"),
|
||||
is_block_coverage: true,
|
||||
ranges: vec![
|
||||
CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 9,
|
||||
count: 10,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 2,
|
||||
end_offset: 5,
|
||||
count: 1,
|
||||
},
|
||||
],
|
||||
}],
|
||||
}],
|
||||
},
|
||||
ProcessCoverage {
|
||||
result: vec![ScriptCoverage {
|
||||
script_id: String::from("0"),
|
||||
url: String::from("/lib.js"),
|
||||
functions: vec![FunctionCoverage {
|
||||
function_name: String::from("lib"),
|
||||
is_block_coverage: true,
|
||||
ranges: vec![
|
||||
CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 9,
|
||||
count: 20,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 4,
|
||||
end_offset: 7,
|
||||
count: 2,
|
||||
},
|
||||
],
|
||||
}],
|
||||
}],
|
||||
},
|
||||
];
|
||||
let expected: Option<ProcessCoverage> = Some(ProcessCoverage {
|
||||
result: vec![ScriptCoverage {
|
||||
script_id: String::from("0"),
|
||||
url: String::from("/lib.js"),
|
||||
functions: vec![FunctionCoverage {
|
||||
function_name: String::from("lib"),
|
||||
is_block_coverage: true,
|
||||
ranges: vec![
|
||||
CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 9,
|
||||
count: 30,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 2,
|
||||
end_offset: 5,
|
||||
count: 21,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 4,
|
||||
end_offset: 5,
|
||||
count: 3,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 5,
|
||||
end_offset: 7,
|
||||
count: 12,
|
||||
},
|
||||
],
|
||||
}],
|
||||
}],
|
||||
});
|
||||
|
||||
assert_eq!(merge_processes(inputs), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn two_trees_with_with_complementary_children_summing_to_the_same_count() {
|
||||
let inputs: Vec<ProcessCoverage> = vec![
|
||||
ProcessCoverage {
|
||||
result: vec![ScriptCoverage {
|
||||
script_id: String::from("0"),
|
||||
url: String::from("/lib.js"),
|
||||
functions: vec![FunctionCoverage {
|
||||
function_name: String::from("lib"),
|
||||
is_block_coverage: true,
|
||||
ranges: vec![
|
||||
CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 9,
|
||||
count: 1,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 1,
|
||||
end_offset: 8,
|
||||
count: 6,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 1,
|
||||
end_offset: 5,
|
||||
count: 5,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 5,
|
||||
end_offset: 8,
|
||||
count: 7,
|
||||
},
|
||||
],
|
||||
}],
|
||||
}],
|
||||
},
|
||||
ProcessCoverage {
|
||||
result: vec![ScriptCoverage {
|
||||
script_id: String::from("0"),
|
||||
url: String::from("/lib.js"),
|
||||
functions: vec![FunctionCoverage {
|
||||
function_name: String::from("lib"),
|
||||
is_block_coverage: true,
|
||||
ranges: vec![
|
||||
CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 9,
|
||||
count: 4,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 1,
|
||||
end_offset: 8,
|
||||
count: 8,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 1,
|
||||
end_offset: 5,
|
||||
count: 9,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 5,
|
||||
end_offset: 8,
|
||||
count: 7,
|
||||
},
|
||||
],
|
||||
}],
|
||||
}],
|
||||
},
|
||||
];
|
||||
let expected: Option<ProcessCoverage> = Some(ProcessCoverage {
|
||||
result: vec![ScriptCoverage {
|
||||
script_id: String::from("0"),
|
||||
url: String::from("/lib.js"),
|
||||
functions: vec![FunctionCoverage {
|
||||
function_name: String::from("lib"),
|
||||
is_block_coverage: true,
|
||||
ranges: vec![
|
||||
CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 9,
|
||||
count: 5,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 1,
|
||||
end_offset: 8,
|
||||
count: 14,
|
||||
},
|
||||
],
|
||||
}],
|
||||
}],
|
||||
});
|
||||
|
||||
assert_eq!(merge_processes(inputs), expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merges_a_similar_sliding_chain_a_bc() {
|
||||
let inputs: Vec<ProcessCoverage> = vec![
|
||||
ProcessCoverage {
|
||||
result: vec![ScriptCoverage {
|
||||
script_id: String::from("0"),
|
||||
url: String::from("/lib.js"),
|
||||
functions: vec![FunctionCoverage {
|
||||
function_name: String::from("lib"),
|
||||
is_block_coverage: true,
|
||||
ranges: vec![
|
||||
CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 7,
|
||||
count: 10,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 4,
|
||||
count: 1,
|
||||
},
|
||||
],
|
||||
}],
|
||||
}],
|
||||
},
|
||||
ProcessCoverage {
|
||||
result: vec![ScriptCoverage {
|
||||
script_id: String::from("0"),
|
||||
url: String::from("/lib.js"),
|
||||
functions: vec![FunctionCoverage {
|
||||
function_name: String::from("lib"),
|
||||
is_block_coverage: true,
|
||||
ranges: vec![
|
||||
CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 7,
|
||||
count: 20,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 1,
|
||||
end_offset: 6,
|
||||
count: 11,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 2,
|
||||
end_offset: 5,
|
||||
count: 2,
|
||||
},
|
||||
],
|
||||
}],
|
||||
}],
|
||||
},
|
||||
];
|
||||
let expected: Option<ProcessCoverage> = Some(ProcessCoverage {
|
||||
result: vec![ScriptCoverage {
|
||||
script_id: String::from("0"),
|
||||
url: String::from("/lib.js"),
|
||||
functions: vec![FunctionCoverage {
|
||||
function_name: String::from("lib"),
|
||||
is_block_coverage: true,
|
||||
ranges: vec![
|
||||
CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 7,
|
||||
count: 30,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 6,
|
||||
count: 21,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 1,
|
||||
end_offset: 5,
|
||||
count: 12,
|
||||
},
|
||||
CoverageRange {
|
||||
start_offset: 2,
|
||||
end_offset: 4,
|
||||
count: 3,
|
||||
},
|
||||
],
|
||||
}],
|
||||
}],
|
||||
});
|
||||
|
||||
assert_eq!(merge_processes(inputs), expected);
|
||||
}
|
||||
}
|
|
@ -17,8 +17,6 @@ use deno_core::serde_json;
|
|||
use deno_core::url::Url;
|
||||
use deno_core::LocalInspectorSession;
|
||||
use regex::Regex;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use sourcemap::SourceMap;
|
||||
use std::fs;
|
||||
use std::fs::File;
|
||||
|
@ -28,52 +26,11 @@ use std::path::PathBuf;
|
|||
use text_lines::TextLines;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct CoverageRange {
|
||||
/// Start byte index.
|
||||
start_offset: usize,
|
||||
/// End byte index.
|
||||
end_offset: usize,
|
||||
count: usize,
|
||||
}
|
||||
mod json_types;
|
||||
mod merge;
|
||||
mod range_tree;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct FunctionCoverage {
|
||||
function_name: String,
|
||||
ranges: Vec<CoverageRange>,
|
||||
is_block_coverage: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct ScriptCoverage {
|
||||
script_id: String,
|
||||
url: String,
|
||||
functions: Vec<FunctionCoverage>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct StartPreciseCoverageParameters {
|
||||
call_count: bool,
|
||||
detailed: bool,
|
||||
allow_triggered_updates: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct StartPreciseCoverageReturnObject {
|
||||
timestamp: f64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct TakePreciseCoverageReturnObject {
|
||||
result: Vec<ScriptCoverage>,
|
||||
timestamp: f64,
|
||||
}
|
||||
use json_types::*;
|
||||
|
||||
pub struct CoverageCollector {
|
||||
pub dir: PathBuf,
|
||||
|
@ -175,21 +132,21 @@ struct BranchCoverageItem {
|
|||
line_index: usize,
|
||||
block_number: usize,
|
||||
branch_number: usize,
|
||||
taken: Option<usize>,
|
||||
taken: Option<i64>,
|
||||
is_hit: bool,
|
||||
}
|
||||
|
||||
struct FunctionCoverageItem {
|
||||
name: String,
|
||||
line_index: usize,
|
||||
execution_count: usize,
|
||||
execution_count: i64,
|
||||
}
|
||||
|
||||
struct CoverageReport {
|
||||
url: ModuleSpecifier,
|
||||
named_functions: Vec<FunctionCoverageItem>,
|
||||
branches: Vec<BranchCoverageItem>,
|
||||
found_lines: Vec<(usize, usize)>,
|
||||
found_lines: Vec<(usize, i64)>,
|
||||
}
|
||||
|
||||
fn generate_coverage_report(
|
||||
|
@ -353,7 +310,7 @@ fn generate_coverage_report(
|
|||
results.into_iter()
|
||||
})
|
||||
.flatten()
|
||||
.collect::<Vec<(usize, usize)>>();
|
||||
.collect::<Vec<(usize, i64)>>();
|
||||
|
||||
found_lines.sort_unstable_by_key(|(index, _)| *index);
|
||||
// combine duplicated lines
|
||||
|
@ -369,7 +326,7 @@ fn generate_coverage_report(
|
|||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(index, count)| (index, count))
|
||||
.collect::<Vec<(usize, usize)>>()
|
||||
.collect::<Vec<(usize, i64)>>()
|
||||
};
|
||||
|
||||
coverage_report
|
||||
|
@ -553,38 +510,7 @@ fn collect_coverages(
|
|||
for file_path in file_paths {
|
||||
let json = fs::read_to_string(file_path.as_path())?;
|
||||
let new_coverage: ScriptCoverage = serde_json::from_str(&json)?;
|
||||
|
||||
let existing_coverage =
|
||||
coverages.iter_mut().find(|x| x.url == new_coverage.url);
|
||||
|
||||
if let Some(existing_coverage) = existing_coverage {
|
||||
for new_function in new_coverage.functions {
|
||||
let existing_function = existing_coverage
|
||||
.functions
|
||||
.iter_mut()
|
||||
.find(|x| x.function_name == new_function.function_name);
|
||||
|
||||
if let Some(existing_function) = existing_function {
|
||||
for new_range in new_function.ranges {
|
||||
let existing_range =
|
||||
existing_function.ranges.iter_mut().find(|x| {
|
||||
x.start_offset == new_range.start_offset
|
||||
&& x.end_offset == new_range.end_offset
|
||||
});
|
||||
|
||||
if let Some(existing_range) = existing_range {
|
||||
existing_range.count += new_range.count;
|
||||
} else {
|
||||
existing_function.ranges.push(new_range);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
existing_coverage.functions.push(new_function);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
coverages.push(new_coverage);
|
||||
}
|
||||
coverages.push(new_coverage);
|
||||
}
|
||||
|
||||
coverages.sort_by_key(|k| k.url.clone());
|
||||
|
@ -632,6 +558,18 @@ pub async fn cover_files(
|
|||
coverage_flags.exclude,
|
||||
);
|
||||
|
||||
let proc_coverages: Vec<_> = script_coverages
|
||||
.into_iter()
|
||||
.map(|cov| ProcessCoverage { result: vec![cov] })
|
||||
.collect();
|
||||
|
||||
let script_coverages = if let Some(c) = merge::merge_processes(proc_coverages)
|
||||
{
|
||||
c.result
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
let reporter_kind = if coverage_flags.lcov {
|
||||
CoverageReporterKind::Lcov
|
||||
} else {
|
207
cli/tools/coverage/range_tree.rs
Normal file
207
cli/tools/coverage/range_tree.rs
Normal file
|
@ -0,0 +1,207 @@
|
|||
// Forked from https://github.com/demurgos/v8-coverage/tree/d0ca18da8740198681e0bc68971b0a6cdb11db3e/rust
|
||||
// Copyright 2021 Charles Samborski. All rights reserved. MIT license.
|
||||
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use super::json_types::CoverageRange;
|
||||
use std::iter::Peekable;
|
||||
use typed_arena::Arena;
|
||||
|
||||
pub struct RangeTreeArena<'a>(Arena<RangeTree<'a>>);
|
||||
|
||||
impl<'a> RangeTreeArena<'a> {
|
||||
#[cfg(test)]
|
||||
pub fn new() -> Self {
|
||||
RangeTreeArena(Arena::new())
|
||||
}
|
||||
|
||||
pub fn with_capacity(n: usize) -> Self {
|
||||
RangeTreeArena(Arena::with_capacity(n))
|
||||
}
|
||||
|
||||
#[allow(clippy::mut_from_ref)]
|
||||
pub fn alloc(&'a self, value: RangeTree<'a>) -> &'a mut RangeTree<'a> {
|
||||
self.0.alloc(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Debug)]
|
||||
pub struct RangeTree<'a> {
|
||||
pub start: usize,
|
||||
pub end: usize,
|
||||
pub delta: i64,
|
||||
pub children: Vec<&'a mut RangeTree<'a>>,
|
||||
}
|
||||
|
||||
impl<'rt> RangeTree<'rt> {
|
||||
pub fn new<'a>(
|
||||
start: usize,
|
||||
end: usize,
|
||||
delta: i64,
|
||||
children: Vec<&'a mut RangeTree<'a>>,
|
||||
) -> RangeTree<'a> {
|
||||
RangeTree {
|
||||
start,
|
||||
end,
|
||||
delta,
|
||||
children,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn split<'a>(
|
||||
rta: &'a RangeTreeArena<'a>,
|
||||
tree: &'a mut RangeTree<'a>,
|
||||
value: usize,
|
||||
) -> (&'a mut RangeTree<'a>, &'a mut RangeTree<'a>) {
|
||||
let mut left_children: Vec<&'a mut RangeTree<'a>> = Vec::new();
|
||||
let mut right_children: Vec<&'a mut RangeTree<'a>> = Vec::new();
|
||||
for child in tree.children.iter_mut() {
|
||||
if child.end <= value {
|
||||
left_children.push(child);
|
||||
} else if value <= child.start {
|
||||
right_children.push(child);
|
||||
} else {
|
||||
let (left_child, right_child) = Self::split(rta, child, value);
|
||||
left_children.push(left_child);
|
||||
right_children.push(right_child);
|
||||
}
|
||||
}
|
||||
|
||||
let left = RangeTree::new(tree.start, value, tree.delta, left_children);
|
||||
let right = RangeTree::new(value, tree.end, tree.delta, right_children);
|
||||
(rta.alloc(left), rta.alloc(right))
|
||||
}
|
||||
|
||||
pub fn normalize<'a>(
|
||||
rta: &'a RangeTreeArena<'a>,
|
||||
tree: &'a mut RangeTree<'a>,
|
||||
) -> &'a mut RangeTree<'a> {
|
||||
tree.children = {
|
||||
let mut children: Vec<&'a mut RangeTree<'a>> = Vec::new();
|
||||
let mut chain: Vec<&'a mut RangeTree<'a>> = Vec::new();
|
||||
for child in tree.children.drain(..) {
|
||||
let is_chain_end: bool =
|
||||
match chain.last().map(|tree| (tree.delta, tree.end)) {
|
||||
Some((delta, chain_end)) => {
|
||||
(delta, chain_end) != (child.delta, child.start)
|
||||
}
|
||||
None => false,
|
||||
};
|
||||
if is_chain_end {
|
||||
let mut chain_iter = chain.drain(..);
|
||||
let mut head: &'a mut RangeTree<'a> = chain_iter.next().unwrap();
|
||||
for tree in chain_iter {
|
||||
head.end = tree.end;
|
||||
for sub_child in tree.children.drain(..) {
|
||||
sub_child.delta += tree.delta - head.delta;
|
||||
head.children.push(sub_child);
|
||||
}
|
||||
}
|
||||
children.push(RangeTree::normalize(rta, head));
|
||||
}
|
||||
chain.push(child)
|
||||
}
|
||||
if !chain.is_empty() {
|
||||
let mut chain_iter = chain.drain(..);
|
||||
let mut head: &'a mut RangeTree<'a> = chain_iter.next().unwrap();
|
||||
for tree in chain_iter {
|
||||
head.end = tree.end;
|
||||
for sub_child in tree.children.drain(..) {
|
||||
sub_child.delta += tree.delta - head.delta;
|
||||
head.children.push(sub_child);
|
||||
}
|
||||
}
|
||||
children.push(RangeTree::normalize(rta, head));
|
||||
}
|
||||
|
||||
if children.len() == 1
|
||||
&& children[0].start == tree.start
|
||||
&& children[0].end == tree.end
|
||||
{
|
||||
let normalized = children.remove(0);
|
||||
normalized.delta += tree.delta;
|
||||
return normalized;
|
||||
}
|
||||
|
||||
children
|
||||
};
|
||||
|
||||
tree
|
||||
}
|
||||
|
||||
pub fn to_ranges(&self) -> Vec<CoverageRange> {
|
||||
let mut ranges: Vec<CoverageRange> = Vec::new();
|
||||
let mut stack: Vec<(&RangeTree, i64)> = vec![(self, 0)];
|
||||
while let Some((cur, parent_count)) = stack.pop() {
|
||||
let count: i64 = parent_count + cur.delta;
|
||||
ranges.push(CoverageRange {
|
||||
start_offset: cur.start,
|
||||
end_offset: cur.end,
|
||||
count,
|
||||
});
|
||||
for child in cur.children.iter().rev() {
|
||||
stack.push((child, count))
|
||||
}
|
||||
}
|
||||
ranges
|
||||
}
|
||||
|
||||
pub fn from_sorted_ranges<'a>(
|
||||
rta: &'a RangeTreeArena<'a>,
|
||||
ranges: &[CoverageRange],
|
||||
) -> Option<&'a mut RangeTree<'a>> {
|
||||
Self::from_sorted_ranges_inner(
|
||||
rta,
|
||||
&mut ranges.iter().peekable(),
|
||||
::std::usize::MAX,
|
||||
0,
|
||||
)
|
||||
}
|
||||
|
||||
fn from_sorted_ranges_inner<'a, 'b, 'c: 'b>(
|
||||
rta: &'a RangeTreeArena<'a>,
|
||||
ranges: &'b mut Peekable<impl Iterator<Item = &'c CoverageRange>>,
|
||||
parent_end: usize,
|
||||
parent_count: i64,
|
||||
) -> Option<&'a mut RangeTree<'a>> {
|
||||
let has_range: bool = match ranges.peek() {
|
||||
None => false,
|
||||
Some(range) => range.start_offset < parent_end,
|
||||
};
|
||||
if !has_range {
|
||||
return None;
|
||||
}
|
||||
let range = ranges.next().unwrap();
|
||||
let start: usize = range.start_offset;
|
||||
let end: usize = range.end_offset;
|
||||
let count: i64 = range.count;
|
||||
let delta: i64 = count - parent_count;
|
||||
let mut children: Vec<&mut RangeTree> = Vec::new();
|
||||
while let Some(child) =
|
||||
Self::from_sorted_ranges_inner(rta, ranges, end, count)
|
||||
{
|
||||
children.push(child);
|
||||
}
|
||||
Some(rta.alloc(RangeTree::new(start, end, delta, children)))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn from_sorted_ranges_empty() {
|
||||
let rta = RangeTreeArena::new();
|
||||
let inputs: Vec<CoverageRange> = vec![CoverageRange {
|
||||
start_offset: 0,
|
||||
end_offset: 9,
|
||||
count: 1,
|
||||
}];
|
||||
let actual: Option<&mut RangeTree> =
|
||||
RangeTree::from_sorted_ranges(&rta, &inputs);
|
||||
let expected: Option<&mut RangeTree> =
|
||||
Some(rta.alloc(RangeTree::new(0, 9, 1, Vec::new())));
|
||||
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
}
|
|
@ -30,10 +30,10 @@ struct StubDocLoader;
|
|||
impl Loader for StubDocLoader {
|
||||
fn load(
|
||||
&mut self,
|
||||
specifier: &ModuleSpecifier,
|
||||
_specifier: &ModuleSpecifier,
|
||||
_is_dynamic: bool,
|
||||
) -> LoadFuture {
|
||||
Box::pin(future::ready((specifier.clone(), Ok(None))))
|
||||
Box::pin(future::ready(Ok(None)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,7 @@ impl Resolver for DocResolver {
|
|||
) -> Result<ModuleSpecifier, AnyError> {
|
||||
if let Some(import_map) = &self.import_map {
|
||||
return import_map
|
||||
.resolve(specifier, referrer.as_str())
|
||||
.resolve(specifier, referrer)
|
||||
.map_err(AnyError::from);
|
||||
}
|
||||
|
||||
|
@ -74,18 +74,16 @@ impl Loader for DocLoader {
|
|||
let specifier = specifier.clone();
|
||||
let ps = self.ps.clone();
|
||||
async move {
|
||||
let result = ps
|
||||
.file_fetcher
|
||||
ps.file_fetcher
|
||||
.fetch(&specifier, &mut Permissions::allow_all())
|
||||
.await
|
||||
.map(|file| {
|
||||
Some(LoadResponse {
|
||||
specifier: specifier.clone(),
|
||||
specifier,
|
||||
content: file.source.clone(),
|
||||
maybe_headers: file.maybe_headers,
|
||||
})
|
||||
});
|
||||
(specifier.clone(), result)
|
||||
})
|
||||
}
|
||||
.boxed_local()
|
||||
}
|
||||
|
@ -113,6 +111,7 @@ pub async fn print_docs(
|
|||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
let doc_parser =
|
||||
|
@ -152,6 +151,7 @@ pub async fn print_docs(
|
|||
Some(&resolver),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
let doc_parser =
|
||||
|
|
|
@ -46,11 +46,12 @@ fn validate_name(exec_name: &str) -> Result<(), AnyError> {
|
|||
/// One compatible with cmd & powershell with a .cmd extension
|
||||
/// A second compatible with git bash / MINGW64
|
||||
/// Generate batch script to satisfy that.
|
||||
fn generate_executable_file(
|
||||
mut file_path: PathBuf,
|
||||
args: Vec<String>,
|
||||
) -> Result<(), AnyError> {
|
||||
let args: Vec<String> = args.iter().map(|c| format!("\"{}\"", c)).collect();
|
||||
fn generate_executable_file(shim_data: &ShimData) -> Result<(), AnyError> {
|
||||
let args: Vec<String> = shim_data
|
||||
.args
|
||||
.iter()
|
||||
.map(|c| format!("\"{}\"", c))
|
||||
.collect();
|
||||
let template = format!(
|
||||
"% generated by deno install %\n@deno {} %*\n",
|
||||
args
|
||||
|
@ -59,12 +60,11 @@ fn generate_executable_file(
|
|||
.collect::<Vec<_>>()
|
||||
.join(" ")
|
||||
);
|
||||
let mut file = File::create(&file_path)?;
|
||||
let mut file = File::create(&shim_data.file_path)?;
|
||||
file.write_all(template.as_bytes())?;
|
||||
|
||||
// write file for bash
|
||||
// create filepath without extensions
|
||||
file_path.set_extension("");
|
||||
let template = format!(
|
||||
r#"#!/bin/sh
|
||||
# generated by deno install
|
||||
|
@ -72,19 +72,17 @@ deno {} "$@"
|
|||
"#,
|
||||
args.join(" "),
|
||||
);
|
||||
let mut file = File::create(&file_path)?;
|
||||
let mut file = File::create(&shim_data.file_path.with_extension(""))?;
|
||||
file.write_all(template.as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
fn generate_executable_file(
|
||||
file_path: PathBuf,
|
||||
args: Vec<String>,
|
||||
) -> Result<(), AnyError> {
|
||||
fn generate_executable_file(shim_data: &ShimData) -> Result<(), AnyError> {
|
||||
use shell_escape::escape;
|
||||
let args: Vec<String> = args
|
||||
.into_iter()
|
||||
let args: Vec<String> = shim_data
|
||||
.args
|
||||
.iter()
|
||||
.map(|c| escape(c.into()).into_owned())
|
||||
.collect();
|
||||
let template = format!(
|
||||
|
@ -94,12 +92,12 @@ exec deno {} "$@"
|
|||
"#,
|
||||
args.join(" "),
|
||||
);
|
||||
let mut file = File::create(&file_path)?;
|
||||
let mut file = File::create(&shim_data.file_path)?;
|
||||
file.write_all(template.as_bytes())?;
|
||||
let _metadata = fs::metadata(&file_path)?;
|
||||
let _metadata = fs::metadata(&shim_data.file_path)?;
|
||||
let mut permissions = _metadata.permissions();
|
||||
permissions.set_mode(0o755);
|
||||
fs::set_permissions(&file_path, permissions)?;
|
||||
fs::set_permissions(&shim_data.file_path, permissions)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -195,27 +193,73 @@ pub fn install(
|
|||
flags: Flags,
|
||||
install_flags: InstallFlags,
|
||||
) -> Result<(), AnyError> {
|
||||
let root = if let Some(root) = install_flags.root {
|
||||
canonicalize_path(&root)?
|
||||
} else {
|
||||
get_installer_root()?
|
||||
};
|
||||
let installation_dir = root.join("bin");
|
||||
let shim_data = resolve_shim_data(&flags, &install_flags)?;
|
||||
|
||||
// ensure directory exists
|
||||
if let Ok(metadata) = fs::metadata(&installation_dir) {
|
||||
if let Ok(metadata) = fs::metadata(&shim_data.installation_dir) {
|
||||
if !metadata.is_dir() {
|
||||
return Err(generic_error("Installation path is not a directory"));
|
||||
}
|
||||
} else {
|
||||
fs::create_dir_all(&installation_dir)?;
|
||||
fs::create_dir_all(&shim_data.installation_dir)?;
|
||||
};
|
||||
|
||||
if shim_data.file_path.exists() && !install_flags.force {
|
||||
return Err(generic_error(
|
||||
"Existing installation found. Aborting (Use -f to overwrite).",
|
||||
));
|
||||
};
|
||||
|
||||
generate_executable_file(&shim_data)?;
|
||||
for (path, contents) in shim_data.extra_files {
|
||||
fs::write(path, contents)?;
|
||||
}
|
||||
|
||||
println!("✅ Successfully installed {}", shim_data.name);
|
||||
println!("{}", shim_data.file_path.display());
|
||||
if cfg!(windows) {
|
||||
let display_path = shim_data.file_path.with_extension("");
|
||||
println!("{} (shell)", display_path.display());
|
||||
}
|
||||
let installation_dir_str = shim_data.installation_dir.to_string_lossy();
|
||||
|
||||
if !is_in_path(&shim_data.installation_dir) {
|
||||
println!("ℹ️ Add {} to PATH", installation_dir_str);
|
||||
if cfg!(windows) {
|
||||
println!(" set PATH=%PATH%;{}", installation_dir_str);
|
||||
} else {
|
||||
println!(" export PATH=\"{}:$PATH\"", installation_dir_str);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
struct ShimData {
|
||||
name: String,
|
||||
installation_dir: PathBuf,
|
||||
file_path: PathBuf,
|
||||
args: Vec<String>,
|
||||
extra_files: Vec<(PathBuf, String)>,
|
||||
}
|
||||
|
||||
fn resolve_shim_data(
|
||||
flags: &Flags,
|
||||
install_flags: &InstallFlags,
|
||||
) -> Result<ShimData, AnyError> {
|
||||
let root = if let Some(root) = &install_flags.root {
|
||||
canonicalize_path(root)?
|
||||
} else {
|
||||
get_installer_root()?
|
||||
};
|
||||
let installation_dir = root.join("bin");
|
||||
|
||||
// Check if module_url is remote
|
||||
let module_url = resolve_url_or_path(&install_flags.module_url)?;
|
||||
|
||||
let name = install_flags
|
||||
.name
|
||||
.clone()
|
||||
.or_else(|| infer_name_from_url(&module_url));
|
||||
|
||||
let name = match name {
|
||||
|
@ -232,12 +276,6 @@ pub fn install(
|
|||
file_path = file_path.with_extension("cmd");
|
||||
}
|
||||
|
||||
if file_path.exists() && !install_flags.force {
|
||||
return Err(generic_error(
|
||||
"Existing installation found. Aborting (Use -f to overwrite).",
|
||||
));
|
||||
};
|
||||
|
||||
let mut extra_files: Vec<(PathBuf, String)> = vec![];
|
||||
|
||||
let mut executable_args = vec!["run".to_string()];
|
||||
|
@ -246,9 +284,9 @@ pub fn install(
|
|||
executable_args.push("--location".to_string());
|
||||
executable_args.push(url.to_string());
|
||||
}
|
||||
if let Some(ca_file) = flags.ca_file {
|
||||
if let Some(ca_file) = &flags.ca_file {
|
||||
executable_args.push("--cert".to_string());
|
||||
executable_args.push(ca_file)
|
||||
executable_args.push(ca_file.to_owned())
|
||||
}
|
||||
if let Some(log_level) = flags.log_level {
|
||||
if log_level == Level::Error {
|
||||
|
@ -290,6 +328,10 @@ pub fn install(
|
|||
executable_args.push("--cached-only".to_string());
|
||||
}
|
||||
|
||||
if flags.prompt {
|
||||
executable_args.push("--prompt".to_string());
|
||||
}
|
||||
|
||||
if !flags.v8_flags.is_empty() {
|
||||
executable_args.push(format!("--v8-flags={}", flags.v8_flags.join(",")));
|
||||
}
|
||||
|
@ -300,20 +342,20 @@ pub fn install(
|
|||
}
|
||||
|
||||
if let Some(inspect) = flags.inspect {
|
||||
executable_args.push(format!("--inspect={}", inspect.to_string()));
|
||||
executable_args.push(format!("--inspect={}", inspect));
|
||||
}
|
||||
|
||||
if let Some(inspect_brk) = flags.inspect_brk {
|
||||
executable_args.push(format!("--inspect-brk={}", inspect_brk.to_string()));
|
||||
executable_args.push(format!("--inspect-brk={}", inspect_brk));
|
||||
}
|
||||
|
||||
if let Some(import_map_path) = flags.import_map_path {
|
||||
let import_map_url = resolve_url_or_path(&import_map_path)?;
|
||||
if let Some(import_map_path) = &flags.import_map_path {
|
||||
let import_map_url = resolve_url_or_path(import_map_path)?;
|
||||
executable_args.push("--import-map".to_string());
|
||||
executable_args.push(import_map_url.to_string());
|
||||
}
|
||||
|
||||
if let Some(config_path) = flags.config_path {
|
||||
if let Some(config_path) = &flags.config_path {
|
||||
let mut copy_path = file_path.clone();
|
||||
copy_path.set_extension("tsconfig.json");
|
||||
executable_args.push("--config".to_string());
|
||||
|
@ -321,7 +363,7 @@ pub fn install(
|
|||
extra_files.push((copy_path, fs::read_to_string(config_path)?));
|
||||
}
|
||||
|
||||
if let Some(lock_path) = flags.lock {
|
||||
if let Some(lock_path) = &flags.lock {
|
||||
let mut copy_path = file_path.clone();
|
||||
copy_path.set_extension("lock.json");
|
||||
executable_args.push("--lock".to_string());
|
||||
|
@ -332,29 +374,13 @@ pub fn install(
|
|||
executable_args.push(module_url.to_string());
|
||||
executable_args.extend_from_slice(&install_flags.args);
|
||||
|
||||
generate_executable_file(file_path.to_owned(), executable_args)?;
|
||||
for (path, contents) in extra_files {
|
||||
fs::write(path, contents)?;
|
||||
}
|
||||
|
||||
println!("✅ Successfully installed {}", name);
|
||||
println!("{}", file_path.to_string_lossy());
|
||||
if cfg!(windows) {
|
||||
file_path.set_extension("");
|
||||
println!("{} (shell)", file_path.to_string_lossy());
|
||||
}
|
||||
let installation_dir_str = installation_dir.to_string_lossy();
|
||||
|
||||
if !is_in_path(&installation_dir) {
|
||||
println!("ℹ️ Add {} to PATH", installation_dir_str);
|
||||
if cfg!(windows) {
|
||||
println!(" set PATH=%PATH%;{}", installation_dir_str);
|
||||
} else {
|
||||
println!(" export PATH=\"{}:$PATH\"", installation_dir_str);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(ShimData {
|
||||
name,
|
||||
installation_dir,
|
||||
file_path,
|
||||
args: executable_args,
|
||||
extra_files,
|
||||
})
|
||||
}
|
||||
|
||||
fn is_in_path(dir: &Path) -> bool {
|
||||
|
@ -480,6 +506,16 @@ mod tests {
|
|||
)
|
||||
.expect("Install failed");
|
||||
|
||||
if let Some(home) = original_home {
|
||||
env::set_var("HOME", home);
|
||||
}
|
||||
if let Some(user_profile) = original_user_profile {
|
||||
env::set_var("USERPROFILE", user_profile);
|
||||
}
|
||||
if let Some(install_root) = original_install_root {
|
||||
env::set_var("DENO_INSTALL_ROOT", install_root);
|
||||
}
|
||||
|
||||
let mut file_path = temp_dir.path().join(".deno/bin/echo_test");
|
||||
assert!(file_path.exists());
|
||||
|
||||
|
@ -498,15 +534,6 @@ mod tests {
|
|||
} else {
|
||||
assert!(content.contains(r#"run 'http://localhost:4545/echo_server.ts'"#));
|
||||
}
|
||||
if let Some(home) = original_home {
|
||||
env::set_var("HOME", home);
|
||||
}
|
||||
if let Some(user_profile) = original_user_profile {
|
||||
env::set_var("USERPROFILE", user_profile);
|
||||
}
|
||||
if let Some(install_root) = original_install_root {
|
||||
env::set_var("DENO_INSTALL_ROOT", install_root);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -551,104 +578,65 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn install_inferred_name() {
|
||||
let temp_dir = TempDir::new().expect("tempdir fail");
|
||||
let bin_dir = temp_dir.path().join("bin");
|
||||
std::fs::create_dir(&bin_dir).unwrap();
|
||||
|
||||
install(
|
||||
Flags::default(),
|
||||
InstallFlags {
|
||||
let shim_data = resolve_shim_data(
|
||||
&Flags::default(),
|
||||
&InstallFlags {
|
||||
module_url: "http://localhost:4545/echo_server.ts".to_string(),
|
||||
args: vec![],
|
||||
name: None,
|
||||
root: Some(temp_dir.path().to_path_buf()),
|
||||
root: Some(env::temp_dir()),
|
||||
force: false,
|
||||
},
|
||||
)
|
||||
.expect("Install failed");
|
||||
.unwrap();
|
||||
|
||||
let mut file_path = bin_dir.join("echo_server");
|
||||
if cfg!(windows) {
|
||||
file_path = file_path.with_extension("cmd");
|
||||
}
|
||||
|
||||
assert!(file_path.exists());
|
||||
let content = fs::read_to_string(file_path).unwrap();
|
||||
if cfg!(windows) {
|
||||
assert!(
|
||||
content.contains(r#""run" "http://localhost:4545/echo_server.ts""#)
|
||||
);
|
||||
} else {
|
||||
assert!(content.contains(r#"run 'http://localhost:4545/echo_server.ts'"#));
|
||||
}
|
||||
assert_eq!(shim_data.name, "echo_server");
|
||||
assert_eq!(
|
||||
shim_data.args,
|
||||
vec!["run", "http://localhost:4545/echo_server.ts",]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn install_inferred_name_from_parent() {
|
||||
let temp_dir = TempDir::new().expect("tempdir fail");
|
||||
let bin_dir = temp_dir.path().join("bin");
|
||||
std::fs::create_dir(&bin_dir).unwrap();
|
||||
|
||||
install(
|
||||
Flags::default(),
|
||||
InstallFlags {
|
||||
let shim_data = resolve_shim_data(
|
||||
&Flags::default(),
|
||||
&InstallFlags {
|
||||
module_url: "http://localhost:4545/subdir/main.ts".to_string(),
|
||||
args: vec![],
|
||||
name: None,
|
||||
root: Some(temp_dir.path().to_path_buf()),
|
||||
root: Some(env::temp_dir()),
|
||||
force: false,
|
||||
},
|
||||
)
|
||||
.expect("Install failed");
|
||||
.unwrap();
|
||||
|
||||
let mut file_path = bin_dir.join("subdir");
|
||||
if cfg!(windows) {
|
||||
file_path = file_path.with_extension("cmd");
|
||||
}
|
||||
|
||||
assert!(file_path.exists());
|
||||
let content = fs::read_to_string(file_path).unwrap();
|
||||
if cfg!(windows) {
|
||||
assert!(
|
||||
content.contains(r#""run" "http://localhost:4545/subdir/main.ts""#)
|
||||
);
|
||||
} else {
|
||||
assert!(content.contains(r#"run 'http://localhost:4545/subdir/main.ts'"#));
|
||||
}
|
||||
assert_eq!(shim_data.name, "subdir");
|
||||
assert_eq!(
|
||||
shim_data.args,
|
||||
vec!["run", "http://localhost:4545/subdir/main.ts",]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn install_custom_dir_option() {
|
||||
let temp_dir = TempDir::new().expect("tempdir fail");
|
||||
let bin_dir = temp_dir.path().join("bin");
|
||||
std::fs::create_dir(&bin_dir).unwrap();
|
||||
|
||||
install(
|
||||
Flags::default(),
|
||||
InstallFlags {
|
||||
let shim_data = resolve_shim_data(
|
||||
&Flags::default(),
|
||||
&InstallFlags {
|
||||
module_url: "http://localhost:4545/echo_server.ts".to_string(),
|
||||
args: vec![],
|
||||
name: Some("echo_test".to_string()),
|
||||
root: Some(temp_dir.path().to_path_buf()),
|
||||
root: Some(env::temp_dir()),
|
||||
force: false,
|
||||
},
|
||||
)
|
||||
.expect("Install failed");
|
||||
.unwrap();
|
||||
|
||||
let mut file_path = bin_dir.join("echo_test");
|
||||
if cfg!(windows) {
|
||||
file_path = file_path.with_extension("cmd");
|
||||
}
|
||||
|
||||
assert!(file_path.exists());
|
||||
let content = fs::read_to_string(file_path).unwrap();
|
||||
if cfg!(windows) {
|
||||
assert!(
|
||||
content.contains(r#""run" "http://localhost:4545/echo_server.ts""#)
|
||||
);
|
||||
} else {
|
||||
assert!(content.contains(r#"run 'http://localhost:4545/echo_server.ts'"#));
|
||||
}
|
||||
assert_eq!(shim_data.name, "echo_test");
|
||||
assert_eq!(
|
||||
shim_data.args,
|
||||
vec!["run", "http://localhost:4545/echo_server.ts",]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -660,9 +648,9 @@ mod tests {
|
|||
let original_install_root = env::var_os("DENO_INSTALL_ROOT");
|
||||
env::set_var("DENO_INSTALL_ROOT", temp_dir.path().to_path_buf());
|
||||
|
||||
install(
|
||||
Flags::default(),
|
||||
InstallFlags {
|
||||
let shim_data = resolve_shim_data(
|
||||
&Flags::default(),
|
||||
&InstallFlags {
|
||||
module_url: "http://localhost:4545/echo_server.ts".to_string(),
|
||||
args: vec![],
|
||||
name: Some("echo_test".to_string()),
|
||||
|
@ -670,100 +658,102 @@ mod tests {
|
|||
force: false,
|
||||
},
|
||||
)
|
||||
.expect("Install failed");
|
||||
.unwrap();
|
||||
|
||||
let mut file_path = bin_dir.join("echo_test");
|
||||
if cfg!(windows) {
|
||||
file_path = file_path.with_extension("cmd");
|
||||
}
|
||||
|
||||
assert!(file_path.exists());
|
||||
let content = fs::read_to_string(file_path).unwrap();
|
||||
if cfg!(windows) {
|
||||
assert!(
|
||||
content.contains(r#""run" "http://localhost:4545/echo_server.ts""#)
|
||||
);
|
||||
} else {
|
||||
assert!(content.contains(r#"run 'http://localhost:4545/echo_server.ts'"#));
|
||||
}
|
||||
if let Some(install_root) = original_install_root {
|
||||
env::set_var("DENO_INSTALL_ROOT", install_root);
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
fs::canonicalize(shim_data.installation_dir).unwrap(),
|
||||
fs::canonicalize(bin_dir).unwrap()
|
||||
);
|
||||
assert_eq!(shim_data.name, "echo_test");
|
||||
assert_eq!(
|
||||
shim_data.args,
|
||||
vec!["run", "http://localhost:4545/echo_server.ts",]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn install_with_flags() {
|
||||
let temp_dir = TempDir::new().expect("tempdir fail");
|
||||
let bin_dir = temp_dir.path().join("bin");
|
||||
std::fs::create_dir(&bin_dir).unwrap();
|
||||
|
||||
install(
|
||||
Flags {
|
||||
let shim_data = resolve_shim_data(
|
||||
&Flags {
|
||||
allow_net: Some(vec![]),
|
||||
allow_read: Some(vec![]),
|
||||
check: CheckFlag::None,
|
||||
log_level: Some(Level::Error),
|
||||
..Flags::default()
|
||||
},
|
||||
InstallFlags {
|
||||
&InstallFlags {
|
||||
module_url: "http://localhost:4545/echo_server.ts".to_string(),
|
||||
args: vec!["--foobar".to_string()],
|
||||
name: Some("echo_test".to_string()),
|
||||
root: Some(temp_dir.path().to_path_buf()),
|
||||
force: false,
|
||||
},
|
||||
)
|
||||
.expect("Install failed");
|
||||
|
||||
let mut file_path = bin_dir.join("echo_test");
|
||||
if cfg!(windows) {
|
||||
file_path = file_path.with_extension("cmd");
|
||||
}
|
||||
|
||||
assert!(file_path.exists());
|
||||
let content = fs::read_to_string(file_path).unwrap();
|
||||
if cfg!(windows) {
|
||||
assert!(content.contains(r#""run" "--allow-read" "--allow-net" "--quiet" "--no-check" "http://localhost:4545/echo_server.ts" "--foobar""#));
|
||||
} else {
|
||||
assert!(content.contains(r#"run --allow-read --allow-net --quiet --no-check 'http://localhost:4545/echo_server.ts' --foobar"#));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn install_allow_all() {
|
||||
let temp_dir = TempDir::new().expect("tempdir fail");
|
||||
let bin_dir = temp_dir.path().join("bin");
|
||||
std::fs::create_dir(&bin_dir).unwrap();
|
||||
|
||||
install(
|
||||
Flags {
|
||||
allow_all: true,
|
||||
..Flags::default()
|
||||
},
|
||||
InstallFlags {
|
||||
module_url: "http://localhost:4545/echo_server.ts".to_string(),
|
||||
args: vec![],
|
||||
name: Some("echo_test".to_string()),
|
||||
root: Some(temp_dir.path().to_path_buf()),
|
||||
root: Some(env::temp_dir()),
|
||||
force: false,
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut file_path = bin_dir.join("echo_test");
|
||||
if cfg!(windows) {
|
||||
file_path = file_path.with_extension("cmd");
|
||||
}
|
||||
assert_eq!(shim_data.name, "echo_test");
|
||||
assert_eq!(
|
||||
shim_data.args,
|
||||
vec![
|
||||
"run",
|
||||
"--allow-read",
|
||||
"--allow-net",
|
||||
"--quiet",
|
||||
"--no-check",
|
||||
"http://localhost:4545/echo_server.ts",
|
||||
"--foobar",
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
let content = fs::read_to_string(file_path).unwrap();
|
||||
if cfg!(windows) {
|
||||
assert!(content.contains(
|
||||
r#""run" "--allow-all" "http://localhost:4545/echo_server.ts""#
|
||||
));
|
||||
} else {
|
||||
assert!(content
|
||||
.contains(r#"run --allow-all 'http://localhost:4545/echo_server.ts'"#));
|
||||
}
|
||||
#[test]
|
||||
fn install_prompt() {
|
||||
let shim_data = resolve_shim_data(
|
||||
&Flags {
|
||||
prompt: true,
|
||||
..Flags::default()
|
||||
},
|
||||
&InstallFlags {
|
||||
module_url: "http://localhost:4545/echo_server.ts".to_string(),
|
||||
args: vec![],
|
||||
name: Some("echo_test".to_string()),
|
||||
root: Some(env::temp_dir()),
|
||||
force: false,
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
shim_data.args,
|
||||
vec!["run", "--prompt", "http://localhost:4545/echo_server.ts",]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn install_allow_all() {
|
||||
let shim_data = resolve_shim_data(
|
||||
&Flags {
|
||||
allow_all: true,
|
||||
..Flags::default()
|
||||
},
|
||||
&InstallFlags {
|
||||
module_url: "http://localhost:4545/echo_server.ts".to_string(),
|
||||
args: vec![],
|
||||
name: Some("echo_test".to_string()),
|
||||
root: Some(env::temp_dir()),
|
||||
force: false,
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
shim_data.args,
|
||||
vec!["run", "--allow-all", "http://localhost:4545/echo_server.ts",]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -999,12 +989,12 @@ mod tests {
|
|||
|
||||
let mut expected_string = format!(
|
||||
"--import-map '{}' 'http://localhost:4545/cat.ts'",
|
||||
import_map_url.to_string()
|
||||
import_map_url
|
||||
);
|
||||
if cfg!(windows) {
|
||||
expected_string = format!(
|
||||
"\"--import-map\" \"{}\" \"http://localhost:4545/cat.ts\"",
|
||||
import_map_url.to_string()
|
||||
import_map_url
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use crate::ast::transpile;
|
||||
use crate::ast::Diagnostics;
|
||||
use crate::ast::ImportsNotUsedAsValues;
|
||||
use crate::colors;
|
||||
use crate::lsp::ReplLanguageServer;
|
||||
use deno_ast::DiagnosticsError;
|
||||
use deno_ast::ImportsNotUsedAsValues;
|
||||
use deno_core::error::AnyError;
|
||||
use deno_core::futures::FutureExt;
|
||||
use deno_core::serde_json::json;
|
||||
|
@ -184,7 +183,7 @@ impl ReplSession {
|
|||
Some(diagnostic) => {
|
||||
Ok(EvaluationOutput::Error(format_diagnostic(diagnostic)))
|
||||
}
|
||||
None => match err.downcast_ref::<Diagnostics>() {
|
||||
None => match err.downcast_ref::<DiagnosticsError>() {
|
||||
Some(diagnostics) => Ok(EvaluationOutput::Error(
|
||||
diagnostics
|
||||
.0
|
||||
|
@ -311,9 +310,8 @@ impl ReplSession {
|
|||
scope_analysis: false,
|
||||
})?;
|
||||
|
||||
let transpiled_src = transpile(
|
||||
&parsed_module,
|
||||
&crate::ast::EmitOptions {
|
||||
let transpiled_src = parsed_module
|
||||
.transpile(&deno_ast::EmitOptions {
|
||||
emit_metadata: false,
|
||||
source_map: false,
|
||||
inline_source_map: false,
|
||||
|
@ -326,10 +324,9 @@ impl ReplSession {
|
|||
jsx_factory: "React.createElement".into(),
|
||||
jsx_fragment_factory: "React.Fragment".into(),
|
||||
jsx_import_source: None,
|
||||
repl_imports: true,
|
||||
},
|
||||
)?
|
||||
.0;
|
||||
var_decl_imports: true,
|
||||
})?
|
||||
.text;
|
||||
|
||||
let value = self
|
||||
.evaluate_expression(&format!(
|
||||
|
|
|
@ -136,14 +136,14 @@ pub async fn write_standalone_binary(
|
|||
let output = match target {
|
||||
Some(target) => {
|
||||
if target.contains("windows") {
|
||||
PathBuf::from(output.display().to_string() + ".exe")
|
||||
output.with_extension("exe")
|
||||
} else {
|
||||
output
|
||||
}
|
||||
}
|
||||
None => {
|
||||
if cfg!(windows) && output.extension().unwrap_or_default() != "exe" {
|
||||
PathBuf::from(output.display().to_string() + ".exe")
|
||||
output.with_extension("exe")
|
||||
} else {
|
||||
output
|
||||
}
|
||||
|
@ -175,7 +175,14 @@ pub async fn write_standalone_binary(
|
|||
// Remove file if it was indeed a deno compiled binary, to avoid corruption
|
||||
// (see https://github.com/denoland/deno/issues/10310)
|
||||
std::fs::remove_file(&output)?;
|
||||
} else {
|
||||
let output_base = &output.parent().unwrap();
|
||||
if output_base.exists() && output_base.is_file() {
|
||||
bail!("Could not compile: {:?} is a file.", &output_base);
|
||||
}
|
||||
tokio::fs::create_dir_all(output_base).await?;
|
||||
}
|
||||
|
||||
tokio::fs::write(&output, final_bin).await?;
|
||||
#[cfg(unix)]
|
||||
{
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use crate::ast::Location;
|
||||
use crate::cache;
|
||||
use crate::cache::CacherLoader;
|
||||
use crate::colors;
|
||||
|
@ -268,11 +267,7 @@ impl PrettyTestReporter {
|
|||
print!("{}", " ".repeat(description.level));
|
||||
}
|
||||
|
||||
println!(
|
||||
"{} {}",
|
||||
status,
|
||||
colors::gray(human_elapsed(elapsed.into())).to_string()
|
||||
);
|
||||
println!("{} {}", status, colors::gray(human_elapsed(elapsed.into())));
|
||||
|
||||
if let Some(error_text) = result.error() {
|
||||
for line in error_text.lines() {
|
||||
|
@ -358,11 +353,7 @@ impl TestReporter for PrettyTestReporter {
|
|||
print!(" ");
|
||||
}
|
||||
|
||||
println!(
|
||||
"{} {}",
|
||||
status,
|
||||
colors::gray(human_elapsed(elapsed.into())).to_string()
|
||||
);
|
||||
println!("{} {}", status, colors::gray(human_elapsed(elapsed.into())));
|
||||
}
|
||||
|
||||
fn report_step_wait(&mut self, description: &TestStepDescription) {
|
||||
|
@ -535,9 +526,10 @@ async fn test_specifier(
|
|||
}
|
||||
|
||||
fn extract_files_from_regex_blocks(
|
||||
location: &Location,
|
||||
specifier: &ModuleSpecifier,
|
||||
source: &str,
|
||||
media_type: MediaType,
|
||||
file_line_index: usize,
|
||||
blocks_regex: &Regex,
|
||||
lines_regex: &Regex,
|
||||
) -> Result<Vec<File>, AnyError> {
|
||||
|
@ -594,9 +586,9 @@ fn extract_files_from_regex_blocks(
|
|||
|
||||
let file_specifier = deno_core::resolve_url_or_path(&format!(
|
||||
"{}${}-{}{}",
|
||||
location.specifier,
|
||||
location.line + line_offset,
|
||||
location.line + line_offset + line_count,
|
||||
specifier,
|
||||
file_line_index + line_offset + 1,
|
||||
file_line_index + line_offset + line_count + 1,
|
||||
file_media_type.as_ts_extension(),
|
||||
))
|
||||
.unwrap();
|
||||
|
@ -642,12 +634,11 @@ fn extract_files_from_source_comments(
|
|||
true
|
||||
})
|
||||
.flat_map(|comment| {
|
||||
let location = Location::from_pos(&parsed_source, comment.span.lo);
|
||||
|
||||
extract_files_from_regex_blocks(
|
||||
&location,
|
||||
specifier,
|
||||
&comment.text,
|
||||
media_type,
|
||||
parsed_source.source().line_index(comment.span.lo),
|
||||
&blocks_regex,
|
||||
&lines_regex,
|
||||
)
|
||||
|
@ -663,19 +654,14 @@ fn extract_files_from_fenced_blocks(
|
|||
source: &str,
|
||||
media_type: MediaType,
|
||||
) -> Result<Vec<File>, AnyError> {
|
||||
let location = Location {
|
||||
specifier: specifier.to_string(),
|
||||
line: 1,
|
||||
col: 0,
|
||||
};
|
||||
|
||||
let blocks_regex = Regex::new(r"```([^\r\n]*)\r?\n([\S\s]*?)```")?;
|
||||
let lines_regex = Regex::new(r"(?:\# ?)?(.*)")?;
|
||||
|
||||
extract_files_from_regex_blocks(
|
||||
&location,
|
||||
specifier,
|
||||
source,
|
||||
media_type,
|
||||
/* file line index */ 0,
|
||||
&blocks_regex,
|
||||
&lines_regex,
|
||||
)
|
||||
|
@ -1150,6 +1136,7 @@ pub async fn run_tests_with_watch(
|
|||
maybe_resolver,
|
||||
maybe_locker,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
graph_valid(&graph, !no_check, check_js)?;
|
||||
|
|
24
cli/tsc.rs
24
cli/tsc.rs
|
@ -51,11 +51,25 @@ pub static SHARED_GLOBALS_LIB: &str =
|
|||
pub static WINDOW_LIB: &str = include_str!("dts/lib.deno.window.d.ts");
|
||||
pub static UNSTABLE_NS_LIB: &str = include_str!("dts/lib.deno.unstable.d.ts");
|
||||
|
||||
pub static COMPILER_SNAPSHOT: &[u8] =
|
||||
include_bytes!(concat!(env!("OUT_DIR"), "/COMPILER_SNAPSHOT.bin"));
|
||||
pub static COMPILER_SNAPSHOT: Lazy<Box<[u8]>> = Lazy::new(
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
|| {
|
||||
static COMPRESSED_COMPILER_SNAPSHOT: &[u8] =
|
||||
include_bytes!(concat!(env!("OUT_DIR"), "/COMPILER_SNAPSHOT.bin"));
|
||||
|
||||
zstd::block::decompress(
|
||||
&COMPRESSED_COMPILER_SNAPSHOT[4..],
|
||||
u32::from_le_bytes(COMPRESSED_COMPILER_SNAPSHOT[0..4].try_into().unwrap())
|
||||
as usize,
|
||||
)
|
||||
.unwrap()
|
||||
.into_boxed_slice()
|
||||
},
|
||||
);
|
||||
|
||||
pub fn compiler_snapshot() -> Snapshot {
|
||||
Snapshot::Static(COMPILER_SNAPSHOT)
|
||||
Snapshot::Static(&*COMPILER_SNAPSHOT)
|
||||
}
|
||||
|
||||
macro_rules! inc {
|
||||
|
@ -675,7 +689,7 @@ mod tests {
|
|||
})
|
||||
})
|
||||
.map_err(|err| err.into());
|
||||
Box::pin(future::ready((specifier.clone(), response)))
|
||||
Box::pin(future::ready(response))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -697,6 +711,7 @@ mod tests {
|
|||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
State::new(
|
||||
|
@ -723,6 +738,7 @@ mod tests {
|
|||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
let config = TsConfig::new(json!({
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
||||
[package]
|
||||
name = "deno_core"
|
||||
version = "0.113.0"
|
||||
version = "0.114.0"
|
||||
authors = ["the Deno authors"]
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
@ -23,7 +23,7 @@ parking_lot = "0.11.1"
|
|||
pin-project = "1.0.7"
|
||||
serde = { version = "1.0.129", features = ["derive"] }
|
||||
serde_json = { version = "1.0.66", features = ["preserve_order"] }
|
||||
serde_v8 = { version = "0.24.0", path = "../serde_v8" }
|
||||
serde_v8 = { version = "0.25.0", path = "../serde_v8" }
|
||||
url = { version = "2.2.2", features = ["serde"] }
|
||||
v8 = "0.37.0"
|
||||
|
||||
|
|
|
@ -372,6 +372,7 @@ impl ErrWithV8Handle {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::non_send_fields_in_send_ty)]
|
||||
unsafe impl Send for ErrWithV8Handle {}
|
||||
unsafe impl Sync for ErrWithV8Handle {}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ impl fmt::Display for ModuleResolutionError {
|
|||
specifier,
|
||||
match maybe_referrer {
|
||||
Some(referrer) => format!(" from \"{}\"", referrer),
|
||||
None => format!(""),
|
||||
None => String::new(),
|
||||
}
|
||||
),
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_broadcast_channel"
|
||||
version = "0.25.0"
|
||||
version = "0.26.0"
|
||||
authors = ["the Deno authors"]
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
@ -15,6 +15,6 @@ path = "lib.rs"
|
|||
|
||||
[dependencies]
|
||||
async-trait = "0.1"
|
||||
deno_core = { version = "0.113.0", path = "../../core" }
|
||||
deno_core = { version = "0.114.0", path = "../../core" }
|
||||
tokio = { version = "1.10.1", features = ["full"] }
|
||||
uuid = { version = "0.8.2", features = ["v4"] }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_console"
|
||||
version = "0.31.0"
|
||||
version = "0.32.0"
|
||||
authors = ["the Deno authors"]
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
@ -14,4 +14,4 @@ description = "Implementation of Console API for Deno"
|
|||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
deno_core = { version = "0.113.0", path = "../../core" }
|
||||
deno_core = { version = "0.114.0", path = "../../core" }
|
||||
|
|
|
@ -133,6 +133,7 @@
|
|||
"decrypt": {
|
||||
"RSA-OAEP": "RsaOaepParams",
|
||||
"AES-CBC": "AesCbcParams",
|
||||
"AES-GCM": "AesGcmParams",
|
||||
"AES-CTR": "AesCtrParams",
|
||||
},
|
||||
"get key length": {
|
||||
|
@ -145,12 +146,10 @@
|
|||
"PBKDF2": null,
|
||||
},
|
||||
"wrapKey": {
|
||||
// TODO(@littledivy): Enable this once implemented.
|
||||
// "AES-KW": "AesKeyWrapParams",
|
||||
"AES-KW": null,
|
||||
},
|
||||
"unwrapKey": {
|
||||
// TODO(@littledivy): Enable this once implemented.
|
||||
// "AES-KW": "AesKeyWrapParams",
|
||||
"AES-KW": null,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -633,6 +632,66 @@
|
|||
// 4.
|
||||
return cipherText.buffer;
|
||||
}
|
||||
case "AES-GCM": {
|
||||
normalizedAlgorithm.iv = copyBuffer(normalizedAlgorithm.iv);
|
||||
|
||||
// 1.
|
||||
if (normalizedAlgorithm.tagLength === undefined) {
|
||||
normalizedAlgorithm.tagLength = 128;
|
||||
} else if (
|
||||
!ArrayPrototypeIncludes(
|
||||
[32, 64, 96, 104, 112, 120, 128],
|
||||
normalizedAlgorithm.tagLength,
|
||||
)
|
||||
) {
|
||||
throw new DOMException(
|
||||
"Invalid tag length",
|
||||
"OperationError",
|
||||
);
|
||||
}
|
||||
|
||||
// 2.
|
||||
if (data.byteLength < normalizedAlgorithm.tagLength / 8) {
|
||||
throw new DOMException(
|
||||
"Tag length overflows ciphertext",
|
||||
"OperationError",
|
||||
);
|
||||
}
|
||||
|
||||
// 3. We only support 96-bit nonce for now.
|
||||
if (normalizedAlgorithm.iv.byteLength !== 12) {
|
||||
throw new DOMException(
|
||||
"Initialization vector length not supported",
|
||||
"NotSupportedError",
|
||||
);
|
||||
}
|
||||
|
||||
// 4.
|
||||
if (normalizedAlgorithm.additionalData !== undefined) {
|
||||
if (normalizedAlgorithm.additionalData.byteLength > (2 ** 64) - 1) {
|
||||
throw new DOMException(
|
||||
"Additional data too large",
|
||||
"OperationError",
|
||||
);
|
||||
}
|
||||
normalizedAlgorithm.additionalData = copyBuffer(
|
||||
normalizedAlgorithm.additionalData,
|
||||
);
|
||||
}
|
||||
|
||||
// 5-8.
|
||||
const plaintext = await core.opAsync("op_crypto_decrypt", {
|
||||
key: keyData,
|
||||
algorithm: "AES-GCM",
|
||||
length: key[_algorithm].length,
|
||||
iv: normalizedAlgorithm.iv,
|
||||
additionalData: normalizedAlgorithm.additionalData,
|
||||
tagLength: normalizedAlgorithm.tagLength,
|
||||
}, data);
|
||||
|
||||
// 9.
|
||||
return plaintext.buffer;
|
||||
}
|
||||
default:
|
||||
throw new DOMException("Not implemented", "NotSupportedError");
|
||||
}
|
||||
|
@ -1271,14 +1330,30 @@
|
|||
if (
|
||||
supportedAlgorithms["wrapKey"][normalizedAlgorithm.name] !== undefined
|
||||
) {
|
||||
// TODO(@littledivy): Implement this for AES-KW.
|
||||
throw new DOMException(
|
||||
"Not implemented",
|
||||
"NotSupportedError",
|
||||
);
|
||||
const handle = wrappingKey[_handle];
|
||||
const keyData = WeakMapPrototypeGet(KEY_STORE, handle);
|
||||
|
||||
switch (normalizedAlgorithm.name) {
|
||||
case "AES-KW": {
|
||||
const cipherText = await core.opSync("op_crypto_wrap_key", {
|
||||
key: keyData,
|
||||
algorithm: normalizedAlgorithm.name,
|
||||
}, bytes);
|
||||
|
||||
// 4.
|
||||
return cipherText.buffer;
|
||||
}
|
||||
default: {
|
||||
throw new DOMException(
|
||||
"Not implemented",
|
||||
"NotSupportedError",
|
||||
);
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
supportedAlgorithms["encrypt"][normalizedAlgorithm.name] !== undefined
|
||||
) {
|
||||
// must construct a new key, since keyUsages is ["wrapKey"] and not ["encrypt"]
|
||||
return await encrypt(
|
||||
normalizedAlgorithm,
|
||||
constructKey(
|
||||
|
@ -1391,14 +1466,31 @@
|
|||
if (
|
||||
supportedAlgorithms["unwrapKey"][normalizedAlgorithm.name] !== undefined
|
||||
) {
|
||||
// TODO(@littledivy): Implement this for AES-KW.
|
||||
throw new DOMException(
|
||||
"Not implemented",
|
||||
"NotSupportedError",
|
||||
);
|
||||
const handle = unwrappingKey[_handle];
|
||||
const keyData = WeakMapPrototypeGet(KEY_STORE, handle);
|
||||
|
||||
switch (normalizedAlgorithm.name) {
|
||||
case "AES-KW": {
|
||||
const plainText = await core.opSync("op_crypto_unwrap_key", {
|
||||
key: keyData,
|
||||
algorithm: normalizedAlgorithm.name,
|
||||
}, wrappedKey);
|
||||
|
||||
// 4.
|
||||
key = plainText.buffer;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new DOMException(
|
||||
"Not implemented",
|
||||
"NotSupportedError",
|
||||
);
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
supportedAlgorithms["decrypt"][normalizedAlgorithm.name] !== undefined
|
||||
) {
|
||||
// must construct a new key, since keyUsages is ["unwrapKey"] and not ["decrypt"]
|
||||
key = await this.decrypt(
|
||||
normalizedAlgorithm,
|
||||
constructKey(
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_crypto"
|
||||
version = "0.45.0"
|
||||
version = "0.46.0"
|
||||
authors = ["the Deno authors"]
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
@ -16,11 +16,12 @@ path = "lib.rs"
|
|||
[dependencies]
|
||||
aes = "0.7.5"
|
||||
aes-gcm = "0.9.4"
|
||||
aes-kw = { version = "0.1", features = ["alloc"] }
|
||||
base64 = "0.13.0"
|
||||
block-modes = "0.8.1"
|
||||
ctr = "0.8.0"
|
||||
deno_core = { version = "0.113.0", path = "../../core" }
|
||||
deno_web = { version = "0.62.0", path = "../web" }
|
||||
deno_core = { version = "0.114.0", path = "../../core" }
|
||||
deno_web = { version = "0.63.0", path = "../web" }
|
||||
elliptic-curve = { version = "0.10.6", features = ["std", "pem"] }
|
||||
num-traits = "0.2.14"
|
||||
once_cell = "=1.9.0"
|
||||
|
|
|
@ -2,8 +2,16 @@ use std::cell::RefCell;
|
|||
use std::rc::Rc;
|
||||
|
||||
use crate::shared::*;
|
||||
use aes::cipher::generic_array::GenericArray;
|
||||
use aes::Aes192;
|
||||
use aes::BlockEncrypt;
|
||||
use aes::NewBlockCipher;
|
||||
use aes_gcm::AeadCore;
|
||||
use aes_gcm::AeadInPlace;
|
||||
use aes_gcm::Aes128Gcm;
|
||||
use aes_gcm::Aes256Gcm;
|
||||
use aes_gcm::NewAead;
|
||||
use aes_gcm::Nonce;
|
||||
use block_modes::BlockMode;
|
||||
use ctr::cipher::NewCipher;
|
||||
use ctr::cipher::StreamCipher;
|
||||
|
@ -17,6 +25,7 @@ use deno_core::error::type_error;
|
|||
use deno_core::error::AnyError;
|
||||
use deno_core::OpState;
|
||||
use deno_core::ZeroCopyBuf;
|
||||
use elliptic_curve::consts::U12;
|
||||
use rsa::pkcs1::FromRsaPrivateKey;
|
||||
use rsa::PaddingScheme;
|
||||
use serde::Deserialize;
|
||||
|
@ -56,8 +65,19 @@ pub enum DecryptAlgorithm {
|
|||
ctr_length: usize,
|
||||
key_length: usize,
|
||||
},
|
||||
#[serde(rename = "AES-GCM", rename_all = "camelCase")]
|
||||
AesGcm {
|
||||
#[serde(with = "serde_bytes")]
|
||||
iv: Vec<u8>,
|
||||
#[serde(with = "serde_bytes")]
|
||||
additional_data: Option<Vec<u8>>,
|
||||
length: usize,
|
||||
tag_length: usize,
|
||||
},
|
||||
}
|
||||
|
||||
type Aes192Gcm = aes_gcm::AesGcm<Aes192, U12>;
|
||||
|
||||
pub async fn op_crypto_decrypt(
|
||||
_state: Rc<RefCell<OpState>>,
|
||||
opts: DecryptOptions,
|
||||
|
@ -76,6 +96,12 @@ pub async fn op_crypto_decrypt(
|
|||
ctr_length,
|
||||
key_length,
|
||||
} => decrypt_aes_ctr(key, key_length, &counter, ctr_length, &data),
|
||||
DecryptAlgorithm::AesGcm {
|
||||
iv,
|
||||
additional_data,
|
||||
length,
|
||||
tag_length,
|
||||
} => decrypt_aes_gcm(key, length, tag_length, iv, additional_data, &data),
|
||||
};
|
||||
let buf = tokio::task::spawn_blocking(fun).await.unwrap()?;
|
||||
Ok(buf.into())
|
||||
|
@ -195,6 +221,30 @@ where
|
|||
Ok(plaintext)
|
||||
}
|
||||
|
||||
fn decrypt_aes_gcm_gen<B>(
|
||||
key: &[u8],
|
||||
tag: &GenericArray<u8, <B as AeadCore>::TagSize>,
|
||||
nonce: &GenericArray<u8, <B as AeadCore>::NonceSize>,
|
||||
additional_data: Vec<u8>,
|
||||
plaintext: &mut [u8],
|
||||
) -> Result<(), AnyError>
|
||||
where
|
||||
B: AeadInPlace + NewAead,
|
||||
{
|
||||
let cipher =
|
||||
B::new_from_slice(key).map_err(|_| operation_error("Decryption failed"))?;
|
||||
cipher
|
||||
.decrypt_in_place_detached(
|
||||
nonce,
|
||||
additional_data.as_slice(),
|
||||
plaintext,
|
||||
tag,
|
||||
)
|
||||
.map_err(|_| operation_error("Decryption failed"))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn decrypt_aes_ctr(
|
||||
key: RawKeyData,
|
||||
key_length: usize,
|
||||
|
@ -228,3 +278,53 @@ fn decrypt_aes_ctr(
|
|||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn decrypt_aes_gcm(
|
||||
key: RawKeyData,
|
||||
length: usize,
|
||||
tag_length: usize,
|
||||
iv: Vec<u8>,
|
||||
additional_data: Option<Vec<u8>>,
|
||||
data: &[u8],
|
||||
) -> Result<Vec<u8>, AnyError> {
|
||||
let key = key.as_secret_key()?;
|
||||
let additional_data = additional_data.unwrap_or_default();
|
||||
|
||||
// Fixed 96-bit nonce
|
||||
if iv.len() != 12 {
|
||||
return Err(type_error("iv length not equal to 12"));
|
||||
}
|
||||
|
||||
let nonce = Nonce::from_slice(&iv);
|
||||
|
||||
let sep = data.len() - (tag_length / 8);
|
||||
let tag = &data[sep..];
|
||||
// The actual ciphertext, called plaintext because it is reused in place.
|
||||
let mut plaintext = data[..sep].to_vec();
|
||||
match length {
|
||||
128 => decrypt_aes_gcm_gen::<Aes128Gcm>(
|
||||
key,
|
||||
tag.into(),
|
||||
nonce,
|
||||
additional_data,
|
||||
&mut plaintext,
|
||||
)?,
|
||||
192 => decrypt_aes_gcm_gen::<Aes192Gcm>(
|
||||
key,
|
||||
tag.into(),
|
||||
nonce,
|
||||
additional_data,
|
||||
&mut plaintext,
|
||||
)?,
|
||||
256 => decrypt_aes_gcm_gen::<Aes256Gcm>(
|
||||
key,
|
||||
tag.into(),
|
||||
nonce,
|
||||
additional_data,
|
||||
&mut plaintext,
|
||||
)?,
|
||||
_ => return Err(type_error("invalid length")),
|
||||
};
|
||||
|
||||
Ok(plaintext)
|
||||
}
|
||||
|
|
14
ext/crypto/lib.deno_crypto.d.ts
vendored
14
ext/crypto/lib.deno_crypto.d.ts
vendored
|
@ -264,6 +264,7 @@ interface SubtleCrypto {
|
|||
| AlgorithmIdentifier
|
||||
| RsaOaepParams
|
||||
| AesCbcParams
|
||||
| AesGcmParams
|
||||
| AesCtrParams,
|
||||
key: CryptoKey,
|
||||
data: BufferSource,
|
||||
|
@ -293,7 +294,11 @@ interface SubtleCrypto {
|
|||
format: KeyFormat,
|
||||
key: CryptoKey,
|
||||
wrappingKey: CryptoKey,
|
||||
wrapAlgorithm: AlgorithmIdentifier | RsaOaepParams,
|
||||
wrapAlgorithm:
|
||||
| AlgorithmIdentifier
|
||||
| RsaOaepParams
|
||||
| AesCbcParams
|
||||
| AesCtrParams,
|
||||
): Promise<ArrayBuffer>;
|
||||
unwrapKey(
|
||||
format: KeyFormat,
|
||||
|
@ -302,12 +307,13 @@ interface SubtleCrypto {
|
|||
unwrapAlgorithm:
|
||||
| AlgorithmIdentifier
|
||||
| RsaOaepParams
|
||||
| AesCbcParams,
|
||||
| AesCbcParams
|
||||
| AesCtrParams,
|
||||
unwrappedKeyAlgorithm:
|
||||
| AlgorithmIdentifier
|
||||
| RsaHashedImportParams
|
||||
| HmacImportParams
|
||||
| AesKeyAlgorithm,
|
||||
| RsaHashedImportParams
|
||||
| EcImportParams,
|
||||
extractable: boolean,
|
||||
keyUsages: KeyUsage[],
|
||||
): Promise<CryptoKey>;
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use aes_kw::KekAes128;
|
||||
use aes_kw::KekAes192;
|
||||
use aes_kw::KekAes256;
|
||||
|
||||
use deno_core::error::custom_error;
|
||||
use deno_core::error::not_supported;
|
||||
use deno_core::error::type_error;
|
||||
|
@ -11,6 +15,7 @@ use deno_core::Extension;
|
|||
use deno_core::OpState;
|
||||
use deno_core::ZeroCopyBuf;
|
||||
use serde::Deserialize;
|
||||
use shared::operation_error;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::num::NonZeroU32;
|
||||
|
@ -47,6 +52,7 @@ use sha2::Digest;
|
|||
use sha2::Sha256;
|
||||
use sha2::Sha384;
|
||||
use sha2::Sha512;
|
||||
use std::convert::TryFrom;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub use rand; // Re-export rand
|
||||
|
@ -68,6 +74,7 @@ use crate::key::Algorithm;
|
|||
use crate::key::CryptoHash;
|
||||
use crate::key::CryptoNamedCurve;
|
||||
use crate::key::HkdfOutput;
|
||||
use crate::shared::RawKeyData;
|
||||
use crate::shared::ID_MFG1;
|
||||
use crate::shared::ID_P_SPECIFIED;
|
||||
use crate::shared::ID_SHA1_OID;
|
||||
|
@ -95,6 +102,8 @@ pub fn init(maybe_seed: Option<u64>) -> Extension {
|
|||
("op_crypto_decrypt", op_async(op_crypto_decrypt)),
|
||||
("op_crypto_subtle_digest", op_async(op_crypto_subtle_digest)),
|
||||
("op_crypto_random_uuid", op_sync(op_crypto_random_uuid)),
|
||||
("op_crypto_wrap_key", op_sync(op_crypto_wrap_key)),
|
||||
("op_crypto_unwrap_key", op_sync(op_crypto_unwrap_key)),
|
||||
])
|
||||
.state(move |state| {
|
||||
if let Some(seed) = maybe_seed {
|
||||
|
@ -815,6 +824,72 @@ pub async fn op_crypto_subtle_digest(
|
|||
Ok(output)
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct WrapUnwrapKeyArg {
|
||||
key: RawKeyData,
|
||||
algorithm: Algorithm,
|
||||
}
|
||||
|
||||
pub fn op_crypto_wrap_key(
|
||||
_state: &mut OpState,
|
||||
args: WrapUnwrapKeyArg,
|
||||
data: ZeroCopyBuf,
|
||||
) -> Result<ZeroCopyBuf, AnyError> {
|
||||
let algorithm = args.algorithm;
|
||||
|
||||
match algorithm {
|
||||
Algorithm::AesKw => {
|
||||
let key = args.key.as_secret_key()?;
|
||||
|
||||
if data.len() % 8 != 0 {
|
||||
return Err(type_error("Data must be multiple of 8 bytes"));
|
||||
}
|
||||
|
||||
let wrapped_key = match key.len() {
|
||||
16 => KekAes128::new(key.into()).wrap_vec(&data),
|
||||
24 => KekAes192::new(key.into()).wrap_vec(&data),
|
||||
32 => KekAes256::new(key.into()).wrap_vec(&data),
|
||||
_ => return Err(type_error("Invalid key length")),
|
||||
}
|
||||
.map_err(|_| operation_error("encryption error"))?;
|
||||
|
||||
Ok(wrapped_key.into())
|
||||
}
|
||||
_ => Err(type_error("Unsupported algorithm")),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn op_crypto_unwrap_key(
|
||||
_state: &mut OpState,
|
||||
args: WrapUnwrapKeyArg,
|
||||
data: ZeroCopyBuf,
|
||||
) -> Result<ZeroCopyBuf, AnyError> {
|
||||
let algorithm = args.algorithm;
|
||||
match algorithm {
|
||||
Algorithm::AesKw => {
|
||||
let key = args.key.as_secret_key()?;
|
||||
|
||||
if data.len() % 8 != 0 {
|
||||
return Err(type_error("Data must be multiple of 8 bytes"));
|
||||
}
|
||||
|
||||
let unwrapped_key = match key.len() {
|
||||
16 => KekAes128::new(key.into()).unwrap_vec(&data),
|
||||
24 => KekAes192::new(key.into()).unwrap_vec(&data),
|
||||
32 => KekAes256::new(key.into()).unwrap_vec(&data),
|
||||
_ => return Err(type_error("Invalid key length")),
|
||||
}
|
||||
.map_err(|_| {
|
||||
operation_error("decryption error - integrity check failed")
|
||||
})?;
|
||||
|
||||
Ok(unwrapped_key.into())
|
||||
}
|
||||
_ => Err(type_error("Unsupported algorithm")),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_declaration() -> PathBuf {
|
||||
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("lib.deno_crypto.d.ts")
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_fetch"
|
||||
version = "0.54.0"
|
||||
version = "0.55.0"
|
||||
authors = ["the Deno authors"]
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
@ -16,8 +16,8 @@ path = "lib.rs"
|
|||
[dependencies]
|
||||
bytes = "1.1.0"
|
||||
data-url = "0.1.0"
|
||||
deno_core = { version = "0.113.0", path = "../../core" }
|
||||
deno_tls = { version = "0.18.0", path = "../tls" }
|
||||
deno_core = { version = "0.114.0", path = "../../core" }
|
||||
deno_tls = { version = "0.19.0", path = "../tls" }
|
||||
dyn-clone = "1"
|
||||
http = "0.2.4"
|
||||
reqwest = { version = "0.11.7", default-features = false, features = ["rustls-tls", "stream", "gzip", "brotli"] }
|
||||
|
|
|
@ -142,6 +142,84 @@
|
|||
}
|
||||
}
|
||||
|
||||
function prepareArgs(types, args) {
|
||||
const parameters = [];
|
||||
const buffers = [];
|
||||
|
||||
for (let i = 0; i < types.length; i++) {
|
||||
const type = types[i];
|
||||
const arg = args[i];
|
||||
|
||||
if (type === "pointer") {
|
||||
if (
|
||||
arg?.buffer instanceof ArrayBuffer &&
|
||||
arg.byteLength !== undefined
|
||||
) {
|
||||
parameters.push(buffers.length);
|
||||
buffers.push(arg);
|
||||
} else if (arg instanceof UnsafePointer) {
|
||||
parameters.push(packU64(arg.value));
|
||||
buffers.push(undefined);
|
||||
} else if (arg === null) {
|
||||
parameters.push(null);
|
||||
buffers.push(undefined);
|
||||
} else {
|
||||
throw new TypeError(
|
||||
"Invalid ffi arg value, expected TypedArray, UnsafePointer or null",
|
||||
);
|
||||
}
|
||||
} else {
|
||||
parameters.push(arg);
|
||||
}
|
||||
}
|
||||
|
||||
return { parameters, buffers };
|
||||
}
|
||||
|
||||
class UnsafeFnPointer {
|
||||
pointer;
|
||||
definition;
|
||||
|
||||
constructor(pointer, definition) {
|
||||
this.pointer = pointer;
|
||||
this.definition = definition;
|
||||
}
|
||||
|
||||
call(...args) {
|
||||
const { parameters, buffers } = prepareArgs(
|
||||
this.definition.parameters,
|
||||
args,
|
||||
);
|
||||
if (this.definition.nonblocking) {
|
||||
const promise = core.opAsync("op_ffi_call_ptr_nonblocking", {
|
||||
pointer: packU64(this.pointer.value),
|
||||
def: this.definition,
|
||||
parameters,
|
||||
buffers,
|
||||
});
|
||||
|
||||
if (this.definition.result === "pointer") {
|
||||
return promise.then((value) => new UnsafePointer(unpackU64(value)));
|
||||
}
|
||||
|
||||
return promise;
|
||||
} else {
|
||||
const result = core.opSync("op_ffi_call_ptr", {
|
||||
pointer: packU64(this.pointer.value),
|
||||
def: this.definition,
|
||||
parameters,
|
||||
buffers,
|
||||
});
|
||||
|
||||
if (this.definition.result === "pointer") {
|
||||
return new UnsafePointer(unpackU64(result));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DynamicLibrary {
|
||||
#rid;
|
||||
symbols = {};
|
||||
|
@ -154,35 +232,7 @@
|
|||
const types = symbols[symbol].parameters;
|
||||
|
||||
this.symbols[symbol] = (...args) => {
|
||||
const parameters = [];
|
||||
const buffers = [];
|
||||
|
||||
for (let i = 0; i < types.length; i++) {
|
||||
const type = types[i];
|
||||
const arg = args[i];
|
||||
|
||||
if (type === "pointer") {
|
||||
if (
|
||||
arg?.buffer instanceof ArrayBuffer &&
|
||||
arg.byteLength !== undefined
|
||||
) {
|
||||
parameters.push(buffers.length);
|
||||
buffers.push(arg);
|
||||
} else if (arg instanceof UnsafePointer) {
|
||||
parameters.push(packU64(arg.value));
|
||||
buffers.push(undefined);
|
||||
} else if (arg === null) {
|
||||
parameters.push(null);
|
||||
buffers.push(undefined);
|
||||
} else {
|
||||
throw new TypeError(
|
||||
"Invalid ffi arg value, expected TypedArray, UnsafePointer or null",
|
||||
);
|
||||
}
|
||||
} else {
|
||||
parameters.push(arg);
|
||||
}
|
||||
}
|
||||
const { parameters, buffers } = prepareArgs(types, args);
|
||||
|
||||
if (isNonBlocking) {
|
||||
const promise = core.opAsync("op_ffi_call_nonblocking", {
|
||||
|
@ -228,5 +278,10 @@
|
|||
return new DynamicLibrary(pathFromURL(path), symbols);
|
||||
}
|
||||
|
||||
window.__bootstrap.ffi = { dlopen, UnsafePointer, UnsafePointerView };
|
||||
window.__bootstrap.ffi = {
|
||||
dlopen,
|
||||
UnsafePointer,
|
||||
UnsafePointerView,
|
||||
UnsafeFnPointer,
|
||||
};
|
||||
})(this);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_ffi"
|
||||
version = "0.18.0"
|
||||
version = "0.19.0"
|
||||
authors = ["the Deno authors"]
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
@ -14,7 +14,7 @@ description = "Dynamic library ffi for deno"
|
|||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
deno_core = { version = "0.113.0", path = "../../core" }
|
||||
deno_core = { version = "0.114.0", path = "../../core" }
|
||||
dlopen = "0.1.8"
|
||||
libffi = "2.0.0"
|
||||
serde = { version = "1.0.129", features = ["derive"] }
|
||||
|
|
|
@ -57,6 +57,7 @@ struct Symbol {
|
|||
result_type: NativeType,
|
||||
}
|
||||
|
||||
#[allow(clippy::non_send_fields_in_send_ty)]
|
||||
unsafe impl Send for Symbol {}
|
||||
unsafe impl Sync for Symbol {}
|
||||
|
||||
|
@ -78,18 +79,21 @@ impl Resource for DynamicLibraryResource {
|
|||
impl DynamicLibraryResource {
|
||||
fn register(
|
||||
&mut self,
|
||||
symbol: String,
|
||||
name: String,
|
||||
foreign_fn: ForeignFunction,
|
||||
) -> Result<(), AnyError> {
|
||||
let symbol = match &foreign_fn.name {
|
||||
Some(symbol) => symbol,
|
||||
None => &name,
|
||||
};
|
||||
// By default, Err returned by this function does not tell
|
||||
// which symbol wasn't exported. So we'll modify the error
|
||||
// message to include the name of symbol.
|
||||
let fn_ptr = match unsafe { self.lib.symbol::<*const c_void>(&symbol) } {
|
||||
let fn_ptr = match unsafe { self.lib.symbol::<*const c_void>(symbol) } {
|
||||
Ok(value) => Ok(value),
|
||||
Err(err) => Err(generic_error(format!(
|
||||
"Failed to register symbol {}: {}",
|
||||
symbol,
|
||||
err.to_string()
|
||||
symbol, err
|
||||
))),
|
||||
}?;
|
||||
let ptr = libffi::middle::CodePtr::from_ptr(fn_ptr as _);
|
||||
|
@ -103,7 +107,7 @@ impl DynamicLibraryResource {
|
|||
);
|
||||
|
||||
self.symbols.insert(
|
||||
symbol,
|
||||
name,
|
||||
Symbol {
|
||||
cif,
|
||||
ptr,
|
||||
|
@ -126,6 +130,11 @@ pub fn init<P: FfiPermissions + 'static>(unstable: bool) -> Extension {
|
|||
("op_ffi_load", op_sync(op_ffi_load::<P>)),
|
||||
("op_ffi_call", op_sync(op_ffi_call)),
|
||||
("op_ffi_call_nonblocking", op_async(op_ffi_call_nonblocking)),
|
||||
("op_ffi_call_ptr", op_sync(op_ffi_call_ptr)),
|
||||
(
|
||||
"op_ffi_call_ptr_nonblocking",
|
||||
op_async(op_ffi_call_ptr_nonblocking),
|
||||
),
|
||||
("op_ffi_ptr_of", op_sync(op_ffi_ptr_of::<P>)),
|
||||
("op_ffi_buf_copy_into", op_sync(op_ffi_buf_copy_into::<P>)),
|
||||
("op_ffi_cstr_read", op_sync(op_ffi_cstr_read::<P>)),
|
||||
|
@ -319,7 +328,7 @@ fn value_as_f64(value: Value) -> Result<f64, AnyError> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
|
||||
struct U32x2(u32, u32);
|
||||
|
||||
impl From<u64> for U32x2 {
|
||||
|
@ -337,6 +346,7 @@ impl From<U32x2> for u64 {
|
|||
#[derive(Deserialize, Debug)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct ForeignFunction {
|
||||
name: Option<String>,
|
||||
parameters: Vec<NativeType>,
|
||||
result: NativeType,
|
||||
}
|
||||
|
@ -464,6 +474,49 @@ struct FfiCallArgs {
|
|||
buffers: Vec<Option<ZeroCopyBuf>>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct FfiCallPtrArgs {
|
||||
pointer: U32x2,
|
||||
def: ForeignFunction,
|
||||
parameters: Vec<Value>,
|
||||
buffers: Vec<Option<ZeroCopyBuf>>,
|
||||
}
|
||||
|
||||
impl From<FfiCallPtrArgs> for FfiCallArgs {
|
||||
fn from(args: FfiCallPtrArgs) -> Self {
|
||||
FfiCallArgs {
|
||||
rid: 0,
|
||||
symbol: String::new(),
|
||||
parameters: args.parameters,
|
||||
buffers: args.buffers,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FfiCallPtrArgs {
|
||||
fn get_symbol(&self) -> Symbol {
|
||||
let fn_ptr: u64 = self.pointer.into();
|
||||
let ptr = libffi::middle::CodePtr::from_ptr(fn_ptr as _);
|
||||
let cif = libffi::middle::Cif::new(
|
||||
self
|
||||
.def
|
||||
.parameters
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(libffi::middle::Type::from),
|
||||
self.def.result.into(),
|
||||
);
|
||||
|
||||
Symbol {
|
||||
cif,
|
||||
ptr,
|
||||
parameter_types: self.def.parameters.clone(),
|
||||
result_type: self.def.result,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn ffi_call(args: FfiCallArgs, symbol: &Symbol) -> Result<Value, AnyError> {
|
||||
let buffers: Vec<Option<&[u8]>> = args
|
||||
.buffers
|
||||
|
@ -558,6 +611,26 @@ fn ffi_call(args: FfiCallArgs, symbol: &Symbol) -> Result<Value, AnyError> {
|
|||
})
|
||||
}
|
||||
|
||||
fn op_ffi_call_ptr(
|
||||
_state: &mut deno_core::OpState,
|
||||
args: FfiCallPtrArgs,
|
||||
_: (),
|
||||
) -> Result<Value, AnyError> {
|
||||
let symbol = args.get_symbol();
|
||||
ffi_call(args.into(), &symbol)
|
||||
}
|
||||
|
||||
async fn op_ffi_call_ptr_nonblocking(
|
||||
_state: Rc<RefCell<deno_core::OpState>>,
|
||||
args: FfiCallPtrArgs,
|
||||
_: (),
|
||||
) -> Result<Value, AnyError> {
|
||||
let symbol = args.get_symbol();
|
||||
tokio::task::spawn_blocking(move || ffi_call(args.into(), &symbol))
|
||||
.await
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn op_ffi_call(
|
||||
state: &mut deno_core::OpState,
|
||||
args: FfiCallArgs,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_http"
|
||||
version = "0.23.0"
|
||||
version = "0.24.0"
|
||||
authors = ["the Deno authors"]
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
@ -16,8 +16,8 @@ path = "lib.rs"
|
|||
[dependencies]
|
||||
base64 = "0.13.0"
|
||||
bytes = "1"
|
||||
deno_core = { version = "0.113.0", path = "../../core" }
|
||||
deno_websocket = { version = "0.36.0", path = "../websocket" }
|
||||
deno_core = { version = "0.114.0", path = "../../core" }
|
||||
deno_websocket = { version = "0.37.0", path = "../websocket" }
|
||||
hyper = { version = "0.14.9", features = ["server", "stream", "http1", "http2", "runtime"] }
|
||||
ring = "0.16.20"
|
||||
serde = { version = "1.0.129", features = ["derive"] }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_net"
|
||||
version = "0.23.0"
|
||||
version = "0.24.0"
|
||||
authors = ["the Deno authors"]
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
@ -14,8 +14,8 @@ description = "Networking for Deno"
|
|||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
deno_core = { version = "0.113.0", path = "../../core" }
|
||||
deno_tls = { version = "0.18.0", path = "../tls" }
|
||||
deno_core = { version = "0.114.0", path = "../../core" }
|
||||
deno_tls = { version = "0.19.0", path = "../tls" }
|
||||
log = "0.4.14"
|
||||
serde = { version = "1.0.129", features = ["derive"] }
|
||||
tokio = { version = "1.10.1", features = ["full"] }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_timers"
|
||||
version = "0.29.0"
|
||||
version = "0.30.0"
|
||||
authors = ["the Deno authors"]
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
@ -14,14 +14,14 @@ description = "Timers API implementation for Deno"
|
|||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
deno_core = { version = "0.113.0", path = "../../core" }
|
||||
deno_core = { version = "0.114.0", path = "../../core" }
|
||||
tokio = { version = "1.10.1", features = ["full"] }
|
||||
|
||||
[dev-dependencies]
|
||||
deno_bench_util = { version = "0.25.0", path = "../../bench_util" }
|
||||
deno_url = { version = "0.31.0", path = "../url" }
|
||||
deno_web = { version = "0.62.0", path = "../web" }
|
||||
deno_webidl = { version = "0.31.0", path = "../webidl" }
|
||||
deno_bench_util = { version = "0.26.0", path = "../../bench_util" }
|
||||
deno_url = { version = "0.32.0", path = "../url" }
|
||||
deno_web = { version = "0.63.0", path = "../web" }
|
||||
deno_webidl = { version = "0.32.0", path = "../webidl" }
|
||||
|
||||
[[bench]]
|
||||
name = "timers_ops"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_tls"
|
||||
version = "0.18.0"
|
||||
version = "0.19.0"
|
||||
authors = ["the Deno authors"]
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
@ -14,7 +14,7 @@ description = "TLS for Deno"
|
|||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
deno_core = { version = "0.113.0", path = "../../core" }
|
||||
deno_core = { version = "0.114.0", path = "../../core" }
|
||||
once_cell = "=1.9.0"
|
||||
rustls = { version = "0.20", features = ["dangerous_configuration"] }
|
||||
rustls-native-certs = "0.6.1"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_url"
|
||||
version = "0.31.0"
|
||||
version = "0.32.0"
|
||||
authors = ["the Deno authors"]
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
@ -14,14 +14,14 @@ description = "URL API implementation for Deno"
|
|||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
deno_core = { version = "0.113.0", path = "../../core" }
|
||||
deno_core = { version = "0.114.0", path = "../../core" }
|
||||
serde = { version = "1.0.129", features = ["derive"] }
|
||||
serde_repr = "0.1.7"
|
||||
urlpattern = "0.1.2"
|
||||
urlpattern = "0.1.3"
|
||||
|
||||
[dev-dependencies]
|
||||
deno_bench_util = { version = "0.25.0", path = "../../bench_util" }
|
||||
deno_webidl = { version = "0.31.0", path = "../webidl" }
|
||||
deno_bench_util = { version = "0.26.0", path = "../../bench_util" }
|
||||
deno_webidl = { version = "0.32.0", path = "../webidl" }
|
||||
|
||||
[[bench]]
|
||||
name = "url_ops"
|
||||
|
|
|
@ -29,8 +29,10 @@
|
|||
* @returns {string}
|
||||
*/
|
||||
function atob(data) {
|
||||
const prefix = "Failed to execute 'atob'";
|
||||
webidl.requiredArguments(arguments.length, 1, { prefix });
|
||||
data = webidl.converters.DOMString(data, {
|
||||
prefix: "Failed to execute 'atob'",
|
||||
prefix,
|
||||
context: "Argument 1",
|
||||
});
|
||||
|
||||
|
|
|
@ -279,6 +279,7 @@
|
|||
const _pullAlgorithm = Symbol("[[pullAlgorithm]]");
|
||||
const _pulling = Symbol("[[pulling]]");
|
||||
const _pullSteps = Symbol("[[PullSteps]]");
|
||||
const _releaseSteps = Symbol("[[ReleaseSteps]]");
|
||||
const _queue = Symbol("[[queue]]");
|
||||
const _queueTotalSize = Symbol("[[queueTotalSize]]");
|
||||
const _readable = Symbol("[[readable]]");
|
||||
|
@ -800,12 +801,19 @@
|
|||
"The BYOB request's buffer has been detached and so cannot be filled with an enqueued chunk",
|
||||
);
|
||||
}
|
||||
readableByteStreamControllerInvalidateBYOBRequest(controller);
|
||||
firstPendingPullInto.buffer = transferArrayBuffer(
|
||||
firstPendingPullInto.buffer,
|
||||
);
|
||||
if (firstPendingPullInto.readerType === "none") {
|
||||
readableByteStreamControllerEnqueueDetachedPullIntoToQueue(
|
||||
controller,
|
||||
firstPendingPullInto,
|
||||
);
|
||||
}
|
||||
}
|
||||
readableByteStreamControllerInvalidateBYOBRequest(controller);
|
||||
if (readableStreamHasDefaultReader(stream)) {
|
||||
readableByteStreamControllerProcessReadRequestsUsingQueue(controller);
|
||||
if (readableStreamGetNumReadRequests(stream) === 0) {
|
||||
assert(controller[_pendingPullIntos].length === 0);
|
||||
readableByteStreamControllerEnqueueChunkToQueue(
|
||||
|
@ -866,6 +874,54 @@
|
|||
controller[_queueTotalSize] += byteLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ReadableByteStreamController} controller
|
||||
* @param {ArrayBufferLike} buffer
|
||||
* @param {number} byteOffset
|
||||
* @param {number} byteLength
|
||||
* @returns {void}
|
||||
*/
|
||||
function readableByteStreamControllerEnqueueClonedChunkToQueue(
|
||||
controller,
|
||||
buffer,
|
||||
byteOffset,
|
||||
byteLength,
|
||||
) {
|
||||
let cloneResult;
|
||||
try {
|
||||
cloneResult = buffer.slice(byteOffset, byteOffset + byteLength);
|
||||
} catch (e) {
|
||||
readableByteStreamControllerError(controller, e);
|
||||
}
|
||||
readableByteStreamControllerEnqueueChunkToQueue(
|
||||
controller,
|
||||
cloneResult,
|
||||
0,
|
||||
byteLength,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ReadableByteStreamController} controller
|
||||
* @param {PullIntoDescriptor} pullIntoDescriptor
|
||||
* @returns {void}
|
||||
*/
|
||||
function readableByteStreamControllerEnqueueDetachedPullIntoToQueue(
|
||||
controller,
|
||||
pullIntoDescriptor,
|
||||
) {
|
||||
assert(pullIntoDescriptor.readerType === "none");
|
||||
if (pullIntoDescriptor.bytesFilled > 0) {
|
||||
readableByteStreamControllerEnqueueClonedChunkToQueue(
|
||||
controller,
|
||||
pullIntoDescriptor.buffer,
|
||||
pullIntoDescriptor.byteOffset,
|
||||
pullIntoDescriptor.bytesFilled,
|
||||
);
|
||||
}
|
||||
readableByteStreamControllerShiftPendingPullInto(controller);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ReadableByteStreamController} controller
|
||||
* @returns {ReadableStreamBYOBRequest | null}
|
||||
|
@ -1000,10 +1056,11 @@
|
|||
readableStreamClose(stream);
|
||||
const reader = stream[_reader];
|
||||
if (reader !== undefined && isReadableStreamBYOBReader(reader)) {
|
||||
for (const readIntoRequest of reader[_readIntoRequests]) {
|
||||
const readIntoRequests = reader[_readIntoRequests];
|
||||
reader[_readIntoRequests] = [];
|
||||
for (const readIntoRequest of readIntoRequests) {
|
||||
readIntoRequest.closeSteps(undefined);
|
||||
}
|
||||
reader[_readIntoRequests] = [];
|
||||
}
|
||||
/** @type {Promise<void>} */
|
||||
const sourceCancelPromise = stream[_controller][_cancelSteps](reason);
|
||||
|
@ -1026,10 +1083,10 @@
|
|||
if (isReadableStreamDefaultReader(reader)) {
|
||||
/** @type {Array<ReadRequest<R>>} */
|
||||
const readRequests = reader[_readRequests];
|
||||
reader[_readRequests] = [];
|
||||
for (const readRequest of readRequests) {
|
||||
readRequest.closeSteps();
|
||||
}
|
||||
reader[_readRequests] = [];
|
||||
}
|
||||
// This promise can be double resolved.
|
||||
// See: https://github.com/whatwg/streams/issues/1100
|
||||
|
@ -1224,6 +1281,27 @@
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ReadableStreamBYOBReader} reader
|
||||
*/
|
||||
function readableStreamBYOBReaderRelease(reader) {
|
||||
readableStreamReaderGenericRelease(reader);
|
||||
const e = new TypeError("The reader was released.");
|
||||
readableStreamBYOBReaderErrorReadIntoRequests(reader, e);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ReadableStreamBYOBReader} reader
|
||||
* @param {any} e
|
||||
*/
|
||||
function readableStreamDefaultReaderErrorReadRequests(reader, e) {
|
||||
const readRequests = reader[_readRequests];
|
||||
reader[_readRequests] = [];
|
||||
for (const readRequest of readRequests) {
|
||||
readRequest.errorSteps(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ReadableByteStreamController} controller
|
||||
*/
|
||||
|
@ -1250,6 +1328,25 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param {ReadableByteStreamController} controller
|
||||
*/
|
||||
function readableByteStreamControllerProcessReadRequestsUsingQueue(
|
||||
controller,
|
||||
) {
|
||||
const reader = controller[_stream][_reader];
|
||||
assert(isReadableStreamDefaultReader(reader));
|
||||
while (reader[_readRequests].length !== 0) {
|
||||
if (controller[_queueTotalSize] === 0) {
|
||||
return;
|
||||
}
|
||||
const readRequest = ArrayPrototypeShift(reader[_readRequests]);
|
||||
readableByteStreamControllerFillReadRequestFromQueue(
|
||||
controller,
|
||||
readRequest,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ReadableByteStreamController} controller
|
||||
|
@ -1401,6 +1498,16 @@
|
|||
bytesWritten,
|
||||
pullIntoDescriptor,
|
||||
);
|
||||
if (pullIntoDescriptor.readerType === "none") {
|
||||
readableByteStreamControllerEnqueueDetachedPullIntoToQueue(
|
||||
controller,
|
||||
pullIntoDescriptor,
|
||||
);
|
||||
readableByteStreamControllerProcessPullIntoDescriptorsUsingQueue(
|
||||
controller,
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (pullIntoDescriptor.bytesFilled < pullIntoDescriptor.elementSize) {
|
||||
return;
|
||||
}
|
||||
|
@ -1410,16 +1517,11 @@
|
|||
if (remainderSize > 0) {
|
||||
const end = pullIntoDescriptor.byteOffset +
|
||||
pullIntoDescriptor.bytesFilled;
|
||||
// We dont have access to CloneArrayBuffer, so we use .slice(). End is non-inclusive, as the spec says.
|
||||
const remainder = pullIntoDescriptor.buffer.slice(
|
||||
end - remainderSize,
|
||||
end,
|
||||
);
|
||||
readableByteStreamControllerEnqueueChunkToQueue(
|
||||
readableByteStreamControllerEnqueueClonedChunkToQueue(
|
||||
controller,
|
||||
remainder,
|
||||
0,
|
||||
remainder.byteLength,
|
||||
pullIntoDescriptor.buffer,
|
||||
end - remainderSize,
|
||||
remainderSize,
|
||||
);
|
||||
}
|
||||
pullIntoDescriptor.bytesFilled -= remainderSize;
|
||||
|
@ -1484,6 +1586,9 @@
|
|||
firstDescriptor,
|
||||
) {
|
||||
assert(firstDescriptor.bytesFilled === 0);
|
||||
if (firstDescriptor.readerType === "none") {
|
||||
readableByteStreamControllerShiftPendingPullInto(controller);
|
||||
}
|
||||
const stream = controller[_stream];
|
||||
if (readableStreamHasBYOBReader(stream)) {
|
||||
while (readableStreamGetNumReadIntoRequests(stream) > 0) {
|
||||
|
@ -1507,6 +1612,7 @@
|
|||
pullIntoDescriptor,
|
||||
) {
|
||||
assert(stream[_state] !== "errored");
|
||||
assert(pullIntoDescriptor.readerType !== "none");
|
||||
let done = false;
|
||||
if (stream[_state] === "closed") {
|
||||
assert(pullIntoDescriptor.bytesFilled === 0);
|
||||
|
@ -1650,6 +1756,27 @@
|
|||
return ready;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ReadableByteStreamController} controller
|
||||
* @param {ReadRequest} readRequest
|
||||
* @returns {void}
|
||||
*/
|
||||
function readableByteStreamControllerFillReadRequestFromQueue(
|
||||
controller,
|
||||
readRequest,
|
||||
) {
|
||||
assert(controller[_queueTotalSize] > 0);
|
||||
const entry = ArrayPrototypeShift(controller[_queue]);
|
||||
controller[_queueTotalSize] -= entry.byteLength;
|
||||
readableByteStreamControllerHandleQueueDrain(controller);
|
||||
const view = new Uint8Array(
|
||||
entry.buffer,
|
||||
entry.byteOffset,
|
||||
entry.byteLength,
|
||||
);
|
||||
readRequest.chunkSteps(view);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ReadableByteStreamController} controller
|
||||
* @param {number} size
|
||||
|
@ -1708,6 +1835,16 @@
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @template R
|
||||
* @param {ReadableStreamDefaultReader<R>} reader
|
||||
*/
|
||||
function readableStreamDefaultReaderRelease(reader) {
|
||||
readableStreamReaderGenericRelease(reader);
|
||||
const e = new TypeError("The reader was released.");
|
||||
readableStreamDefaultReaderErrorReadRequests(reader, e);
|
||||
}
|
||||
|
||||
/**
|
||||
* @template R
|
||||
* @param {ReadableStream<R>} stream
|
||||
|
@ -1727,18 +1864,10 @@
|
|||
closedPromise.reject(e);
|
||||
setPromiseIsHandledToTrue(closedPromise.promise);
|
||||
if (isReadableStreamDefaultReader(reader)) {
|
||||
/** @type {Array<ReadRequest<R>>} */
|
||||
const readRequests = reader[_readRequests];
|
||||
for (const readRequest of readRequests) {
|
||||
readRequest.errorSteps(e);
|
||||
}
|
||||
reader[_readRequests] = [];
|
||||
readableStreamDefaultReaderErrorReadRequests(reader, e);
|
||||
} else {
|
||||
assert(isReadableStreamBYOBReader(reader));
|
||||
for (const readIntoRequest of reader[_readIntoRequests]) {
|
||||
readIntoRequest.errorSteps(e);
|
||||
}
|
||||
reader[_readIntoRequests] = [];
|
||||
readableStreamBYOBReaderErrorReadIntoRequests(reader, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2104,7 +2233,7 @@
|
|||
*/
|
||||
function finalize(isError, error) {
|
||||
writableStreamDefaultWriterRelease(writer);
|
||||
readableStreamReaderGenericRelease(reader);
|
||||
readableStreamDefaultReaderRelease(reader);
|
||||
|
||||
if (signal !== undefined) {
|
||||
signal[remove](abortAlgorithm);
|
||||
|
@ -2154,9 +2283,10 @@
|
|||
* @param {ReadableStreamGenericReader<R> | ReadableStreamBYOBReader} reader
|
||||
*/
|
||||
function readableStreamReaderGenericRelease(reader) {
|
||||
assert(reader[_stream] !== undefined);
|
||||
assert(reader[_stream][_reader] === reader);
|
||||
if (reader[_stream][_state] === "readable") {
|
||||
const stream = reader[_stream];
|
||||
assert(stream !== undefined);
|
||||
assert(stream[_reader] === reader);
|
||||
if (stream[_state] === "readable") {
|
||||
reader[_closedPromise].reject(
|
||||
new TypeError(
|
||||
"Reader was released and can no longer be used to monitor the stream's closedness.",
|
||||
|
@ -2171,10 +2301,23 @@
|
|||
);
|
||||
}
|
||||
setPromiseIsHandledToTrue(reader[_closedPromise].promise);
|
||||
reader[_stream][_reader] = undefined;
|
||||
stream[_controller][_releaseSteps]();
|
||||
stream[_reader] = undefined;
|
||||
reader[_stream] = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ReadableStreamBYOBReader} reader
|
||||
* @param {any} e
|
||||
*/
|
||||
function readableStreamBYOBReaderErrorReadIntoRequests(reader, e) {
|
||||
const readIntoRequests = reader[_readIntoRequests];
|
||||
reader[_readIntoRequests] = [];
|
||||
for (const readIntoRequest of readIntoRequests) {
|
||||
readIntoRequest.errorSteps(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @template R
|
||||
* @param {ReadableStream<R>} stream
|
||||
|
@ -2381,7 +2524,7 @@
|
|||
function pullWithDefaultReader() {
|
||||
if (isReadableStreamBYOBReader(reader)) {
|
||||
assert(reader[_readIntoRequests].length === 0);
|
||||
readableStreamReaderGenericRelease(reader);
|
||||
readableStreamBYOBReaderRelease(reader);
|
||||
reader = acquireReadableStreamDefaultReader(stream);
|
||||
forwardReaderError(reader);
|
||||
}
|
||||
|
@ -2446,7 +2589,7 @@
|
|||
function pullWithBYOBReader(view, forBranch2) {
|
||||
if (isReadableStreamDefaultReader(reader)) {
|
||||
assert(reader[_readRequests].length === 0);
|
||||
readableStreamReaderGenericRelease(reader);
|
||||
readableStreamDefaultReaderRelease(reader);
|
||||
reader = acquireReadableStreamBYOBReader(stream);
|
||||
forwardReaderError(reader);
|
||||
}
|
||||
|
@ -3982,11 +4125,11 @@
|
|||
promise.resolve(createIteratorResult(chunk, false));
|
||||
},
|
||||
closeSteps() {
|
||||
readableStreamReaderGenericRelease(reader);
|
||||
readableStreamDefaultReaderRelease(reader);
|
||||
promise.resolve(createIteratorResult(undefined, true));
|
||||
},
|
||||
errorSteps(e) {
|
||||
readableStreamReaderGenericRelease(reader);
|
||||
readableStreamDefaultReaderRelease(reader);
|
||||
promise.reject(e);
|
||||
},
|
||||
};
|
||||
|
@ -4006,11 +4149,11 @@
|
|||
assert(reader[_readRequests].length === 0);
|
||||
if (this[_preventCancel] === false) {
|
||||
const result = readableStreamReaderGenericCancel(reader, arg);
|
||||
readableStreamReaderGenericRelease(reader);
|
||||
readableStreamDefaultReaderRelease(reader);
|
||||
await result;
|
||||
return createIteratorResult(arg, true);
|
||||
}
|
||||
readableStreamReaderGenericRelease(reader);
|
||||
readableStreamDefaultReaderRelease(reader);
|
||||
return createIteratorResult(undefined, true);
|
||||
},
|
||||
}, asyncIteratorPrototype);
|
||||
|
@ -4417,12 +4560,7 @@
|
|||
if (this[_stream] === undefined) {
|
||||
return;
|
||||
}
|
||||
if (this[_readRequests].length) {
|
||||
throw new TypeError(
|
||||
"There are pending read requests, so the reader cannot be release.",
|
||||
);
|
||||
}
|
||||
readableStreamReaderGenericRelease(this);
|
||||
readableStreamDefaultReaderRelease(this);
|
||||
}
|
||||
|
||||
get closed() {
|
||||
|
@ -4544,12 +4682,7 @@
|
|||
if (this[_stream] === undefined) {
|
||||
return;
|
||||
}
|
||||
if (this[_readIntoRequests].length !== 0) {
|
||||
throw new TypeError(
|
||||
"There are pending read requests, so the reader cannot be released.",
|
||||
);
|
||||
}
|
||||
readableStreamReaderGenericRelease(this);
|
||||
readableStreamBYOBReaderRelease(this);
|
||||
}
|
||||
|
||||
get closed() {
|
||||
|
@ -4794,15 +4927,7 @@
|
|||
assert(readableStreamHasDefaultReader(stream));
|
||||
if (this[_queueTotalSize] > 0) {
|
||||
assert(readableStreamGetNumReadRequests(stream) === 0);
|
||||
const entry = ArrayPrototypeShift(this[_queue]);
|
||||
this[_queueTotalSize] -= entry.byteLength;
|
||||
readableByteStreamControllerHandleQueueDrain(this);
|
||||
const view = new Uint8Array(
|
||||
entry.buffer,
|
||||
entry.byteOffset,
|
||||
entry.byteLength,
|
||||
);
|
||||
readRequest.chunkSteps(view);
|
||||
readableByteStreamControllerFillReadRequestFromQueue(this, readRequest);
|
||||
return;
|
||||
}
|
||||
const autoAllocateChunkSize = this[_autoAllocateChunkSize];
|
||||
|
@ -4830,6 +4955,15 @@
|
|||
readableStreamAddReadRequest(stream, readRequest);
|
||||
readableByteStreamControllerCallPullIfNeeded(this);
|
||||
}
|
||||
|
||||
[_releaseSteps]() {
|
||||
if (this[_pendingPullIntos].length !== 0) {
|
||||
/** @type {PullIntoDescriptor} */
|
||||
const firstPendingPullInto = this[_pendingPullIntos][0];
|
||||
firstPendingPullInto.readerType = "none";
|
||||
this[_pendingPullIntos] = [firstPendingPullInto];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
webidl.configurePrototype(ReadableByteStreamController);
|
||||
|
@ -4944,6 +5078,10 @@
|
|||
readableStreamDefaultControllerCallPullIfNeeded(this);
|
||||
}
|
||||
}
|
||||
|
||||
[_releaseSteps]() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
webidl.configurePrototype(ReadableStreamDefaultController);
|
||||
|
|
2
ext/web/06_streams_types.d.ts
vendored
2
ext/web/06_streams_types.d.ts
vendored
|
@ -33,7 +33,7 @@ interface PullIntoDescriptor {
|
|||
elementSize: number;
|
||||
// deno-lint-ignore no-explicit-any
|
||||
viewConstructor: any;
|
||||
readerType: "default" | "byob";
|
||||
readerType: "default" | "byob" | "none";
|
||||
}
|
||||
|
||||
interface ReadableByteStreamQueueEntry {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_web"
|
||||
version = "0.62.0"
|
||||
version = "0.63.0"
|
||||
authors = ["the Deno authors"]
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
@ -16,7 +16,7 @@ path = "lib.rs"
|
|||
[dependencies]
|
||||
async-trait = "0.1.51"
|
||||
base64 = "0.13.0"
|
||||
deno_core = { version = "0.113.0", path = "../../core" }
|
||||
deno_core = { version = "0.114.0", path = "../../core" }
|
||||
encoding_rs = "0.8.29"
|
||||
serde = "1.0.129"
|
||||
tokio = { version = "1.10.1", features = ["full"] }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_webgpu"
|
||||
version = "0.32.0"
|
||||
version = "0.33.0"
|
||||
authors = ["the Deno authors"]
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
@ -14,7 +14,7 @@ description = "WebGPU implementation for Deno"
|
|||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
deno_core = { version = "0.113.0", path = "../../core" }
|
||||
deno_core = { version = "0.114.0", path = "../../core" }
|
||||
serde = { version = "1.0.129", features = ["derive"] }
|
||||
tokio = { version = "1.10.1", features = ["full"] }
|
||||
wgpu-core = { version = "0.10.1", features = ["trace"] }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_webidl"
|
||||
version = "0.31.0"
|
||||
version = "0.32.0"
|
||||
authors = ["the Deno authors"]
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
@ -14,4 +14,4 @@ description = "WebIDL implementation for Deno"
|
|||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
deno_core = { version = "0.113.0", path = "../../core" }
|
||||
deno_core = { version = "0.114.0", path = "../../core" }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_websocket"
|
||||
version = "0.36.0"
|
||||
version = "0.37.0"
|
||||
authors = ["the Deno authors"]
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
@ -14,8 +14,8 @@ description = "Implementation of WebSocket API for Deno"
|
|||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
deno_core = { version = "0.113.0", path = "../../core" }
|
||||
deno_tls = { version = "0.18.0", path = "../tls" }
|
||||
deno_core = { version = "0.114.0", path = "../../core" }
|
||||
deno_tls = { version = "0.19.0", path = "../tls" }
|
||||
http = "0.2.4"
|
||||
hyper = { version = "0.14.12" }
|
||||
serde = { version = "1.0.129", features = ["derive"] }
|
||||
|
|
|
@ -334,7 +334,7 @@ where
|
|||
.map_err(|err| {
|
||||
DomExceptionNetworkError::new(&format!(
|
||||
"failed to connect to WebSocket: {}",
|
||||
err.to_string()
|
||||
err
|
||||
))
|
||||
})?;
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_webstorage"
|
||||
version = "0.26.0"
|
||||
version = "0.27.0"
|
||||
authors = ["the Deno authors"]
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
@ -14,7 +14,7 @@ description = "Implementation of WebStorage API for Deno"
|
|||
path = "lib.rs"
|
||||
|
||||
[dependencies]
|
||||
deno_core = { version = "0.113.0", path = "../../core" }
|
||||
deno_web = { version = "0.62.0", path = "../web" }
|
||||
deno_core = { version = "0.114.0", path = "../../core" }
|
||||
deno_web = { version = "0.63.0", path = "../web" }
|
||||
rusqlite = { version = "0.25.3", features = ["unlock_notify", "bundled"] }
|
||||
serde = { version = "1.0.129", features = ["derive"] }
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[package]
|
||||
name = "deno_runtime"
|
||||
version = "0.39.0"
|
||||
version = "0.40.0"
|
||||
authors = ["the Deno authors"]
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
@ -22,44 +22,46 @@ name = "hello_runtime"
|
|||
path = "examples/hello_runtime.rs"
|
||||
|
||||
[build-dependencies]
|
||||
deno_broadcast_channel = { version = "0.25.0", path = "../ext/broadcast_channel" }
|
||||
deno_console = { version = "0.31.0", path = "../ext/console" }
|
||||
deno_core = { version = "0.113.0", path = "../core" }
|
||||
deno_crypto = { version = "0.45.0", path = "../ext/crypto" }
|
||||
deno_fetch = { version = "0.54.0", path = "../ext/fetch" }
|
||||
deno_ffi = { version = "0.18.0", path = "../ext/ffi" }
|
||||
deno_http = { version = "0.23.0", path = "../ext/http" }
|
||||
deno_net = { version = "0.23.0", path = "../ext/net" }
|
||||
deno_timers = { version = "0.29.0", path = "../ext/timers" }
|
||||
deno_tls = { version = "0.18.0", path = "../ext/tls" }
|
||||
deno_url = { version = "0.31.0", path = "../ext/url" }
|
||||
deno_web = { version = "0.62.0", path = "../ext/web" }
|
||||
deno_webgpu = { version = "0.32.0", path = "../ext/webgpu" }
|
||||
deno_webidl = { version = "0.31.0", path = "../ext/webidl" }
|
||||
deno_websocket = { version = "0.36.0", path = "../ext/websocket" }
|
||||
deno_webstorage = { version = "0.26.0", path = "../ext/webstorage" }
|
||||
deno_broadcast_channel = { version = "0.26.0", path = "../ext/broadcast_channel" }
|
||||
deno_console = { version = "0.32.0", path = "../ext/console" }
|
||||
deno_core = { version = "0.114.0", path = "../core" }
|
||||
deno_crypto = { version = "0.46.0", path = "../ext/crypto" }
|
||||
deno_fetch = { version = "0.55.0", path = "../ext/fetch" }
|
||||
deno_ffi = { version = "0.19.0", path = "../ext/ffi" }
|
||||
deno_http = { version = "0.24.0", path = "../ext/http" }
|
||||
deno_net = { version = "0.24.0", path = "../ext/net" }
|
||||
deno_timers = { version = "0.30.0", path = "../ext/timers" }
|
||||
deno_tls = { version = "0.19.0", path = "../ext/tls" }
|
||||
deno_url = { version = "0.32.0", path = "../ext/url" }
|
||||
deno_web = { version = "0.63.0", path = "../ext/web" }
|
||||
deno_webgpu = { version = "0.33.0", path = "../ext/webgpu" }
|
||||
deno_webidl = { version = "0.32.0", path = "../ext/webidl" }
|
||||
deno_websocket = { version = "0.37.0", path = "../ext/websocket" }
|
||||
deno_webstorage = { version = "0.27.0", path = "../ext/webstorage" }
|
||||
|
||||
lzzzz = '=0.8.0'
|
||||
|
||||
[target.'cfg(windows)'.build-dependencies]
|
||||
winres = "0.1.11"
|
||||
winapi = "0.3.9"
|
||||
|
||||
[dependencies]
|
||||
deno_broadcast_channel = { version = "0.25.0", path = "../ext/broadcast_channel" }
|
||||
deno_console = { version = "0.31.0", path = "../ext/console" }
|
||||
deno_core = { version = "0.113.0", path = "../core" }
|
||||
deno_crypto = { version = "0.45.0", path = "../ext/crypto" }
|
||||
deno_fetch = { version = "0.54.0", path = "../ext/fetch" }
|
||||
deno_ffi = { version = "0.18.0", path = "../ext/ffi" }
|
||||
deno_http = { version = "0.23.0", path = "../ext/http" }
|
||||
deno_net = { version = "0.23.0", path = "../ext/net" }
|
||||
deno_timers = { version = "0.29.0", path = "../ext/timers" }
|
||||
deno_tls = { version = "0.18.0", path = "../ext/tls" }
|
||||
deno_url = { version = "0.31.0", path = "../ext/url" }
|
||||
deno_web = { version = "0.62.0", path = "../ext/web" }
|
||||
deno_webgpu = { version = "0.32.0", path = "../ext/webgpu" }
|
||||
deno_webidl = { version = "0.31.0", path = "../ext/webidl" }
|
||||
deno_websocket = { version = "0.36.0", path = "../ext/websocket" }
|
||||
deno_webstorage = { version = "0.26.0", path = "../ext/webstorage" }
|
||||
deno_broadcast_channel = { version = "0.26.0", path = "../ext/broadcast_channel" }
|
||||
deno_console = { version = "0.32.0", path = "../ext/console" }
|
||||
deno_core = { version = "0.114.0", path = "../core" }
|
||||
deno_crypto = { version = "0.46.0", path = "../ext/crypto" }
|
||||
deno_fetch = { version = "0.55.0", path = "../ext/fetch" }
|
||||
deno_ffi = { version = "0.19.0", path = "../ext/ffi" }
|
||||
deno_http = { version = "0.24.0", path = "../ext/http" }
|
||||
deno_net = { version = "0.24.0", path = "../ext/net" }
|
||||
deno_timers = { version = "0.30.0", path = "../ext/timers" }
|
||||
deno_tls = { version = "0.19.0", path = "../ext/tls" }
|
||||
deno_url = { version = "0.32.0", path = "../ext/url" }
|
||||
deno_web = { version = "0.63.0", path = "../ext/web" }
|
||||
deno_webgpu = { version = "0.33.0", path = "../ext/webgpu" }
|
||||
deno_webidl = { version = "0.32.0", path = "../ext/webidl" }
|
||||
deno_websocket = { version = "0.37.0", path = "../ext/websocket" }
|
||||
deno_webstorage = { version = "0.27.0", path = "../ext/webstorage" }
|
||||
|
||||
atty = "0.2.14"
|
||||
dlopen = "0.1.8"
|
||||
|
@ -70,6 +72,7 @@ http = "0.2.4"
|
|||
hyper = { version = "0.14.12", features = ["server", "stream", "http1", "http2", "runtime"] }
|
||||
libc = "0.2.106"
|
||||
log = "0.4.14"
|
||||
lzzzz = '=0.8.0'
|
||||
netif = "0.1.0"
|
||||
notify = "=5.0.0-pre.12"
|
||||
once_cell = "=1.9.0"
|
||||
|
|
|
@ -37,7 +37,32 @@ mod not_docs {
|
|||
let snapshot = js_runtime.snapshot();
|
||||
let snapshot_slice: &[u8] = &*snapshot;
|
||||
println!("Snapshot size: {}", snapshot_slice.len());
|
||||
std::fs::write(&snapshot_path, snapshot_slice).unwrap();
|
||||
|
||||
let compressed_snapshot_with_size = {
|
||||
let mut vec = vec![];
|
||||
|
||||
vec.extend_from_slice(
|
||||
&u32::try_from(snapshot.len())
|
||||
.expect("snapshot larger than 4gb")
|
||||
.to_le_bytes(),
|
||||
);
|
||||
|
||||
lzzzz::lz4_hc::compress_to_vec(
|
||||
snapshot_slice,
|
||||
&mut vec,
|
||||
lzzzz::lz4_hc::CLEVEL_MAX,
|
||||
)
|
||||
.expect("snapshot compression failed");
|
||||
|
||||
vec
|
||||
};
|
||||
|
||||
println!(
|
||||
"Snapshot compressed size: {}",
|
||||
compressed_snapshot_with_size.len()
|
||||
);
|
||||
|
||||
std::fs::write(&snapshot_path, compressed_snapshot_with_size).unwrap();
|
||||
println!("Snapshot written to: {} ", snapshot_path.display());
|
||||
}
|
||||
|
||||
|
|
|
@ -152,11 +152,7 @@ fn handle_ws_request(
|
|||
_ => http::Response::builder()
|
||||
.status(http::StatusCode::BAD_REQUEST)
|
||||
.body("Not a valid Websocket Request".into()),
|
||||
});
|
||||
|
||||
if resp.is_err() {
|
||||
return resp;
|
||||
}
|
||||
})?;
|
||||
|
||||
let (parts, _) = req.into_parts();
|
||||
let req = http::Request::from_parts(parts, body);
|
||||
|
@ -193,7 +189,7 @@ fn handle_ws_request(
|
|||
pump_websocket_messages(websocket, inbound_tx, outbound_rx).await;
|
||||
});
|
||||
|
||||
resp
|
||||
Ok(resp)
|
||||
}
|
||||
|
||||
fn handle_json_request(
|
||||
|
|
|
@ -1,14 +1,36 @@
|
|||
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
||||
use deno_core::Snapshot;
|
||||
use log::debug;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
pub static CLI_SNAPSHOT: &[u8] =
|
||||
include_bytes!(concat!(env!("OUT_DIR"), "/CLI_SNAPSHOT.bin"));
|
||||
pub static CLI_SNAPSHOT: Lazy<Box<[u8]>> = Lazy::new(
|
||||
#[allow(clippy::uninit_vec)]
|
||||
#[cold]
|
||||
#[inline(never)]
|
||||
|| {
|
||||
static COMPRESSED_CLI_SNAPSHOT: &[u8] =
|
||||
include_bytes!(concat!(env!("OUT_DIR"), "/CLI_SNAPSHOT.bin"));
|
||||
|
||||
let size =
|
||||
u32::from_le_bytes(COMPRESSED_CLI_SNAPSHOT[0..4].try_into().unwrap())
|
||||
as usize;
|
||||
let mut vec = Vec::with_capacity(size);
|
||||
|
||||
// SAFETY: vec is allocated with exact snapshot size (+ alignment)
|
||||
// SAFETY: non zeroed bytes are overwritten with decompressed snapshot
|
||||
unsafe {
|
||||
vec.set_len(size);
|
||||
}
|
||||
|
||||
lzzzz::lz4::decompress(&COMPRESSED_CLI_SNAPSHOT[4..], &mut vec).unwrap();
|
||||
|
||||
vec.into_boxed_slice()
|
||||
},
|
||||
);
|
||||
|
||||
pub fn deno_isolate_init() -> Snapshot {
|
||||
debug!("Deno isolate init with snapshots.");
|
||||
let data = CLI_SNAPSHOT;
|
||||
Snapshot::Static(data)
|
||||
Snapshot::Static(&*CLI_SNAPSHOT)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -138,6 +138,7 @@
|
|||
dlopen: __bootstrap.ffi.dlopen,
|
||||
UnsafePointer: __bootstrap.ffi.UnsafePointer,
|
||||
UnsafePointerView: __bootstrap.ffi.UnsafePointerView,
|
||||
UnsafeFnPointer: __bootstrap.ffi.UnsafeFnPointer,
|
||||
flock: __bootstrap.fs.flock,
|
||||
flockSync: __bootstrap.fs.flockSync,
|
||||
funlock: __bootstrap.fs.funlock,
|
||||
|
|
|
@ -1918,7 +1918,7 @@ fn permission_prompt(message: &str) -> bool {
|
|||
if success != TRUE {
|
||||
panic!(
|
||||
"Error flushing console input buffer: {}",
|
||||
std::io::Error::last_os_error().to_string()
|
||||
std::io::Error::last_os_error()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1941,7 +1941,7 @@ fn permission_prompt(message: &str) -> bool {
|
|||
if success != TRUE {
|
||||
panic!(
|
||||
"Error emulating enter key press: {}",
|
||||
std::io::Error::last_os_error().to_string()
|
||||
std::io::Error::last_os_error()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1954,7 +1954,7 @@ fn permission_prompt(message: &str) -> bool {
|
|||
if success != TRUE {
|
||||
panic!(
|
||||
"Error peeking console input buffer: {}",
|
||||
std::io::Error::last_os_error().to_string()
|
||||
std::io::Error::last_os_error()
|
||||
)
|
||||
}
|
||||
events_read == 0
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
||||
[package]
|
||||
name = "serde_v8"
|
||||
version = "0.24.0"
|
||||
version = "0.25.0"
|
||||
authors = ["the Deno authors"]
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
|
||||
|
||||
use std::os::raw::c_void;
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
|
||||
|
@ -101,3 +102,13 @@ pub extern "C" fn nonblocking_buffer(ptr: *const u8, len: usize) {
|
|||
let buf = unsafe { std::slice::from_raw_parts(ptr, len) };
|
||||
assert_eq!(buf, vec![1, 2, 3, 4, 5, 6, 7, 8]);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn get_add_u32_ptr() -> *const c_void {
|
||||
add_u32 as *const c_void
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn get_sleep_blocking_ptr() -> *const c_void {
|
||||
sleep_blocking as *const c_void
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ remote.symbols.method14(null);
|
|||
remote.symbols.method14(0);
|
||||
|
||||
// @ts-expect-error: Invalid argument
|
||||
remote.symbols.method15(null);
|
||||
remote.symbols.method15(0);
|
||||
remote.symbols.method15(new Uint16Array(1));
|
||||
remote.symbols.method15({} as Deno.UnsafePointer);
|
||||
|
||||
|
@ -109,3 +109,15 @@ const result4 = remote.symbols.method19();
|
|||
// @ts-expect-error: Invalid argument
|
||||
result4.then((_0: Deno.TypedArray) => {});
|
||||
result4.then((_1: Deno.UnsafePointer) => {});
|
||||
|
||||
const ptr = new Deno.UnsafePointer(0n);
|
||||
const fnptr = new Deno.UnsafeFnPointer(
|
||||
ptr,
|
||||
{
|
||||
parameters: ["u32", "pointer"],
|
||||
result: "void",
|
||||
} as const,
|
||||
);
|
||||
// @ts-expect-error: Invalid argument
|
||||
fnptr.call(null, null);
|
||||
fnptr.call(0, null);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue