1
0
Fork 0
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:
Ryan Dahl 2022-01-15 11:13:46 -05:00
commit a91fbcc4e7
106 changed files with 3795 additions and 3060 deletions

View file

@ -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' &&

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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

View file

@ -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)

View file

@ -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]]

View file

@ -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"

View file

@ -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 }))
}),
},
])
}
}

View file

@ -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");
}
}

View file

@ -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()
}
}

View file

@ -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"),
);
}

View file

@ -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"
}
}),
)

View file

@ -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": {

View file

@ -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());
}

View file

@ -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)))
}
}

View file

@ -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);

View file

@ -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",

View file

@ -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;
}

View file

@ -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 */

View file

@ -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::*;

View file

@ -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);
}
}

File diff suppressed because it is too large Load diff

View file

@ -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),
));
}
}

View file

@ -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;

View file

@ -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);
}
}
}

View file

@ -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()));

View file

@ -80,6 +80,7 @@ impl CacheServer {
maybe_resolver,
None,
None,
None,
)
.await;

View file

@ -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());
}
}
}

View file

@ -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()

View file

@ -588,8 +588,8 @@ pub(crate) fn to_hover_text(
"blob" => "_(a blob url)_".to_string(),
_ => format!(
"{}&#8203;{}",
specifier[..url::Position::AfterScheme].to_string(),
specifier[url::Position::AfterScheme..].to_string()
&specifier[..url::Position::AfterScheme],
&specifier[url::Position::AfterScheme..],
)
.replace('@', "&#8203;@"),
},

View file

@ -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;
}

View file

@ -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))),

View file

@ -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();

View file

@ -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() {

View file

@ -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())
}
}

View file

@ -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",
});

View file

@ -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");

View file

@ -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());
}

View file

@ -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()

View 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]

View file

@ -1,5 +1,5 @@
{
"imports": {
"std/": "https://deno.land/std@0.120.0/"
"std/": "https://deno.land/std@0.121.0/"
}
}

View file

@ -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));

View file

@ -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"]);
},

View file

@ -0,0 +1,8 @@
import { test } from "./mod.js";
Deno.test({
name: "bugrepo a",
fn: () => {
test(true);
},
});

View file

@ -0,0 +1,8 @@
import { test } from "./mod.js";
Deno.test({
name: "bugrepo b",
fn: () => {
test(false);
},
});

View 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

View file

@ -0,0 +1 @@
cover [WILDCARD]/multifile/mod.js ... 100.000% (7/7)

View file

@ -0,0 +1,6 @@
export function test(a) {
if (a) {
return 0;
}
return 1;
}

View file

@ -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));
});

View 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
View 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);
}
}

View file

@ -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 {

View 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);
}
}

View file

@ -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 =

View file

@ -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
);
}

View file

@ -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!(

View file

@ -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)]
{

View file

@ -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)?;

View file

@ -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!({

View file

@ -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"

View file

@ -372,6 +372,7 @@ impl ErrWithV8Handle {
}
}
#[allow(clippy::non_send_fields_in_send_ty)]
unsafe impl Send for ErrWithV8Handle {}
unsafe impl Sync for ErrWithV8Handle {}

View file

@ -43,7 +43,7 @@ impl fmt::Display for ModuleResolutionError {
specifier,
match maybe_referrer {
Some(referrer) => format!(" from \"{}\"", referrer),
None => format!(""),
None => String::new(),
}
),
}

View file

@ -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"] }

View file

@ -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" }

View file

@ -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(

View file

@ -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"

View file

@ -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)
}

View file

@ -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>;

View file

@ -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")
}

View file

@ -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"] }

View file

@ -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);

View file

@ -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"] }

View file

@ -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,

View file

@ -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"] }

View file

@ -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"] }

View file

@ -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"

View file

@ -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"

View file

@ -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"

View file

@ -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",
});

View file

@ -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);

View file

@ -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 {

View file

@ -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"] }

View file

@ -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"] }

View file

@ -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" }

View file

@ -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"] }

View file

@ -334,7 +334,7 @@ where
.map_err(|err| {
DomExceptionNetworkError::new(&format!(
"failed to connect to WebSocket: {}",
err.to_string()
err
))
})?;

View file

@ -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"] }

View file

@ -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"

View file

@ -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());
}

View file

@ -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(

View file

@ -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)]

View file

@ -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,

View file

@ -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

View file

@ -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"

View file

@ -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
}

View file

@ -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