From 0c80a0b3080521b20048899d61e093716519d018 Mon Sep 17 00:00:00 2001 From: iykekings Date: Fri, 5 Jun 2020 15:12:09 +0100 Subject: [PATCH 01/44] first working draft --- cli/doctest_runner.rs | 223 ++++++++++++++++++++++++++++++++++++++++++ cli/flags.rs | 77 +++++++++++++++ cli/js/testing.ts | 22 +++-- cli/main.rs | 62 ++++++++++++ cli/test_runner.rs | 2 +- 5 files changed, 376 insertions(+), 10 deletions(-) create mode 100644 cli/doctest_runner.rs diff --git a/cli/doctest_runner.rs b/cli/doctest_runner.rs new file mode 100644 index 00000000000000..c55f3d923945c4 --- /dev/null +++ b/cli/doctest_runner.rs @@ -0,0 +1,223 @@ +use regex::Regex; +use std::path::{Path, PathBuf}; + +use crate::fs as deno_fs; +use crate::installer::is_remote_url; +use crate::test_runner::is_supported; + +pub struct DocTest { + // This removes repetition of imports in a file + imports: std::collections::HashSet, + // This contains codes in an @example section with their imports removed + bodies: Vec, +} + +struct DocTestBody { + caption: String, + line_number: usize, + path: PathBuf, + value: String, + ignore: bool, + is_async: bool, +} + +pub fn prepare_doctest( + include: Vec, + // root_path: &PathBuf, +) -> Vec { + let include_paths: Vec<_> = + include.into_iter().filter(|n| !is_remote_url(n)).collect(); + + let mut prepared = vec![]; + + for path in include_paths { + let p = deno_fs::normalize_path(&Path::new(&path)); + if p.is_dir() { + let test_files = crate::fs::files_in_subtree(p, |p| { + let supported_files = ["ts", "tsx", "js", "jsx"]; + match p.extension().and_then(std::ffi::OsStr::to_str) { + Some(x) => supported_files.contains(&x) && !is_supported(p), + _ => false, + } + }); + prepared.extend(test_files); + } else { + prepared.push(p); + } + } + + prepared + .iter() + .filter_map(|dir| { + // TODO(iykekings) use deno error instead + let content = std::fs::read_to_string(&dir).expect( + format!("File doesn't exist {}", dir.to_str().unwrap_or("")).as_str(), + ); + extract_jsdoc_examples(content, dir.to_owned()) + }) + .collect::>() +} + +fn extract_jsdoc_examples(input: String, p: PathBuf) -> Option { + lazy_static! { + static ref JS_DOC_PATTERN: Regex = + Regex::new(r"/\*\*\s*\n([^\*]|\*[^/])*\*/").unwrap(); + // IMPORT_PATTERN doesn't match dynamic imports + static ref IMPORT_PATTERN: Regex = + Regex::new(r"import[^(].*\n").unwrap(); + static ref EXAMPLE_PATTERN: Regex = Regex::new(r"@example\s*(?:<\w+>.*)*\n(?:\s*\*\s*\n*)*```").unwrap(); + static ref TICKS_OR_IMPORT_PATTERN: Regex = Regex::new(r"(?:import[^(].*)|(?:```\w*)").unwrap(); + static ref CAPTION_PATTERN: Regex = Regex::new(r"([\s\w\W]+)").unwrap(); + static ref TEST_TAG_PATTERN: Regex = Regex::new(r"@example\s*(?:<\w+>.*)*\n(?:\s*\*\s*\n*)*```(\w+)").unwrap(); + static ref AWAIT_PATTERN: Regex = Regex::new(r"\Wawait\s").unwrap(); + } + + let mut import_set = std::collections::HashSet::new(); + + let test_bodies = JS_DOC_PATTERN + .captures_iter(&input) + .filter_map(|caps| caps.get(0).map(|c| (c.start(), c.as_str()))) + .flat_map(|(offset, section)| { + EXAMPLE_PATTERN.find_iter(section).filter_map(move |cap| { + section[cap.end()..].find("```").map(|i| { + ( + offset + cap.end(), + section[cap.start()..i + cap.end()].to_string(), + ) + }) + }) + }) + .filter_map(|(offset, example_section)| { + let test_tag = TEST_TAG_PATTERN + .captures(&example_section) + .and_then(|m| m.get(1).map(|c| c.as_str())); + + if test_tag == Some("text") { + return None; + } + + IMPORT_PATTERN + .captures_iter(&example_section) + .filter_map(|caps| caps.get(0).map(|m| m.as_str())) + .for_each(|import| { + import_set.insert(import.to_string()); + }); + + let caption = CAPTION_PATTERN + .captures(&example_section) + .and_then(|cap| cap.get(1).map(|m| m.as_str())) + .unwrap_or(""); + + let line_number = &input[0..offset].lines().count(); + + let body = TICKS_OR_IMPORT_PATTERN + .replace_all(&example_section, "\n") + .lines() + .skip(1) + .filter_map(|line| { + let res = match line.trim_start().starts_with("*") { + true => line.replacen("*", "", 1).trim_start().to_string(), + false => line.trim_start().to_string(), + }; + match res.len() { + 0 => None, + _ => Some(format!(" {}", res)), + } + }) + .collect::>() + .join("\n"); + let is_async = match AWAIT_PATTERN.find(&example_section) { + Some(_) => true, + _ => false, + }; + Some(DocTestBody { + caption: caption.to_owned(), + line_number: line_number.clone(), + path: p.clone(), + value: body, + ignore: test_tag == Some("ignore"), + is_async, + }) + }) + .collect::>(); + + match test_bodies.len() { + 0 => None, + _ => Some(DocTest { + imports: import_set, + bodies: test_bodies, + }), + } +} + +pub fn render_doctest_file( + doctests: Vec, + fail_fast: bool, + quiet: bool, + filter: Option, +) -> String { + let mut test_file = "".to_string(); + + // TODO(iykekings) - discuss with team if this is fine + let default_import = "import { + assert, + assertArrayContains, + assertEquals, + assertMatch, + assertNotEquals, + assertStrContains, + assertStrictEq, + assertThrows, + assertThrowsAsync, + equal, + unimplemented, + unreachable, + } from \"https://deno.land/std/testing/asserts.ts\";\n"; + + test_file.push_str(default_import); + + let all_imports: String = doctests + .iter() + .map(|doctest| doctest.imports.clone()) + .flatten() + .collect(); + + test_file.push_str(&all_imports); + test_file.push_str("\n"); + + let all_test_section = doctests + .into_iter() + .map(|doctest| doctest.bodies.into_iter()) + .flatten() + .map(|test| { + let async_str = if test.is_async {"async "} else {""}; + format!( + "Deno.test({{\n\tname: \"{} -> {} (line {})\",\n\tignore: {},\n\t{}fn() {{\n{}\n}}\n}});\n", + test.path.display(), + test.caption, + test.line_number, + test.ignore, + async_str, + test.value + ) + }) + .collect::>() + .join("\n"); + + test_file.push_str(&all_test_section); + + let options = if let Some(filter) = filter { + json!({ "failFast": fail_fast, "reportToConsole": !quiet, "disableLog": quiet, "isDoctest": true, "filter": filter }) + } else { + json!({ "failFast": fail_fast, "reportToConsole": !quiet, "disableLog": quiet, "isDoctest": true }) + }; + + let run_tests_cmd = format!( + "\n// @ts-ignore\nDeno[Deno.internal].runTests({});\n", + options + ); + + test_file.push_str(&run_tests_cmd); + + test_file +} diff --git a/cli/flags.rs b/cli/flags.rs index 075a29b5d475a0..3584c40e13dce3 100644 --- a/cli/flags.rs +++ b/cli/flags.rs @@ -28,6 +28,13 @@ pub enum DenoSubcommand { source_file: Option, filter: Option, }, + Doctest { + fail_fast: bool, + quiet: bool, + allow_none: bool, + include: Option>, + filter: Option, + }, Eval { code: String, as_typescript: bool, @@ -260,6 +267,8 @@ pub fn flags_from_vec_safe(args: Vec) -> clap::Result { upgrade_parse(&mut flags, m); } else if let Some(m) = matches.subcommand_matches("doc") { doc_parse(&mut flags, m); + } else if let Some(m) = matches.subcommand_matches("doctest") { + doctest_parse(&mut flags, m); } else { repl_parse(&mut flags, &matches); } @@ -314,6 +323,7 @@ If the flag is set, restrict these messages to errors.", .subcommand(types_subcommand()) .subcommand(upgrade_subcommand()) .subcommand(doc_subcommand()) + .subcommand(doctest_subcommand()) .long_about(DENO_HELP) .after_help(ENV_VARIABLES_HELP) } @@ -584,6 +594,33 @@ fn doc_parse(flags: &mut Flags, matches: &clap::ArgMatches) { }; } +fn doctest_parse(flags: &mut Flags, matches: &clap::ArgMatches) { + run_test_args_parse(flags, matches); + + let failfast = matches.is_present("failfast"); + let allow_none = matches.is_present("allow_none"); + let quiet = matches.is_present("quiet"); + let filter = matches.value_of("filter").map(String::from); + let include = if matches.is_present("files") { + let files: Vec = matches + .values_of("files") + .unwrap() + .map(String::from) + .collect(); + Some(files) + } else { + None + }; + + flags.subcommand = DenoSubcommand::Doctest { + include, + fail_fast: failfast, + quiet, + filter, + allow_none, + }; +} + fn types_subcommand<'a, 'b>() -> App<'a, 'b> { SubCommand::with_name("types") .arg(unstable_arg()) @@ -886,6 +923,46 @@ Show documentation for runtime built-ins: ) } +fn doctest_subcommand<'a, 'b>() -> App<'a, 'b> { + run_test_args(SubCommand::with_name("doctest")) + .arg( + Arg::with_name("failfast") + .long("failfast") + .help("Stop on first error") + .takes_value(false), + ) + .arg( + Arg::with_name("allow_none") + .long("allow-none") + .help("Don't return error code if no files with doctests are found") + .takes_value(false), + ) + .arg( + Arg::with_name("filter") + .long("filter") + .takes_value(true) + .help("A pattern to filter the doctests to run by"), + ) + .arg( + Arg::with_name("files") + .help("List of file names to run") + .takes_value(true) + .multiple(true), + ) + .about("Run Doctests") + .long_about( + "Run doctests using Deno's built-in doctest runner. + +Evaluate the given modules, run all doctests declared in JSDoc @example block and +report results to standard output: + deno doctest src/fetch.ts src/signal.ts + +Directory arguments are expanded to all contained files matching the glob +{*_,*.,}.{js,ts,jsx,tsx} except test files: + deno doctest src/", + ) +} + fn permission_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { app .arg( diff --git a/cli/js/testing.ts b/cli/js/testing.ts index fc32fd604f7216..757efa2f67e9e5 100644 --- a/cli/js/testing.ts +++ b/cli/js/testing.ts @@ -54,7 +54,7 @@ After: - completed: ${post.opsCompletedAsync} Make sure to await all promises returned from Deno APIs before -finishing test case.` +finishing test case.`, ); }; } @@ -63,7 +63,7 @@ finishing test case.` // the test case does not "leak" resources - ie. resource table after // the test has exactly the same contents as before the test. function assertResources( - fn: () => void | Promise + fn: () => void | Promise, ): () => void | Promise { return async function resourceSanitizer(): Promise { const pre = resources(); @@ -98,7 +98,7 @@ export function test(name: string, fn: () => void | Promise): void; // creates a new object with "name" and "fn" fields. export function test( t: string | TestDefinition, - fn?: () => void | Promise + fn?: () => void | Promise, ): void { let testDef: TestDefinition; const defaults = { @@ -174,7 +174,7 @@ function log(msg: string, noNewLine = false): void { stdout.writeSync(encoder.encode(msg)); } -function reportToConsole(message: TestMessage): void { +function reportToConsole(message: TestMessage, isDoctest: boolean): void { if (message.start != null) { log(`running ${message.start.tests.length} tests`); } else if (message.testStart != null) { @@ -212,11 +212,13 @@ function reportToConsole(message: TestMessage): void { } } log( - `\ntest result: ${message.end.failed ? RED_FAILED : GREEN_OK}. ` + + `\n${isDoctest ? "doctest" : "test"} result: ${ + message.end.failed ? RED_FAILED : GREEN_OK + }. ` + `${message.end.passed} passed; ${message.end.failed} failed; ` + `${message.end.ignored} ignored; ${message.end.measured} measured; ` + `${message.end.filtered} filtered out ` + - `${formatDuration(message.end.duration)}\n` + `${formatDuration(message.end.duration)}\n`, ); } } @@ -238,7 +240,7 @@ class TestApi { constructor( public tests: TestDefinition[], public filterFn: (def: TestDefinition) => boolean, - public failFast: boolean + public failFast: boolean, ) { this.testsToRun = tests.filter(filterFn); this.stats.filtered = tests.length - this.testsToRun.length; @@ -286,7 +288,7 @@ class TestApi { function createFilterFn( filter: undefined | string | RegExp, - skip: undefined | string | RegExp + skip: undefined | string | RegExp, ): (def: TestDefinition) => boolean { return (def: TestDefinition): boolean => { let passes = true; @@ -317,6 +319,7 @@ interface RunTestsOptions { filter?: string | RegExp; skip?: string | RegExp; disableLog?: boolean; + isDoctest?: boolean; reportToConsole?: boolean; onMessage?: (message: TestMessage) => void | Promise; } @@ -327,6 +330,7 @@ async function runTests({ filter = undefined, skip = undefined, disableLog = false, + isDoctest = false, reportToConsole: reportToConsole_ = true, onMessage = undefined, }: RunTestsOptions = {}): Promise { @@ -347,7 +351,7 @@ async function runTests({ await onMessage(message); } if (reportToConsole_) { - reportToConsole(message); + reportToConsole(message, isDoctest); } if (message.end != null) { endMsg = message.end; diff --git a/cli/main.rs b/cli/main.rs index 68ba5e7763c5c3..1d4a916d00c483 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -27,6 +27,7 @@ pub mod deno_dir; pub mod diagnostics; mod disk_cache; mod doc; +mod doctest_runner; mod file_fetcher; pub mod flags; mod fmt; @@ -497,6 +498,59 @@ async fn doc_command( } } +async fn doctest_command( + flags: Flags, + include: Option>, + fail_fast: bool, + quiet: bool, + allow_none: bool, + filter: Option, +) -> Result<(), ErrBox> { + let global_state = GlobalState::new(flags.clone())?; + let cwd = std::env::current_dir().expect("No current directory"); + let include = include.unwrap_or_else(|| vec![".".to_string()]); + let doctests = doctest_runner::prepare_doctest(include); + + if doctests.is_empty() { + println!("No matching doctest modules found"); + if !allow_none { + std::process::exit(1); + } + return Ok(()); + } + + let doctest_file_path = cwd.join(".deno_doctest.test.ts"); + let doctest_file_url = + Url::from_file_path(&doctest_file_path).expect("Should be valid file url"); + let doctest_file = + doctest_runner::render_doctest_file(doctests, fail_fast, quiet, filter); + let main_module = + ModuleSpecifier::resolve_url(&doctest_file_url.to_string()).unwrap(); + let mut worker = + create_main_worker(global_state.clone(), main_module.clone())?; + + let source_file = SourceFile { + filename: doctest_file_url.to_file_path().unwrap(), + url: doctest_file_url, + types_url: None, + types_header: None, + media_type: MediaType::TypeScript, + source_code: doctest_file.clone().into_bytes(), + }; + + worker + .state + .borrow() + .global_state + .file_fetcher + .save_source_file_in_cache(&main_module, source_file); + let execute_result = worker.execute_module(&main_module).await; + execute_result?; + worker.execute("window.dispatchEvent(new Event('load'))")?; + (&mut *worker).await?; + worker.execute("window.dispatchEvent(new Event('unload'))") +} + async fn run_repl(flags: Flags) -> Result<(), ErrBox> { let main_module = ModuleSpecifier::resolve_url_or_path("./__$deno$repl.ts").unwrap(); @@ -613,6 +667,14 @@ pub fn main() { json, filter, } => doc_command(flags, source_file, json, filter).boxed_local(), + DenoSubcommand::Doctest { + include, + fail_fast, + quiet, + allow_none, + filter, + } => doctest_command(flags, include, fail_fast, quiet, allow_none, filter) + .boxed_local(), DenoSubcommand::Eval { code, as_typescript, diff --git a/cli/test_runner.rs b/cli/test_runner.rs index 3e3ed1291ba456..51920c563a3230 100644 --- a/cli/test_runner.rs +++ b/cli/test_runner.rs @@ -7,7 +7,7 @@ use std::path::Path; use std::path::PathBuf; use url::Url; -fn is_supported(p: &Path) -> bool { +pub(crate) fn is_supported(p: &Path) -> bool { use std::path::Component; if let Some(Component::Normal(basename_os_str)) = p.components().next_back() { let basename = basename_os_str.to_string_lossy(); From 2756a4765824693749f932c1baae15bed5b8819d Mon Sep 17 00:00:00 2001 From: iykekings Date: Fri, 5 Jun 2020 17:39:41 +0100 Subject: [PATCH 02/44] use Mainwoker::create --- cli/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/main.rs b/cli/main.rs index 4220fe3174599e..9b732a6759db37 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -548,7 +548,7 @@ async fn doctest_command( let main_module = ModuleSpecifier::resolve_url(&doctest_file_url.to_string()).unwrap(); let mut worker = - create_main_worker(global_state.clone(), main_module.clone())?; + MainWorker::create(global_state.clone(), main_module.clone())?; let source_file = SourceFile { filename: doctest_file_url.to_file_path().unwrap(), From f811f16e216118cb07738dd25624bf30c3e2abe7 Mon Sep 17 00:00:00 2001 From: iykekings Date: Sat, 6 Jun 2020 05:39:25 +0100 Subject: [PATCH 03/44] format --- cli/js/testing.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cli/js/testing.ts b/cli/js/testing.ts index 50798f0231c39a..e9895c93fb0066 100644 --- a/cli/js/testing.ts +++ b/cli/js/testing.ts @@ -54,7 +54,7 @@ After: - completed: ${post.opsCompletedAsync} Make sure to await all promises returned from Deno APIs before -finishing test case.`, +finishing test case.` ); }; } @@ -63,7 +63,7 @@ finishing test case.`, // the test case does not "leak" resources - ie. resource table after // the test has exactly the same contents as before the test. function assertResources( - fn: () => void | Promise, + fn: () => void | Promise ): () => void | Promise { return async function resourceSanitizer(): Promise { const pre = resources(); @@ -98,7 +98,7 @@ export function test(name: string, fn: () => void | Promise): void; // creates a new object with "name" and "fn" fields. export function test( t: string | TestDefinition, - fn?: () => void | Promise, + fn?: () => void | Promise ): void { let testDef: TestDefinition; const defaults = { @@ -218,7 +218,7 @@ function reportToConsole(message: TestMessage, isDoctest: boolean): void { `${message.end.passed} passed; ${message.end.failed} failed; ` + `${message.end.ignored} ignored; ${message.end.measured} measured; ` + `${message.end.filtered} filtered out ` + - `${formatDuration(message.end.duration)}\n`, + `${formatDuration(message.end.duration)}\n` ); } } @@ -240,7 +240,7 @@ class TestApi { constructor( public tests: TestDefinition[], public filterFn: (def: TestDefinition) => boolean, - public failFast: boolean, + public failFast: boolean ) { this.testsToRun = tests.filter(filterFn); this.stats.filtered = tests.length - this.testsToRun.length; @@ -288,7 +288,7 @@ class TestApi { function createFilterFn( filter: undefined | string | RegExp, - skip: undefined | string | RegExp, + skip: undefined | string | RegExp ): (def: TestDefinition) => boolean { return (def: TestDefinition): boolean => { let passes = true; From 041c3681256024cde0aabcaf24f315850522cd73 Mon Sep 17 00:00:00 2001 From: Ikechukwu Eze Date: Sat, 6 Jun 2020 07:31:07 +0100 Subject: [PATCH 04/44] General refactoring (#4) * fix clippy errors * break extract_jsdoc_examples to smaller fns * fix error when ran without arguments --- cli/doctest_runner.rs | 124 ++++++++++++++++++++++++------------------ cli/main.rs | 5 +- 2 files changed, 73 insertions(+), 56 deletions(-) diff --git a/cli/doctest_runner.rs b/cli/doctest_runner.rs index c55f3d923945c4..a61da71cb3fc94 100644 --- a/cli/doctest_runner.rs +++ b/cli/doctest_runner.rs @@ -1,5 +1,7 @@ use regex::Regex; -use std::path::{Path, PathBuf}; +use std::collections::HashSet; +use std::ffi::OsStr; +use std::path::PathBuf; use crate::fs as deno_fs; use crate::installer::is_remote_url; @@ -7,7 +9,7 @@ use crate::test_runner::is_supported; pub struct DocTest { // This removes repetition of imports in a file - imports: std::collections::HashSet, + imports: HashSet, // This contains codes in an @example section with their imports removed bodies: Vec, } @@ -15,30 +17,29 @@ pub struct DocTest { struct DocTestBody { caption: String, line_number: usize, - path: PathBuf, + path: String, value: String, ignore: bool, is_async: bool, } pub fn prepare_doctest( - include: Vec, - // root_path: &PathBuf, + mut include: Vec, + root_path: &PathBuf, ) -> Vec { - let include_paths: Vec<_> = - include.into_iter().filter(|n| !is_remote_url(n)).collect(); + include.retain(|n| !is_remote_url(n)); let mut prepared = vec![]; - for path in include_paths { - let p = deno_fs::normalize_path(&Path::new(&path)); + for path in include { + let p = deno_fs::normalize_path(&root_path.join(path)); if p.is_dir() { - let test_files = crate::fs::files_in_subtree(p, |p| { - let supported_files = ["ts", "tsx", "js", "jsx"]; - match p.extension().and_then(std::ffi::OsStr::to_str) { - Some(x) => supported_files.contains(&x) && !is_supported(p), - _ => false, - } + let test_files = deno_fs::files_in_subtree(p, |p| { + let valid_ext = ["ts", "tsx", "js", "jsx"]; + p.extension() + .and_then(OsStr::to_str) + .map(|ext| valid_ext.contains(&ext) && !is_supported(p)) + .unwrap_or(false) }); prepared.extend(test_files); } else { @@ -50,9 +51,8 @@ pub fn prepare_doctest( .iter() .filter_map(|dir| { // TODO(iykekings) use deno error instead - let content = std::fs::read_to_string(&dir).expect( - format!("File doesn't exist {}", dir.to_str().unwrap_or("")).as_str(), - ); + let content = std::fs::read_to_string(&dir) + .unwrap_or_else(|_| panic!("File doesn't exist {}", dir.display())); extract_jsdoc_examples(content, dir.to_owned()) }) .collect::>() @@ -62,17 +62,15 @@ fn extract_jsdoc_examples(input: String, p: PathBuf) -> Option { lazy_static! { static ref JS_DOC_PATTERN: Regex = Regex::new(r"/\*\*\s*\n([^\*]|\*[^/])*\*/").unwrap(); - // IMPORT_PATTERN doesn't match dynamic imports + // IMPORT_PATTERN doesn't match dynamic imports by design static ref IMPORT_PATTERN: Regex = Regex::new(r"import[^(].*\n").unwrap(); static ref EXAMPLE_PATTERN: Regex = Regex::new(r"@example\s*(?:<\w+>.*)*\n(?:\s*\*\s*\n*)*```").unwrap(); - static ref TICKS_OR_IMPORT_PATTERN: Regex = Regex::new(r"(?:import[^(].*)|(?:```\w*)").unwrap(); - static ref CAPTION_PATTERN: Regex = Regex::new(r"([\s\w\W]+)").unwrap(); static ref TEST_TAG_PATTERN: Regex = Regex::new(r"@example\s*(?:<\w+>.*)*\n(?:\s*\*\s*\n*)*```(\w+)").unwrap(); static ref AWAIT_PATTERN: Regex = Regex::new(r"\Wawait\s").unwrap(); } - let mut import_set = std::collections::HashSet::new(); + let mut import_set = HashSet::new(); let test_bodies = JS_DOC_PATTERN .captures_iter(&input) @@ -103,38 +101,21 @@ fn extract_jsdoc_examples(input: String, p: PathBuf) -> Option { import_set.insert(import.to_string()); }); - let caption = CAPTION_PATTERN - .captures(&example_section) - .and_then(|cap| cap.get(1).map(|m| m.as_str())) - .unwrap_or(""); - + let caption = get_caption_from_example(&example_section); let line_number = &input[0..offset].lines().count(); - - let body = TICKS_OR_IMPORT_PATTERN - .replace_all(&example_section, "\n") - .lines() - .skip(1) - .filter_map(|line| { - let res = match line.trim_start().starts_with("*") { - true => line.replacen("*", "", 1).trim_start().to_string(), - false => line.trim_start().to_string(), - }; - match res.len() { - 0 => None, - _ => Some(format!(" {}", res)), - } - }) - .collect::>() - .join("\n"); - let is_async = match AWAIT_PATTERN.find(&example_section) { - Some(_) => true, - _ => false, - }; + let code_block = get_code_from_example(&example_section); + let is_async = AWAIT_PATTERN.find(&example_section).is_some(); + + let cwd = std::env::current_dir() + .expect("expected: process has a current working directory"); + let path = p + .to_str() + .map(|x| x.replace(cwd.to_str().unwrap_or(""), "")); Some(DocTestBody { - caption: caption.to_owned(), - line_number: line_number.clone(), - path: p.clone(), - value: body, + caption, + line_number: *line_number, + path: path.unwrap_or("".to_string()), + value: code_block, ignore: test_tag == Some("ignore"), is_async, }) @@ -192,8 +173,8 @@ pub fn render_doctest_file( .map(|test| { let async_str = if test.is_async {"async "} else {""}; format!( - "Deno.test({{\n\tname: \"{} -> {} (line {})\",\n\tignore: {},\n\t{}fn() {{\n{}\n}}\n}});\n", - test.path.display(), + "Deno.test({{\n\tname: \"{} - {} (line {})\",\n\tignore: {},\n\t{}fn() {{\n{}\n}}\n}});\n", + &test.path[1..], test.caption, test.line_number, test.ignore, @@ -221,3 +202,38 @@ pub fn render_doctest_file( test_file } + +fn get_caption_from_example(ex: &str) -> String { + lazy_static! { + static ref CAPTION_PATTERN: Regex = + Regex::new(r"([\s\w\W]+)").unwrap(); + } + CAPTION_PATTERN + .captures(ex) + .and_then(|cap| cap.get(1).map(|m| m.as_str())) + .unwrap_or("") + .to_string() +} + +fn get_code_from_example(ex: &str) -> String { + lazy_static! { + static ref TICKS_OR_IMPORT_PATTERN: Regex = + Regex::new(r"(?:import[^(].*)|(?:```\w*)").unwrap(); + } + TICKS_OR_IMPORT_PATTERN + .replace_all(ex, "\n") + .lines() + .skip(1) + .filter_map(|line| { + let res = match line.trim_start().starts_with('*') { + true => line.replacen("*", "", 1).trim_start().to_string(), + false => line.trim_start().to_string(), + }; + match res.len() { + 0 => None, + _ => Some(format!(" {}", res)), + } + }) + .collect::>() + .join("\n") +} diff --git a/cli/main.rs b/cli/main.rs index 9b732a6759db37..eb6bff8f420a85 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -528,9 +528,10 @@ async fn doctest_command( filter: Option, ) -> Result<(), ErrBox> { let global_state = GlobalState::new(flags.clone())?; - let cwd = std::env::current_dir().expect("No current directory"); + let cwd = std::env::current_dir() + .expect("expected: process has a current working directory"); let include = include.unwrap_or_else(|| vec![".".to_string()]); - let doctests = doctest_runner::prepare_doctest(include); + let doctests = doctest_runner::prepare_doctest(include, &cwd); if doctests.is_empty() { println!("No matching doctest modules found"); From 6b0004567890fd27d65be6ba6d7576f745d6e838 Mon Sep 17 00:00:00 2001 From: iykekings Date: Sat, 6 Jun 2020 07:43:12 +0100 Subject: [PATCH 05/44] make clippy happy --- cli/doctest_runner.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cli/doctest_runner.rs b/cli/doctest_runner.rs index a61da71cb3fc94..c61e994a91ebc8 100644 --- a/cli/doctest_runner.rs +++ b/cli/doctest_runner.rs @@ -114,7 +114,7 @@ fn extract_jsdoc_examples(input: String, p: PathBuf) -> Option { Some(DocTestBody { caption, line_number: *line_number, - path: path.unwrap_or("".to_string()), + path: path.unwrap_or_else(|| "".to_string()), value: code_block, ignore: test_tag == Some("ignore"), is_async, @@ -225,9 +225,10 @@ fn get_code_from_example(ex: &str) -> String { .lines() .skip(1) .filter_map(|line| { - let res = match line.trim_start().starts_with('*') { - true => line.replacen("*", "", 1).trim_start().to_string(), - false => line.trim_start().to_string(), + let res = if line.trim_start().starts_with('*') { + line.replacen("*", "", 1).trim_start().to_string() + } else { + line.trim_start().to_string() }; match res.len() { 0 => None, From dfaae34d54d3de800d4df78414dda61e4cebc288 Mon Sep 17 00:00:00 2001 From: Ikechukwu Eze Date: Sat, 6 Jun 2020 17:57:49 +0100 Subject: [PATCH 06/44] use deno test --docs (#5) --- cli/doctest_runner.rs | 2 +- cli/flags.rs | 100 +++++++++++++----------------------------- cli/main.rs | 96 ++++++++++++---------------------------- 3 files changed, 59 insertions(+), 139 deletions(-) diff --git a/cli/doctest_runner.rs b/cli/doctest_runner.rs index c61e994a91ebc8..70fea81077747f 100644 --- a/cli/doctest_runner.rs +++ b/cli/doctest_runner.rs @@ -23,7 +23,7 @@ struct DocTestBody { is_async: bool, } -pub fn prepare_doctest( +pub fn prepare_doctests( mut include: Vec, root_path: &PathBuf, ) -> Vec { diff --git a/cli/flags.rs b/cli/flags.rs index c07d64d97bbd7e..ffca3a8da8509d 100644 --- a/cli/flags.rs +++ b/cli/flags.rs @@ -61,6 +61,7 @@ pub enum DenoSubcommand { script: String, }, Test { + docs: bool, fail_fast: bool, quiet: bool, allow_none: bool, @@ -266,8 +267,6 @@ pub fn flags_from_vec_safe(args: Vec) -> clap::Result { upgrade_parse(&mut flags, m); } else if let Some(m) = matches.subcommand_matches("doc") { doc_parse(&mut flags, m); - } else if let Some(m) = matches.subcommand_matches("doctest") { - doctest_parse(&mut flags, m); } else { repl_parse(&mut flags, &matches); } @@ -322,7 +321,6 @@ If the flag is set, restrict these messages to errors.", .subcommand(types_subcommand()) .subcommand(upgrade_subcommand()) .subcommand(doc_subcommand()) - .subcommand(doctest_subcommand()) .long_about(DENO_HELP) .after_help(ENV_VARIABLES_HELP) } @@ -537,6 +535,7 @@ fn run_parse(flags: &mut Flags, matches: &clap::ArgMatches) { fn test_parse(flags: &mut Flags, matches: &clap::ArgMatches) { run_test_args_parse(flags, matches); + let docs = matches.is_present("docs"); let failfast = matches.is_present("failfast"); let allow_none = matches.is_present("allow_none"); let quiet = matches.is_present("quiet"); @@ -553,6 +552,7 @@ fn test_parse(flags: &mut Flags, matches: &clap::ArgMatches) { }; flags.subcommand = DenoSubcommand::Test { + docs, fail_fast: failfast, quiet, include, @@ -586,33 +586,6 @@ fn doc_parse(flags: &mut Flags, matches: &clap::ArgMatches) { }; } -fn doctest_parse(flags: &mut Flags, matches: &clap::ArgMatches) { - run_test_args_parse(flags, matches); - - let failfast = matches.is_present("failfast"); - let allow_none = matches.is_present("allow_none"); - let quiet = matches.is_present("quiet"); - let filter = matches.value_of("filter").map(String::from); - let include = if matches.is_present("files") { - let files: Vec = matches - .values_of("files") - .unwrap() - .map(String::from) - .collect(); - Some(files) - } else { - None - }; - - flags.subcommand = DenoSubcommand::Doctest { - include, - fail_fast: failfast, - quiet, - filter, - allow_none, - }; -} - fn types_subcommand<'a, 'b>() -> App<'a, 'b> { SubCommand::with_name("types") .arg(unstable_arg()) @@ -915,46 +888,6 @@ Show documentation for runtime built-ins: ) } -fn doctest_subcommand<'a, 'b>() -> App<'a, 'b> { - run_test_args(SubCommand::with_name("doctest")) - .arg( - Arg::with_name("failfast") - .long("failfast") - .help("Stop on first error") - .takes_value(false), - ) - .arg( - Arg::with_name("allow_none") - .long("allow-none") - .help("Don't return error code if no files with doctests are found") - .takes_value(false), - ) - .arg( - Arg::with_name("filter") - .long("filter") - .takes_value(true) - .help("A pattern to filter the doctests to run by"), - ) - .arg( - Arg::with_name("files") - .help("List of file names to run") - .takes_value(true) - .multiple(true), - ) - .about("Run Doctests") - .long_about( - "Run doctests using Deno's built-in doctest runner. - -Evaluate the given modules, run all doctests declared in JSDoc @example block and -report results to standard output: - deno doctest src/fetch.ts src/signal.ts - -Directory arguments are expanded to all contained files matching the glob -{*_,*.,}.{js,ts,jsx,tsx} except test files: - deno doctest src/", - ) -} - fn permission_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { app .arg( @@ -1072,6 +1005,12 @@ fn test_subcommand<'a, 'b>() -> App<'a, 'b> { .help("Stop on first error") .takes_value(false), ) + .arg( + Arg::with_name("docs") + .long("docs") + .help("Run code examples as tests") + .takes_value(false), + ) .arg( Arg::with_name("allow_none") .long("allow-none") @@ -2447,6 +2386,7 @@ mod tests { r.unwrap(), Flags { subcommand: DenoSubcommand::Test { + docs: false, fail_fast: false, filter: None, allow_none: true, @@ -2466,6 +2406,7 @@ mod tests { r.unwrap(), Flags { subcommand: DenoSubcommand::Test { + docs: false, fail_fast: false, allow_none: false, quiet: false, @@ -2763,4 +2704,23 @@ mod tests { } ); } + + #[test] + fn doctest() { + let r = flags_from_vec_safe(svec!["deno", "test", "--docs"]); + assert_eq!( + r.unwrap(), + Flags { + subcommand: DenoSubcommand::Test { + allow_none: false, + docs: true, + fail_fast: false, + quiet: false, + include: None, + filter: None + }, + ..Flags::default() + } + ); + } } diff --git a/cli/main.rs b/cli/main.rs index eb6bff8f420a85..e003231a630383 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -519,60 +519,6 @@ async fn doc_command( } } -async fn doctest_command( - flags: Flags, - include: Option>, - fail_fast: bool, - quiet: bool, - allow_none: bool, - filter: Option, -) -> Result<(), ErrBox> { - let global_state = GlobalState::new(flags.clone())?; - let cwd = std::env::current_dir() - .expect("expected: process has a current working directory"); - let include = include.unwrap_or_else(|| vec![".".to_string()]); - let doctests = doctest_runner::prepare_doctest(include, &cwd); - - if doctests.is_empty() { - println!("No matching doctest modules found"); - if !allow_none { - std::process::exit(1); - } - return Ok(()); - } - - let doctest_file_path = cwd.join(".deno_doctest.test.ts"); - let doctest_file_url = - Url::from_file_path(&doctest_file_path).expect("Should be valid file url"); - let doctest_file = - doctest_runner::render_doctest_file(doctests, fail_fast, quiet, filter); - let main_module = - ModuleSpecifier::resolve_url(&doctest_file_url.to_string()).unwrap(); - let mut worker = - MainWorker::create(global_state.clone(), main_module.clone())?; - - let source_file = SourceFile { - filename: doctest_file_url.to_file_path().unwrap(), - url: doctest_file_url, - types_url: None, - types_header: None, - media_type: MediaType::TypeScript, - source_code: doctest_file.clone().into_bytes(), - }; - - worker - .state - .borrow() - .global_state - .file_fetcher - .save_source_file_in_cache(&main_module, source_file); - let execute_result = worker.execute_module(&main_module).await; - execute_result?; - worker.execute("window.dispatchEvent(new Event('load'))")?; - (&mut *worker).await?; - worker.execute("window.dispatchEvent(new Event('unload'))") -} - async fn run_repl(flags: Flags) -> Result<(), ErrBox> { let main_module = ModuleSpecifier::resolve_url_or_path("./__$deno$repl.ts").unwrap(); @@ -598,6 +544,7 @@ async fn run_command(flags: Flags, script: String) -> Result<(), ErrBox> { } async fn test_command( + docs: bool, flags: Flags, include: Option>, fail_fast: bool, @@ -608,9 +555,29 @@ async fn test_command( let global_state = GlobalState::new(flags.clone())?; let cwd = std::env::current_dir().expect("No current directory"); let include = include.unwrap_or_else(|| vec![".".to_string()]); - let test_modules = test_runner::prepare_test_modules_urls(include, &cwd)?; - if test_modules.is_empty() { + let (test_file, is_empty) = if !docs { + let test_modules = test_runner::prepare_test_modules_urls(include, &cwd)?; + let empty = &test_modules.is_empty(); + ( + test_runner::render_test_file(test_modules, fail_fast, quiet, filter), + empty.clone(), + ) + } else { + let doctest_modules = doctest_runner::prepare_doctests(include, &cwd); + let empty = &doctest_modules.is_empty(); + ( + doctest_runner::render_doctest_file( + doctest_modules, + fail_fast, + quiet, + filter, + ), + empty.clone(), + ) + }; + + if is_empty { println!("No matching test modules found"); if !allow_none { std::process::exit(1); @@ -621,8 +588,6 @@ async fn test_command( let test_file_path = cwd.join(".deno.test.ts"); let test_file_url = Url::from_file_path(&test_file_path).expect("Should be valid file url"); - let test_file = - test_runner::render_test_file(test_modules, fail_fast, quiet, filter); let main_module = ModuleSpecifier::resolve_url(&test_file_url.to_string()).unwrap(); let mut worker = @@ -681,14 +646,6 @@ pub fn main() { json, filter, } => doc_command(flags, source_file, json, filter).boxed_local(), - DenoSubcommand::Doctest { - include, - fail_fast, - quiet, - allow_none, - filter, - } => doctest_command(flags, include, fail_fast, quiet, allow_none, filter) - .boxed_local(), DenoSubcommand::Eval { code, as_typescript, @@ -712,13 +669,16 @@ pub fn main() { DenoSubcommand::Repl => run_repl(flags).boxed_local(), DenoSubcommand::Run { script } => run_command(flags, script).boxed_local(), DenoSubcommand::Test { + docs, fail_fast, quiet, include, allow_none, filter, - } => test_command(flags, include, fail_fast, quiet, allow_none, filter) - .boxed_local(), + } => { + test_command(docs, flags, include, fail_fast, quiet, allow_none, filter) + .boxed_local() + } DenoSubcommand::Completions { buf } => { if let Err(e) = write_to_stdout_ignore_sigpipe(&buf) { eprintln!("{}", e); From 1de241877358eec94f720d3bd93dd72f3658a463 Mon Sep 17 00:00:00 2001 From: iykekings Date: Sat, 6 Jun 2020 18:05:57 +0100 Subject: [PATCH 07/44] clippy :( --- cli/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/main.rs b/cli/main.rs index e003231a630383..a45eb4e73f67cd 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -561,7 +561,7 @@ async fn test_command( let empty = &test_modules.is_empty(); ( test_runner::render_test_file(test_modules, fail_fast, quiet, filter), - empty.clone(), + *empty, ) } else { let doctest_modules = doctest_runner::prepare_doctests(include, &cwd); @@ -573,7 +573,7 @@ async fn test_command( quiet, filter, ), - empty.clone(), + *empty, ) }; From d7065c8258420a4490fb7a797fbe87cbf3872ac8 Mon Sep 17 00:00:00 2001 From: iykekings Date: Sat, 6 Jun 2020 18:32:43 +0100 Subject: [PATCH 08/44] refactor: remove Doctest from DenoSubcommand --- cli/flags.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/cli/flags.rs b/cli/flags.rs index ffca3a8da8509d..02c34eccdaa3b8 100644 --- a/cli/flags.rs +++ b/cli/flags.rs @@ -27,13 +27,6 @@ pub enum DenoSubcommand { source_file: Option, filter: Option, }, - Doctest { - fail_fast: bool, - quiet: bool, - allow_none: bool, - include: Option>, - filter: Option, - }, Eval { code: String, as_typescript: bool, From 2d8d5eb3a6c55079ffb44025cee9a5eafb9a87b1 Mon Sep 17 00:00:00 2001 From: Ikechukwu Eze Date: Sun, 7 Jun 2020 20:29:57 +0100 Subject: [PATCH 09/44] Add tests (#6) * test: extract_jsdoc_examples * add more tests * formatting --- cli/doctest_runner.rs | 199 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) diff --git a/cli/doctest_runner.rs b/cli/doctest_runner.rs index 70fea81077747f..098e1ef5705e6d 100644 --- a/cli/doctest_runner.rs +++ b/cli/doctest_runner.rs @@ -238,3 +238,202 @@ fn get_code_from_example(ex: &str) -> String { .collect::>() .join("\n") } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_extract_jsdoc() { + let test = r#"/** + * + * @param list - LinkedList + * @example Linkedlists.compareWith + * ```ts + * import { LinkedList } from './js_test/linkedlist.ts' + * const testArr = [1, 2, 3, 4, 5, 6, 78, 9, 0, 65]; + * const firstList = new LinkedList(); + * const secondList = new LinkedList(); + * for (let data of testArr) { + * firstList.insertNode(data); + * secondList.insertNode(data); + * } + * const result = firstList.compareWith(secondList); + * assert(result); + * ``` + * @returns boolean + */ + compareWith(list: LinkedList): boolean { + let current1 = this.head; + let current2 = list.head; + while (current1 && current2) { + if (current1.data !== current2.data) return false; + if (current1.next && !current2.next && !current1.next && current2.next) { + return false; + } + current1 = current1.next; + current2 = current2.next; + } + return true; + }"#; + let res = extract_jsdoc_examples(test.to_string(), PathBuf::from("user")); + assert!(res.is_some()); + + let doctest = res.unwrap(); + assert_eq!(1, *&doctest.imports.len()); + assert_eq!(*&doctest.bodies.len(), 1); + let body = &doctest.bodies[0]; + assert!(!body.is_async); + assert!(!body.ignore); + assert_eq!(body.caption, "Linkedlists.compareWith".to_string()); + assert_eq!(body.line_number, 5); + assert_eq!( + body.value, + vec![ + " const testArr = [1, 2, 3, 4, 5, 6, 78, 9, 0, 65];", + " const firstList = new LinkedList();", + " const secondList = new LinkedList();", + " for (let data of testArr) {", + " firstList.insertNode(data);", + " secondList.insertNode(data);", + " }", + " const result = firstList.compareWith(secondList);", + " assert(result);" + ] + .join("\n") + ) + } + + #[test] + fn test_multiple_examples() { + let test = r#" /** + * + * @param fn - (data: T, index: number) => T + * @example Linkedlist.map + * ```ts + * import { LinkedList } from './js_test/linkedlist.ts' + * const testArr = [1, 2, 3, 4, 5, 6, 78, 9, 0, 65]; + * const testList = new LinkedList(); + * for (let data of testArr) { + * testList.insertNode(data); + * } + * testList.map((c: number) => c ** 2); + * testList.forEach((c: number, i: number) => assertEquals(c, testArr[i] ** 2)); + * ``` + * + * @example Linkedlist.map 2 + * ```ignore + * import { LinkedList } from './js_test/linkedlist.ts' + * const testArr = [1, 2, 3, 4, 5]; + * const testList = new LinkedList(); + * for (let data of testArr) { + * testList.insertNode(data); + * } + * testList.map((c: number) => c ** 2); + * testList.forEach((c: number, i: number) => assertEquals(c, testArr[i] ** 2)); + * ``` + */"#; + let res = extract_jsdoc_examples(test.to_string(), PathBuf::from("user")); + assert!(res.is_some()); + + let doctest = res.unwrap(); + // imports are deduped + assert_eq!(1, *&doctest.imports.len()); + assert_eq!(*&doctest.bodies.len(), 2); + let body1 = &doctest.bodies[0]; + let body2 = &doctest.bodies[1]; + assert!(!body1.is_async); + assert!(!body2.is_async); + assert!(!body1.ignore); + assert!(body2.ignore); + assert_eq!(body1.caption, "Linkedlist.map".to_string()); + assert_eq!(body2.caption, "Linkedlist.map 2".to_string()); + assert_eq!(body1.line_number, 5); + assert_eq!(body2.line_number, 17); + assert_eq!( + body2.value, + vec![ + " const testArr = [1, 2, 3, 4, 5];", + " const testList = new LinkedList();", + " for (let data of testArr) {", + " testList.insertNode(data);", + " }", + " testList.map((c: number) => c ** 2);", + " testList.forEach((c: number, i: number) => assertEquals(c, testArr[i] ** 2));" + ] + .join("\n") + ); + assert_eq!( + body1.value, + vec![ + " const testArr = [1, 2, 3, 4, 5, 6, 78, 9, 0, 65];", + " const testList = new LinkedList();", + " for (let data of testArr) {", + " testList.insertNode(data);", + " }", + " testList.map((c: number) => c ** 2);", + " testList.forEach((c: number, i: number) => assertEquals(c, testArr[i] ** 2));", + ].join("\n")); + } + + #[test] + fn test_code_without_jsdoc() { + let test = r#"class Node { + constructor(public data: T, public next?: Node) {} + + swap(other: Node) { + let temp = this.data; + this.data = other.data; + other.data = temp; + } + }"#; + let res = extract_jsdoc_examples(test.to_string(), PathBuf::from("user")); + assert!(res.is_none()); + } + + #[test] + fn test_async_detection() { + let test = r#" /** + * @example + * ```ts + * const response = await fetch("https://deno.land"); + * const body = await response.text(); + * assert(body.length > 0); + * ``` + */"#; + + let res = extract_jsdoc_examples(test.to_string(), PathBuf::from("user")); + assert!(res.is_some()); + let doctest = res.unwrap(); + let body = &doctest.bodies[0]; + assert!(body.is_async); + } + + #[test] + fn test_text_tag() { + let test = r#" /** + * @example + * ```text + * const response = await fetch("https://deno.land"); + * const body = await response.text(); + * assert(body.length > 0); + * ``` + */"#; + + let res = extract_jsdoc_examples(test.to_string(), PathBuf::from("user")); + assert!(res.is_none()); + } + + #[test] + fn test_jump_example_without_backticks() { + let test = r#" /** + * @example + * const response = await fetch("https://deno.land"); + * const body = await response.text(); + * assert(body.length > 0); + */"#; + + let res = extract_jsdoc_examples(test.to_string(), PathBuf::from("user")); + assert!(res.is_none()); + } +} From dcca3db870ce520cf38434800b0d0a080aff544d Mon Sep 17 00:00:00 2001 From: iykekings Date: Sun, 7 Jun 2020 20:50:17 +0100 Subject: [PATCH 10/44] x --- cli/doctest_runner.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cli/doctest_runner.rs b/cli/doctest_runner.rs index 098e1ef5705e6d..61a3ede817bd79 100644 --- a/cli/doctest_runner.rs +++ b/cli/doctest_runner.rs @@ -280,8 +280,8 @@ mod test { assert!(res.is_some()); let doctest = res.unwrap(); - assert_eq!(1, *&doctest.imports.len()); - assert_eq!(*&doctest.bodies.len(), 1); + assert_eq!(1, doctest.imports.len()); + assert_eq!(doctest.bodies.len(), 1); let body = &doctest.bodies[0]; assert!(!body.is_async); assert!(!body.ignore); @@ -338,8 +338,8 @@ mod test { let doctest = res.unwrap(); // imports are deduped - assert_eq!(1, *&doctest.imports.len()); - assert_eq!(*&doctest.bodies.len(), 2); + assert_eq!(1, doctest.imports.len()); + assert_eq!(doctest.bodies.len(), 2); let body1 = &doctest.bodies[0]; let body2 = &doctest.bodies[1]; assert!(!body1.is_async); From d6d51579ae12ad28035ec197f362680063f78032 Mon Sep 17 00:00:00 2001 From: iykekings Date: Sun, 7 Jun 2020 21:17:09 +0100 Subject: [PATCH 11/44] xx From 6cdd2fd48c8174de2857cec7e9afed65a5b01bdf Mon Sep 17 00:00:00 2001 From: iykekings Date: Sun, 7 Jun 2020 21:45:43 +0100 Subject: [PATCH 12/44] another empty commit From e9227137de60458d1b1c7b60c91dbcc775fbb566 Mon Sep 17 00:00:00 2001 From: iykekings Date: Tue, 25 Aug 2020 22:12:06 +0100 Subject: [PATCH 13/44] fix conflict --- cli/main.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/cli/main.rs b/cli/main.rs index 075de718e209fb..d951c7dfdca835 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -29,11 +29,7 @@ pub mod deno_dir; pub mod diagnostics; mod diff; mod disk_cache; -<<<<<<< HEAD -mod doc; mod doctest_runner; -======= ->>>>>>> d0ccab7fb7dd80030d3765ca9a9af44de6ecda5a mod file_fetcher; pub mod flags; mod flags_allow_net; From be1aaeb79b1ebf8efdb03f511c88150ba55fb8f1 Mon Sep 17 00:00:00 2001 From: iykekings Date: Sun, 20 Sep 2020 21:12:03 +0100 Subject: [PATCH 14/44] parse jsdoc with jsdoc crate --- Cargo.lock | 5 ++- cli/Cargo.toml | 1 + cli/doctest_runner.rs | 89 +++++++++++++++++++++++++++++--------- cli/flags.rs | 40 ++++++++--------- cli/main.rs | 84 ++++++++++++++++++----------------- cli/test_runner.rs | 14 ++++-- deno_typescript/typescript | 1 + 7 files changed, 147 insertions(+), 87 deletions(-) create mode 160000 deno_typescript/typescript diff --git a/Cargo.lock b/Cargo.lock index 427dc592184b26..38ab9b9ce8b07c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -410,6 +410,7 @@ dependencies = [ "http", "idna", "indexmap", + "jsdoc", "jsonc-parser", "lazy_static", "libc", @@ -1113,9 +1114,9 @@ dependencies = [ [[package]] name = "jsdoc" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf288cd831329dde36e0c5b667d1823c4cfba4fcb311c6471e37cdcb8b019a7" +checksum = "3eb0392aa1730824b8359786500d1e1812a8fe4f220bb97a799a4390cf302d9d" dependencies = [ "nom", "serde", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 5a969b785fefb6..4389b0beb2d3d1 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -46,6 +46,7 @@ filetime = "0.2.12" http = "0.2.1" idna = "0.2.0" indexmap = "1.5.2" +jsdoc = "0.5.1" jsonc-parser = "0.14.0" lazy_static = "1.4.0" libc = "0.2.74" diff --git a/cli/doctest_runner.rs b/cli/doctest_runner.rs index 61a3ede817bd79..43a7993f23de5d 100644 --- a/cli/doctest_runner.rs +++ b/cli/doctest_runner.rs @@ -1,12 +1,36 @@ +use crate::file_fetcher::map_file_extension; +use crate::flags::Flags; +use crate::global_state::GlobalState; +use crate::swc_util; +use crate::swc_util::get_syntax_for_media_type; +use deno_core::ErrBox; +use deno_doc::DocParser; +use jsdoc::{self, ast::JsDoc, Input}; use regex::Regex; use std::collections::HashSet; use std::ffi::OsStr; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; +use url::Url; use crate::fs as deno_fs; use crate::installer::is_remote_url; use crate::test_runner::is_supported; +lazy_static! { + static ref JS_DOC_PATTERN: Regex = + Regex::new(r"/\*\*\s*\n([^\*]|\*[^/])*\*/").unwrap(); + // IMPORT_PATTERN doesn't match dynamic imports by design + static ref IMPORT_PATTERN: Regex = + Regex::new(r"import[^(].*\n").unwrap(); + static ref EXAMPLE_PATTERN: Regex = Regex::new(r"@example\s*(?:<\w+>.*)*\n(?:\s*\*\s*\n*)*```").unwrap(); + static ref TEST_TAG_PATTERN: Regex = Regex::new(r"@example\s*(?:<\w+>.*)*\n(?:\s*\*\s*\n*)*```(\w+)").unwrap(); + static ref AWAIT_PATTERN: Regex = Regex::new(r"\Wawait\s").unwrap(); + static ref CAPTION_PATTERN: Regex = + Regex::new(r"([\s\w\W]+)").unwrap(); + static ref TICKS_OR_IMPORT_PATTERN: Regex = + Regex::new(r"(?:import[^(].*)|(?:```\w*)").unwrap(); +} + pub struct DocTest { // This removes repetition of imports in a file imports: HashSet, @@ -23,6 +47,49 @@ struct DocTestBody { is_async: bool, } +pub async fn parse_jsdoc( + source_files: Vec, + flags: Flags, +) -> Result, ErrBox> { + let global_state = GlobalState::new(flags.clone())?; + let loader = Box::new(global_state.file_fetcher.clone()); + + let doc_parser = DocParser::new(loader, false); + let mut modules = vec![]; + for url in source_files { + let source_code = + doc_parser.loader.load_source_code(&url.to_string()).await?; + let path = PathBuf::from(&url.to_string()); + let media_type = map_file_extension(&path); + let module = doc_parser.ast_parser.parse_module( + &url.to_string(), + get_syntax_for_media_type(media_type), + &source_code, + )?; + modules.push(module); + } + + let jsdocs = modules + .into_iter() + .flat_map(|module| doc_parser.ast_parser.get_span_comments(module.span)) + .map(|comment| { + jsdoc::parse(Input::from(&comment)) + .expect("Error when parsing jsdoc") + .1 + }) + .collect::>(); + Ok(jsdocs) +} + +pub fn is_supported_doctest(path: &Path) -> bool { + let valid_ext = ["ts", "tsx", "js", "jsx"]; + path + .extension() + .and_then(OsStr::to_str) + .map(|ext| valid_ext.contains(&ext) && !is_supported(path)) + .unwrap_or(false) +} + pub fn prepare_doctests( mut include: Vec, root_path: &PathBuf, @@ -59,17 +126,6 @@ pub fn prepare_doctests( } fn extract_jsdoc_examples(input: String, p: PathBuf) -> Option { - lazy_static! { - static ref JS_DOC_PATTERN: Regex = - Regex::new(r"/\*\*\s*\n([^\*]|\*[^/])*\*/").unwrap(); - // IMPORT_PATTERN doesn't match dynamic imports by design - static ref IMPORT_PATTERN: Regex = - Regex::new(r"import[^(].*\n").unwrap(); - static ref EXAMPLE_PATTERN: Regex = Regex::new(r"@example\s*(?:<\w+>.*)*\n(?:\s*\*\s*\n*)*```").unwrap(); - static ref TEST_TAG_PATTERN: Regex = Regex::new(r"@example\s*(?:<\w+>.*)*\n(?:\s*\*\s*\n*)*```(\w+)").unwrap(); - static ref AWAIT_PATTERN: Regex = Regex::new(r"\Wawait\s").unwrap(); - } - let mut import_set = HashSet::new(); let test_bodies = JS_DOC_PATTERN @@ -204,10 +260,6 @@ pub fn render_doctest_file( } fn get_caption_from_example(ex: &str) -> String { - lazy_static! { - static ref CAPTION_PATTERN: Regex = - Regex::new(r"([\s\w\W]+)").unwrap(); - } CAPTION_PATTERN .captures(ex) .and_then(|cap| cap.get(1).map(|m| m.as_str())) @@ -216,10 +268,6 @@ fn get_caption_from_example(ex: &str) -> String { } fn get_code_from_example(ex: &str) -> String { - lazy_static! { - static ref TICKS_OR_IMPORT_PATTERN: Regex = - Regex::new(r"(?:import[^(].*)|(?:```\w*)").unwrap(); - } TICKS_OR_IMPORT_PATTERN .replace_all(ex, "\n") .lines() @@ -242,7 +290,6 @@ fn get_code_from_example(ex: &str) -> String { #[cfg(test)] mod test { use super::*; - #[test] fn test_extract_jsdoc() { let test = r#"/** diff --git a/cli/flags.rs b/cli/flags.rs index 8809fae3cc3a29..7edc1b2bf0dd90 100644 --- a/cli/flags.rs +++ b/cli/flags.rs @@ -1195,7 +1195,7 @@ fn test_subcommand<'a, 'b>() -> App<'a, 'b> { .arg( Arg::with_name("docs") .long("docs") - .help("Run code examples as tests") + .help("Run code examples from JSDocs as tests") .takes_value(false), ) .arg( @@ -2871,6 +2871,24 @@ mod tests { } ); } + #[test] + fn test_docs() { + let r = flags_from_vec_safe(svec!["deno", "test", "--docs", "dir1"]); + assert_eq!( + r.unwrap(), + Flags { + subcommand: DenoSubcommand::Test { + docs: true, + fail_fast: false, + allow_none: false, + quiet: false, + filter: None, + include: Some(svec!["dir1"]), + }, + ..Flags::default() + } + ); + } #[test] fn test_filter_leading_hyphen() { @@ -2880,6 +2898,7 @@ mod tests { r.unwrap(), Flags { subcommand: DenoSubcommand::Test { + docs: false, fail_fast: false, allow_none: false, quiet: false, @@ -3223,23 +3242,4 @@ mod tests { } ); } - - #[test] - fn doctest() { - let r = flags_from_vec_safe(svec!["deno", "test", "--docs"]); - assert_eq!( - r.unwrap(), - Flags { - subcommand: DenoSubcommand::Test { - allow_none: false, - docs: true, - fail_fast: false, - quiet: false, - include: None, - filter: None - }, - ..Flags::default() - } - ); - } } diff --git a/cli/main.rs b/cli/main.rs index 0d2cd88402233c..66f7b42087f74e 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -100,6 +100,45 @@ use std::sync::Arc; use upgrade::upgrade_command; use url::Url; +impl DocFileLoader for SourceFileFetcher { + fn resolve( + &self, + specifier: &str, + referrer: &str, + ) -> Result { + ModuleSpecifier::resolve_import(specifier, referrer) + .map(|specifier| specifier.to_string()) + .map_err(|e| doc::DocError::Resolve(e.to_string())) + } + + fn load_source_code( + &self, + specifier: &str, + ) -> Pin>>> { + let fetcher = self.clone(); + let specifier = ModuleSpecifier::resolve_url_or_path(specifier) + .expect("Expected valid specifier"); + async move { + let source_file = fetcher + .fetch_source_file(&specifier, None, Permissions::allow_all()) + .await + .map_err(|e| { + doc::DocError::Io(std::io::Error::new( + std::io::ErrorKind::Other, + e.to_string(), + )) + })?; + source_file.source_code.to_string().map_err(|e| { + doc::DocError::Io(std::io::Error::new( + std::io::ErrorKind::Other, + e.to_string(), + )) + }) + } + .boxed_local() + } +} + fn write_to_stdout_ignore_sigpipe(bytes: &[u8]) -> Result<(), std::io::Error> { use std::io::ErrorKind; @@ -329,45 +368,6 @@ async fn doc_command( let global_state = GlobalState::new(flags.clone())?; let source_file = source_file.unwrap_or_else(|| "--builtin".to_string()); - impl DocFileLoader for SourceFileFetcher { - fn resolve( - &self, - specifier: &str, - referrer: &str, - ) -> Result { - ModuleSpecifier::resolve_import(specifier, referrer) - .map(|specifier| specifier.to_string()) - .map_err(|e| doc::DocError::Resolve(e.to_string())) - } - - fn load_source_code( - &self, - specifier: &str, - ) -> Pin>>> { - let fetcher = self.clone(); - let specifier = ModuleSpecifier::resolve_url_or_path(specifier) - .expect("Expected valid specifier"); - async move { - let source_file = fetcher - .fetch_source_file(&specifier, None, Permissions::allow_all()) - .await - .map_err(|e| { - doc::DocError::Io(std::io::Error::new( - std::io::ErrorKind::Other, - e.to_string(), - )) - })?; - source_file.source_code.to_string().map_err(|e| { - doc::DocError::Io(std::io::Error::new( - std::io::ErrorKind::Other, - e.to_string(), - )) - }) - } - .boxed_local() - } - } - let loader = Box::new(global_state.file_fetcher.clone()); let doc_parser = doc::DocParser::new(loader, private); @@ -487,7 +487,11 @@ async fn test_command( let include = include.unwrap_or_else(|| vec![".".to_string()]); let (test_file, is_empty) = if !docs { - let test_modules = test_runner::prepare_test_modules_urls(include, &cwd)?; + let test_modules = test_runner::prepare_test_modules_urls( + include, + &cwd, + test_runner::is_supported, + )?; let empty = &test_modules.is_empty(); ( test_runner::render_test_file(test_modules, fail_fast, quiet, filter), diff --git a/cli/test_runner.rs b/cli/test_runner.rs index 3c2359d31b51aa..9ba422dd92f052 100644 --- a/cli/test_runner.rs +++ b/cli/test_runner.rs @@ -31,10 +31,14 @@ pub(crate) fn is_supported(p: &Path) -> bool { } } -pub fn prepare_test_modules_urls( +pub fn prepare_test_modules_urls( include: Vec, root_path: &PathBuf, -) -> Result, ErrBox> { + filter: F, +) -> Result, ErrBox> +where + F: Fn(&Path) -> bool, +{ let (include_paths, include_urls): (Vec, Vec) = include.into_iter().partition(|n| !is_remote_url(n)); @@ -43,7 +47,7 @@ pub fn prepare_test_modules_urls( for path in include_paths { let p = deno_fs::normalize_path(&root_path.join(path)); if p.is_dir() { - let test_files = crate::fs::files_in_subtree(p, is_supported); + let test_files = crate::fs::files_in_subtree(p, &filter); let test_files_as_urls = test_files .iter() .map(|f| Url::from_file_path(f).unwrap()) @@ -106,6 +110,7 @@ mod tests { "http://example.com/printf_test.ts".to_string(), ], &test_data_path, + is_supported, ) .unwrap(); let test_data_url = @@ -150,7 +155,8 @@ mod tests { let root = test_util::root_path().join("std").join("http"); println!("root {:?}", root); let mut matched_urls = - prepare_test_modules_urls(vec![".".to_string()], &root).unwrap(); + prepare_test_modules_urls(vec![".".to_string()], &root, is_supported) + .unwrap(); matched_urls.sort(); let root_url = Url::from_file_path(root).unwrap().to_string(); println!("root_url {}", root_url); diff --git a/deno_typescript/typescript b/deno_typescript/typescript new file mode 160000 index 00000000000000..551f0dd9a1b57e --- /dev/null +++ b/deno_typescript/typescript @@ -0,0 +1 @@ +Subproject commit 551f0dd9a1b57ecd527a665b0af7fc98cd107af6 From b5220fbae5691b1a4c994d971dbec6f2bc34d72b Mon Sep 17 00:00:00 2001 From: iykekings Date: Thu, 24 Sep 2020 20:45:25 +0100 Subject: [PATCH 15/44] fix tests --- cli/doctest_runner.rs | 528 ++++++++++++------------------------------ cli/main.rs | 26 ++- 2 files changed, 163 insertions(+), 391 deletions(-) diff --git a/cli/doctest_runner.rs b/cli/doctest_runner.rs index df81921a9f8f59..321fe6215ebc73 100644 --- a/cli/doctest_runner.rs +++ b/cli/doctest_runner.rs @@ -2,245 +2,105 @@ use crate::ast; use crate::flags::Flags; use crate::global_state::GlobalState; use crate::media_type::MediaType; -use deno_core::error::AnyError; use deno_core::url::Url; +use deno_core::{error::AnyError, ModuleSpecifier}; use deno_doc::DocParser; -use jsdoc::{self, ast::JsDoc, Input}; +use jsdoc::{self, ast::Tag, Input}; use regex::Regex; use std::collections::HashSet; use std::ffi::OsStr; use std::path::{Path, PathBuf}; -use crate::fs as deno_fs; -use crate::installer::is_remote_url; use crate::test_runner::is_supported; lazy_static! { - static ref JS_DOC_PATTERN: Regex = - Regex::new(r"/\*\*\s*\n([^\*]|\*[^/])*\*/").unwrap(); - // IMPORT_PATTERN doesn't match dynamic imports by design static ref IMPORT_PATTERN: Regex = - Regex::new(r"import[^(].*\n").unwrap(); + Regex::new(r#"import\s+?(?:(?:(?:[\w*\s{},]*)\s+from\s+?)|)(?:(?:".*?")|(?:'.*?'))[\s]*?(?:;|$|)"#).unwrap(); static ref EXAMPLE_PATTERN: Regex = Regex::new(r"@example\s*(?:<\w+>.*)*\n(?:\s*\*\s*\n*)*```").unwrap(); - static ref TEST_TAG_PATTERN: Regex = Regex::new(r"@example\s*(?:<\w+>.*)*\n(?:\s*\*\s*\n*)*```(\w+)").unwrap(); + static ref TEST_TAG_PATTERN: Regex = Regex::new(r"```(\w+)?").unwrap(); static ref AWAIT_PATTERN: Regex = Regex::new(r"\Wawait\s").unwrap(); static ref CAPTION_PATTERN: Regex = Regex::new(r"([\s\w\W]+)").unwrap(); - static ref TICKS_OR_IMPORT_PATTERN: Regex = + static ref TICKS_OR_IMPORT_PATTERN: Regex = Regex::new(r"(?:import[^(].*)|(?:```\w*)").unwrap(); } -pub struct DocTest { - // This removes repetition of imports in a file - imports: HashSet, - // This contains codes in an @example section with their imports removed - bodies: Vec, -} - -struct DocTestBody { - caption: String, - line_number: usize, - path: String, - value: String, - ignore: bool, - is_async: bool, -} - -pub async fn parse_jsdoc( - source_files: Vec, +pub async fn parse_jsdocs( + source_files: &Vec, flags: Flags, -) -> Result, AnyError> { +) -> Result, AnyError> { let global_state = GlobalState::new(flags.clone())?; let loader = Box::new(global_state.file_fetcher.clone()); let doc_parser = DocParser::new(loader, false); - let mut modules = vec![]; + let mut results = vec![]; for url in source_files { let source_code = doc_parser.loader.load_source_code(&url.to_string()).await?; let path = PathBuf::from(&url.to_string()); let media_type = MediaType::from(&path); - let module = doc_parser.ast_parser.parse_module( - &url.to_string(), - ast::get_syntax(&media_type), - &source_code, - )?; - modules.push(module); - } - - let jsdocs = modules - .into_iter() - .flat_map(|module| doc_parser.ast_parser.get_span_comments(module.span)) - .map(|comment| { - jsdoc::parse(Input::from(&comment)) - .expect("Error when parsing jsdoc") - .1 - }) - .collect::>(); - Ok(jsdocs) -} - -pub fn is_supported_doctest(path: &Path) -> bool { - let valid_ext = ["ts", "tsx", "js", "jsx"]; - path - .extension() - .and_then(OsStr::to_str) - .map(|ext| valid_ext.contains(&ext) && !is_supported(path)) - .unwrap_or(false) -} - -pub fn prepare_doctests( - mut include: Vec, - root_path: &PathBuf, -) -> Vec { - include.retain(|n| !is_remote_url(n)); - - let mut prepared = vec![]; - - for path in include { - let p = deno_fs::normalize_path(&root_path.join(path)); - if p.is_dir() { - let test_files = deno_fs::files_in_subtree(p, |p| { - let valid_ext = ["ts", "tsx", "js", "jsx"]; - p.extension() - .and_then(OsStr::to_str) - .map(|ext| valid_ext.contains(&ext) && !is_supported(p)) - .unwrap_or(false) - }); - prepared.extend(test_files); - } else { - prepared.push(p); - } - } + let specifier = ModuleSpecifier::resolve_url(&url.to_string())?; + let module = ast::parse(&specifier, &source_code, &media_type)?; - prepared - .iter() - .filter_map(|dir| { - // TODO(iykekings) use deno error instead - let content = std::fs::read_to_string(&dir) - .unwrap_or_else(|_| panic!("File doesn't exist {}", dir.display())); - extract_jsdoc_examples(content, dir.to_owned()) - }) - .collect::>() -} - -fn extract_jsdoc_examples(input: String, p: PathBuf) -> Option { - let mut import_set = HashSet::new(); - - let test_bodies = JS_DOC_PATTERN - .captures_iter(&input) - .filter_map(|caps| caps.get(0).map(|c| (c.start(), c.as_str()))) - .flat_map(|(offset, section)| { - EXAMPLE_PATTERN.find_iter(section).filter_map(move |cap| { - section[cap.end()..].find("```").map(|i| { - ( - offset + cap.end(), - section[cap.start()..i + cap.end()].to_string(), - ) - }) + let result = module + .get_leading_comments() + .into_iter() + .map(|comment| { + jsdoc::parse(Input::from(&comment)) + .expect("Error Parsing Jsdoc") + .1 }) - }) - .filter_map(|(offset, example_section)| { - let test_tag = TEST_TAG_PATTERN - .captures(&example_section) - .and_then(|m| m.get(1).map(|c| c.as_str())); - - if test_tag == Some("text") { - return None; - } - - IMPORT_PATTERN - .captures_iter(&example_section) - .filter_map(|caps| caps.get(0).map(|m| m.as_str())) - .for_each(|import| { - import_set.insert(import.to_string()); - }); - - let caption = get_caption_from_example(&example_section); - let line_number = &input[0..offset].lines().count(); - let code_block = get_code_from_example(&example_section); - let is_async = AWAIT_PATTERN.find(&example_section).is_some(); - - let cwd = std::env::current_dir() - .expect("expected: process has a current working directory"); - let path = p - .to_str() - .map(|x| x.replace(cwd.to_str().unwrap_or(""), "")); - Some(DocTestBody { - caption, - line_number: *line_number, - path: path.unwrap_or_else(|| "".to_string()), - value: code_block, - ignore: test_tag == Some("ignore"), - is_async, + .flat_map(|jsdoc| jsdoc.tags) + .filter_map(|tag_item| match tag_item.tag { + Tag::Example(ex_tag) => Some(( + module.get_location(&ex_tag.text.span), + ex_tag.text.value.to_string(), + )), + _ => None, }) - }) - .collect::>(); - - match test_bodies.len() { - 0 => None, - _ => Some(DocTest { - imports: import_set, - bodies: test_bodies, - }), + .collect::>(); + results.extend(result); } + Ok(results) } -pub fn render_doctest_file( - doctests: Vec, +pub fn prepare_doctests( + jsdocs: Vec<(ast::Location, String)>, fail_fast: bool, quiet: bool, filter: Option, ) -> String { - let mut test_file = "".to_string(); - - // TODO(iykekings) - discuss with team if this is fine - let default_import = "import { - assert, - assertArrayContains, - assertEquals, - assertMatch, - assertNotEquals, - assertStrContains, - assertStrictEq, - assertThrows, - assertThrowsAsync, - equal, - unimplemented, - unreachable, - } from \"https://deno.land/std/testing/asserts.ts\";\n"; - - test_file.push_str(default_import); - - let all_imports: String = doctests - .iter() - .map(|doctest| doctest.imports.clone()) - .flatten() + let mut test_file = "import * as assert from \"https://deno.land/std@0.70.0/testing/asserts.ts\";\n".to_string(); + let mut import_set = HashSet::new(); + let tests: String = jsdocs + .into_iter() + .map(|(loc, example)| (loc, clean_string(&example))) + .filter_map(|(l, x)| { + let test_tag = extract_test_tag(&x); + if test_tag == Some("text") { + return None; + } + let ignore = test_tag == Some("ignore"); + extract_imports(&x).into_iter().for_each(|import| { import_set.insert(import.to_string()); }); + let caption = extract_caption(&x); + let code_body = extract_code_body(&x); + let is_async = has_await(&x); + let res = format!( + "\nDeno.test({{\n\tname: \"{} - {} (line {})\",\n\tignore: {},\n\t{}fn() {{\n{}\n}}\n}});\n", + l.filename, + caption.unwrap_or(""), + l.line, + ignore, + if is_async { "async"} else {""}, + code_body + ); + Some(res) + }) .collect(); - - test_file.push_str(&all_imports); + let imports_str = import_set.into_iter().collect::>().join("\n"); + test_file.push_str(&imports_str); test_file.push_str("\n"); - - let all_test_section = doctests - .into_iter() - .map(|doctest| doctest.bodies.into_iter()) - .flatten() - .map(|test| { - let async_str = if test.is_async {"async "} else {""}; - format!( - "Deno.test({{\n\tname: \"{} - {} (line {})\",\n\tignore: {},\n\t{}fn() {{\n{}\n}}\n}});\n", - &test.path[1..], - test.caption, - test.line_number, - test.ignore, - async_str, - test.value - ) - }) - .collect::>() - .join("\n"); - - test_file.push_str(&all_test_section); + test_file.push_str(&tests); let options = if let Some(filter) = filter { json!({ "failFast": fail_fast, "reportToConsole": !quiet, "disableLog": quiet, "isDoctest": true, "filter": filter }) @@ -254,36 +114,75 @@ pub fn render_doctest_file( ); test_file.push_str(&run_tests_cmd); - test_file } -fn get_caption_from_example(ex: &str) -> String { +fn clean_string(input: &str) -> String { + input + .lines() + .map(|line| { + if line.trim().starts_with("*") { + &line.trim()[1..] + } else { + line.trim() + } + }) + .filter(|line| line.len() > 0) + .collect::>() + .join("\n") +} + +pub fn is_supported_doctest(path: &Path) -> bool { + let valid_ext = ["ts", "tsx", "js", "jsx"]; + path + .extension() + .and_then(OsStr::to_str) + .map(|ext| valid_ext.contains(&ext) && !is_supported(path)) + .unwrap_or(false) +} + +fn extract_test_tag(input: &str) -> Option<&str> { + TEST_TAG_PATTERN + .captures(input) + .and_then(|m| m.get(1).map(|c| c.as_str())) +} + +fn extract_caption(input: &str) -> Option<&str> { CAPTION_PATTERN - .captures(ex) - .and_then(|cap| cap.get(1).map(|m| m.as_str())) - .unwrap_or("") - .to_string() + .captures(input) + .and_then(|m| m.get(1).map(|c| c.as_str())) +} + +fn extract_imports(input: &str) -> Vec<&str> { + IMPORT_PATTERN + .captures_iter(input) + .filter_map(|caps| caps.get(0).map(|m| m.as_str())) + .collect() +} + +fn has_await(input: &str) -> bool { + AWAIT_PATTERN.find(input).is_some() } -fn get_code_from_example(ex: &str) -> String { - TICKS_OR_IMPORT_PATTERN +fn extract_code_body(ex: &str) -> String { + let code_sans_imports = IMPORT_PATTERN .replace_all(ex, "\n") .lines() - .skip(1) .filter_map(|line| { - let res = if line.trim_start().starts_with('*') { - line.replacen("*", "", 1).trim_start().to_string() + let res = line.trim(); + if line.len() > 0 { + Some(res) } else { - line.trim_start().to_string() - }; - match res.len() { - 0 => None, - _ => Some(format!(" {}", res)), + None } }) .collect::>() - .join("\n") + .join("\n"); + let code_sans_tag = TEST_TAG_PATTERN.replace_all(&code_sans_imports, ""); + CAPTION_PATTERN + .replace(&code_sans_tag, "") + .trim() + .to_string() } #[cfg(test)] @@ -291,10 +190,7 @@ mod test { use super::*; #[test] fn test_extract_jsdoc() { - let test = r#"/** - * - * @param list - LinkedList - * @example Linkedlists.compareWith + let test = r#"Linkedlists.compareWith * ```ts * import { LinkedList } from './js_test/linkedlist.ts' * const testArr = [1, 2, 3, 4, 5, 6, 78, 9, 0, 65]; @@ -306,180 +202,40 @@ mod test { * } * const result = firstList.compareWith(secondList); * assert(result); - * ``` - * @returns boolean - */ - compareWith(list: LinkedList): boolean { - let current1 = this.head; - let current2 = list.head; - while (current1 && current2) { - if (current1.data !== current2.data) return false; - if (current1.next && !current2.next && !current1.next && current2.next) { - return false; - } - current1 = current1.next; - current2 = current2.next; - } - return true; - }"#; - let res = extract_jsdoc_examples(test.to_string(), PathBuf::from("user")); - assert!(res.is_some()); - - let doctest = res.unwrap(); - assert_eq!(1, doctest.imports.len()); - assert_eq!(doctest.bodies.len(), 1); - let body = &doctest.bodies[0]; - assert!(!body.is_async); - assert!(!body.ignore); - assert_eq!(body.caption, "Linkedlists.compareWith".to_string()); - assert_eq!(body.line_number, 5); + ```"#; + let res = clean_string(test); + assert_eq!(extract_caption(&res), Some("Linkedlists.compareWith")); assert_eq!( - body.value, - vec![ - " const testArr = [1, 2, 3, 4, 5, 6, 78, 9, 0, 65];", - " const firstList = new LinkedList();", - " const secondList = new LinkedList();", - " for (let data of testArr) {", - " firstList.insertNode(data);", - " secondList.insertNode(data);", - " }", - " const result = firstList.compareWith(secondList);", - " assert(result);" - ] - .join("\n") - ) - } - - #[test] - fn test_multiple_examples() { - let test = r#" /** - * - * @param fn - (data: T, index: number) => T - * @example Linkedlist.map - * ```ts - * import { LinkedList } from './js_test/linkedlist.ts' - * const testArr = [1, 2, 3, 4, 5, 6, 78, 9, 0, 65]; - * const testList = new LinkedList(); - * for (let data of testArr) { - * testList.insertNode(data); - * } - * testList.map((c: number) => c ** 2); - * testList.forEach((c: number, i: number) => assertEquals(c, testArr[i] ** 2)); - * ``` - * - * @example Linkedlist.map 2 - * ```ignore - * import { LinkedList } from './js_test/linkedlist.ts' - * const testArr = [1, 2, 3, 4, 5]; - * const testList = new LinkedList(); - * for (let data of testArr) { - * testList.insertNode(data); - * } - * testList.map((c: number) => c ** 2); - * testList.forEach((c: number, i: number) => assertEquals(c, testArr[i] ** 2)); - * ``` - */"#; - let res = extract_jsdoc_examples(test.to_string(), PathBuf::from("user")); - assert!(res.is_some()); - - let doctest = res.unwrap(); - // imports are deduped - assert_eq!(1, doctest.imports.len()); - assert_eq!(doctest.bodies.len(), 2); - let body1 = &doctest.bodies[0]; - let body2 = &doctest.bodies[1]; - assert!(!body1.is_async); - assert!(!body2.is_async); - assert!(!body1.ignore); - assert!(body2.ignore); - assert_eq!(body1.caption, "Linkedlist.map".to_string()); - assert_eq!(body2.caption, "Linkedlist.map 2".to_string()); - assert_eq!(body1.line_number, 5); - assert_eq!(body2.line_number, 17); + extract_imports(&res), + vec!["import { LinkedList } from './js_test/linkedlist.ts'"] + ); + assert!(!has_await(&res)); + assert_eq!(extract_test_tag(&res), Some("ts")); assert_eq!( - body2.value, + extract_code_body(&res), vec![ - " const testArr = [1, 2, 3, 4, 5];", - " const testList = new LinkedList();", - " for (let data of testArr) {", - " testList.insertNode(data);", - " }", - " testList.map((c: number) => c ** 2);", - " testList.forEach((c: number, i: number) => assertEquals(c, testArr[i] ** 2));" + "const testArr = [1, 2, 3, 4, 5, 6, 78, 9, 0, 65];", + "const firstList = new LinkedList();", + "const secondList = new LinkedList();", + "for (let data of testArr) {", + "firstList.insertNode(data);", + "secondList.insertNode(data);", + "}", + "const result = firstList.compareWith(secondList);", + "assert.assert(result);" ] .join("\n") - ); - assert_eq!( - body1.value, - vec![ - " const testArr = [1, 2, 3, 4, 5, 6, 78, 9, 0, 65];", - " const testList = new LinkedList();", - " for (let data of testArr) {", - " testList.insertNode(data);", - " }", - " testList.map((c: number) => c ** 2);", - " testList.forEach((c: number, i: number) => assertEquals(c, testArr[i] ** 2));", - ].join("\n")); - } - - #[test] - fn test_code_without_jsdoc() { - let test = r#"class Node { - constructor(public data: T, public next?: Node) {} - - swap(other: Node) { - let temp = this.data; - this.data = other.data; - other.data = temp; - } - }"#; - let res = extract_jsdoc_examples(test.to_string(), PathBuf::from("user")); - assert!(res.is_none()); + ) } #[test] fn test_async_detection() { - let test = r#" /** - * @example - * ```ts - * const response = await fetch("https://deno.land"); - * const body = await response.text(); - * assert(body.length > 0); - * ``` - */"#; - - let res = extract_jsdoc_examples(test.to_string(), PathBuf::from("user")); - assert!(res.is_some()); - let doctest = res.unwrap(); - let body = &doctest.bodies[0]; - assert!(body.is_async); - } - - #[test] - fn test_text_tag() { - let test = r#" /** - * @example - * ```text - * const response = await fetch("https://deno.land"); - * const body = await response.text(); - * assert(body.length > 0); - * ``` - */"#; - - let res = extract_jsdoc_examples(test.to_string(), PathBuf::from("user")); - assert!(res.is_none()); - } - - #[test] - fn test_jump_example_without_backticks() { - let test = r#" /** - * @example - * const response = await fetch("https://deno.land"); - * const body = await response.text(); - * assert(body.length > 0); - */"#; - - let res = extract_jsdoc_examples(test.to_string(), PathBuf::from("user")); - assert!(res.is_none()); + let test = r#" + ```ts + const response = await fetch("https://deno.land"); + const body = await response.text(); + assert(body.length > 0); + ```"#; + assert!(has_await(&test)); } } diff --git a/cli/main.rs b/cli/main.rs index 5483af46f1a5b3..16c35f45b0f992 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -544,11 +544,13 @@ async fn test_command( let cwd = std::env::current_dir().expect("No current directory"); let include = include.unwrap_or_else(|| vec![".".to_string()]); - let test_modules = test_runner::prepare_test_modules_urls( - include, - &cwd, - test_runner::is_supported, - )?; + let test_files_filter = if docs { + doctest_runner::is_supported_doctest + } else { + test_runner::is_supported + }; + let test_modules = + test_runner::prepare_test_modules_urls(include, &cwd, test_files_filter)?; let is_empty = test_modules.is_empty(); if is_empty { @@ -559,6 +561,15 @@ async fn test_command( return Ok(()); } + if docs { + let jsdocs = doctest_runner::parse_jsdocs(&test_modules, flags).await?; + let res = + doctest_runner::prepare_doctests(jsdocs, fail_fast, quiet, filter); + std::fs::write("../js_test/res.ts", res)?; + // println!("{:#?}", res); + return Ok(()); + } + let test_file_path = cwd.join(".deno.test.ts"); let test_file_url = Url::from_file_path(&test_file_path).expect("Should be valid file url"); @@ -568,6 +579,11 @@ async fn test_command( quiet, filter, ); + // } else { + // let jsdocs = doctest_runner::parse_jsdocs(&test_modules, flags).await?; + // doctest_runner::prepare_doctests_new(jsdocs) + // }; + let main_module = ModuleSpecifier::resolve_url(&test_file_url.to_string()).unwrap(); let mut worker = MainWorker::create(&global_state, main_module.clone())?; From 5c77b29288f8533cfc8134c41baafd470bdabaea Mon Sep 17 00:00:00 2001 From: iykekings Date: Thu, 24 Sep 2020 23:11:39 +0100 Subject: [PATCH 16/44] completed rewrite --- cli/doctest_runner.rs | 10 +++++++--- cli/main.rs | 31 ++++++++++++------------------- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/cli/doctest_runner.rs b/cli/doctest_runner.rs index 321fe6215ebc73..7dfb9c1ff346dd 100644 --- a/cli/doctest_runner.rs +++ b/cli/doctest_runner.rs @@ -69,9 +69,13 @@ pub fn prepare_doctests( fail_fast: bool, quiet: bool, filter: Option, -) -> String { +) -> Result { let mut test_file = "import * as assert from \"https://deno.land/std@0.70.0/testing/asserts.ts\";\n".to_string(); let mut import_set = HashSet::new(); + let cwd = std::env::current_dir()?; + let cwd_url_str = Url::from_directory_path(cwd) + .map(|url| url.to_string()) + .unwrap_or("".to_string()); let tests: String = jsdocs .into_iter() .map(|(loc, example)| (loc, clean_string(&example))) @@ -87,7 +91,7 @@ pub fn prepare_doctests( let is_async = has_await(&x); let res = format!( "\nDeno.test({{\n\tname: \"{} - {} (line {})\",\n\tignore: {},\n\t{}fn() {{\n{}\n}}\n}});\n", - l.filename, + l.filename.replace(&cwd_url_str, ""), caption.unwrap_or(""), l.line, ignore, @@ -114,7 +118,7 @@ pub fn prepare_doctests( ); test_file.push_str(&run_tests_cmd); - test_file + Ok(test_file) } fn clean_string(input: &str) -> String { diff --git a/cli/main.rs b/cli/main.rs index 16c35f45b0f992..9433be316fd9bd 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -561,28 +561,21 @@ async fn test_command( return Ok(()); } - if docs { - let jsdocs = doctest_runner::parse_jsdocs(&test_modules, flags).await?; - let res = - doctest_runner::prepare_doctests(jsdocs, fail_fast, quiet, filter); - std::fs::write("../js_test/res.ts", res)?; - // println!("{:#?}", res); - return Ok(()); - } - let test_file_path = cwd.join(".deno.test.ts"); let test_file_url = Url::from_file_path(&test_file_path).expect("Should be valid file url"); - let test_file = test_runner::render_test_file( - test_modules.clone(), - fail_fast, - quiet, - filter, - ); - // } else { - // let jsdocs = doctest_runner::parse_jsdocs(&test_modules, flags).await?; - // doctest_runner::prepare_doctests_new(jsdocs) - // }; + + let test_file = if !docs { + test_runner::render_test_file( + test_modules.clone(), + fail_fast, + quiet, + filter, + ) + } else { + let jsdocs = doctest_runner::parse_jsdocs(&test_modules, flags).await?; + doctest_runner::prepare_doctests(jsdocs, fail_fast, quiet, filter)? + }; let main_module = ModuleSpecifier::resolve_url(&test_file_url.to_string()).unwrap(); From 85ebc0aa5bbbd5ae96a4fba2c45e8d1358142eff Mon Sep 17 00:00:00 2001 From: iykekings Date: Thu, 24 Sep 2020 23:48:04 +0100 Subject: [PATCH 17/44] issues with submodule From b934b586da2826833144a5c8a9a6a79c9b3667d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Fri, 25 Sep 2020 12:28:41 +0200 Subject: [PATCH 18/44] fix2 --- deno_typescript/typescript | 1 - third_party | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 160000 deno_typescript/typescript diff --git a/deno_typescript/typescript b/deno_typescript/typescript deleted file mode 160000 index 551f0dd9a1b57e..00000000000000 --- a/deno_typescript/typescript +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 551f0dd9a1b57ecd527a665b0af7fc98cd107af6 diff --git a/third_party b/third_party index 9ad53352a9bc7c..e80050929aec91 160000 --- a/third_party +++ b/third_party @@ -1 +1 @@ -Subproject commit 9ad53352a9bc7cd179d9e06663a097352514d389 +Subproject commit e80050929aec91d594d68fc01f3919de70a1dc3d From 178cf12a8a4c921fc44caef8047991343b2d98cb Mon Sep 17 00:00:00 2001 From: iykekings Date: Fri, 25 Sep 2020 11:38:33 +0100 Subject: [PATCH 19/44] update --- cli/doctest_runner.rs | 1 + std/wasi/testdata | 2 +- third_party | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cli/doctest_runner.rs b/cli/doctest_runner.rs index 7dfb9c1ff346dd..566af37fd228e7 100644 --- a/cli/doctest_runner.rs +++ b/cli/doctest_runner.rs @@ -2,6 +2,7 @@ use crate::ast; use crate::flags::Flags; use crate::global_state::GlobalState; use crate::media_type::MediaType; +use deno_core::serde_json::json; use deno_core::url::Url; use deno_core::{error::AnyError, ModuleSpecifier}; use deno_doc::DocParser; diff --git a/std/wasi/testdata b/std/wasi/testdata index 7f8aa6ba628a2b..f5c23108d0f191 160000 --- a/std/wasi/testdata +++ b/std/wasi/testdata @@ -1 +1 @@ -Subproject commit 7f8aa6ba628a2bea3612e50638b8c9c9c4bb71a8 +Subproject commit f5c23108d0f191e1f9ffc0fbc21ff7b123d5c90d diff --git a/third_party b/third_party index e80050929aec91..9ad53352a9bc7c 160000 --- a/third_party +++ b/third_party @@ -1 +1 @@ -Subproject commit e80050929aec91d594d68fc01f3919de70a1dc3d +Subproject commit 9ad53352a9bc7cd179d9e06663a097352514d389 From c81cd80adf8094a52ae581aadc422dc2eb33ea04 Mon Sep 17 00:00:00 2001 From: iykekings Date: Thu, 8 Oct 2020 18:11:54 +0100 Subject: [PATCH 20/44] rewrite completed --- cli/ast.rs | 6 +- cli/doctest_runner.rs | 196 +++++++++++++++++++++++++++++++++--------- 2 files changed, 160 insertions(+), 42 deletions(-) diff --git a/cli/ast.rs b/cli/ast.rs index 61c534e954eab2..b00deb1a4fc068 100644 --- a/cli/ast.rs +++ b/cli/ast.rs @@ -207,10 +207,10 @@ impl Default for TranspileOptions { /// processing. #[derive(Clone)] pub struct ParsedModule { - comments: SingleThreadedComments, + pub(crate) comments: SingleThreadedComments, leading_comments: Vec, - module: Module, - source_map: Rc, + pub(crate) module: Module, + pub(crate) source_map: Rc, } impl fmt::Debug for ParsedModule { diff --git a/cli/doctest_runner.rs b/cli/doctest_runner.rs index 566af37fd228e7..23d15ee2c489eb 100644 --- a/cli/doctest_runner.rs +++ b/cli/doctest_runner.rs @@ -1,4 +1,6 @@ -use crate::ast; +// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. + +use crate::ast::{self, Location}; use crate::flags::Flags; use crate::global_state::GlobalState; use crate::media_type::MediaType; @@ -6,30 +8,157 @@ use deno_core::serde_json::json; use deno_core::url::Url; use deno_core::{error::AnyError, ModuleSpecifier}; use deno_doc::DocParser; -use jsdoc::{self, ast::Tag, Input}; +use jsdoc::ast::Tag; +use jsdoc::Input; use regex::Regex; +use std::borrow::BorrowMut; +use std::cell::RefCell; use std::collections::HashSet; use std::ffi::OsStr; use std::path::{Path, PathBuf}; +use std::rc::Rc; +use swc_common::{comments::SingleThreadedComments, SourceMap, Span}; +use swc_ecmascript::visit::Visit; +use swc_ecmascript::{ + ast::{Class, Decl, ExportDecl, Expr, Function, Module, VarDecl}, + visit::Node, +}; use crate::test_runner::is_supported; lazy_static! { + // matches non-dynamic js imports static ref IMPORT_PATTERN: Regex = Regex::new(r#"import\s+?(?:(?:(?:[\w*\s{},]*)\s+from\s+?)|)(?:(?:".*?")|(?:'.*?'))[\s]*?(?:;|$|)"#).unwrap(); - static ref EXAMPLE_PATTERN: Regex = Regex::new(r"@example\s*(?:<\w+>.*)*\n(?:\s*\*\s*\n*)*```").unwrap(); static ref TEST_TAG_PATTERN: Regex = Regex::new(r"```(\w+)?").unwrap(); static ref AWAIT_PATTERN: Regex = Regex::new(r"\Wawait\s").unwrap(); + // matches jsdoc example caption static ref CAPTION_PATTERN: Regex = Regex::new(r"([\s\w\W]+)").unwrap(); - static ref TICKS_OR_IMPORT_PATTERN: Regex = - Regex::new(r"(?:import[^(].*)|(?:```\w*)").unwrap(); +} + +struct DocTestVisitor { + comments: SingleThreadedComments, + source_map: Rc, + examples: RefCell>, +} + +struct DocTester { + doctest_visitor: DocTestVisitor, + module: Module, +} + +impl DocTester { + fn new( + module: Module, + comments: SingleThreadedComments, + source_map: Rc, + ) -> Self { + Self { + doctest_visitor: DocTestVisitor::new(comments, source_map), + module, + } + } + pub fn get_comments(&mut self) -> Vec<(Location, String)> { + let visitor = self.doctest_visitor.borrow_mut(); + visitor.visit_module(&self.module, &self.module); + visitor.examples.clone().into_inner() + } +} + +impl DocTestVisitor { + fn new(comments: SingleThreadedComments, source_map: Rc) -> Self { + Self { + comments, + source_map, + examples: RefCell::new(vec![]), + } + } + + fn get_span_location(&self, span: Span) -> Location { + self.source_map.lookup_char_pos(span.lo()).into() + } + + fn parse_span_comments(&mut self, span: Span) { + let comments = self + .comments + .with_leading(span.lo, |comments| comments.to_vec()); + let examples = comments + .iter() + .map(|comment| { + jsdoc::parse(Input::from(comment)) + .expect("Unable to parse jsdoc") + .1 + }) + .flat_map(|js_doc| { + js_doc + .tags + .into_iter() + .filter_map(|tag_item| match tag_item.tag { + Tag::Example(ex_tag) => Some(( + self.get_span_location(ex_tag.text.span), + ex_tag.text.value.to_string(), + )), + _ => None, + }) + }); + self.examples.borrow_mut().extend(examples); + } + + fn check_var_decl( + &mut self, + var_decl: &VarDecl, + opt_export_decl: Option<&ExportDecl>, + ) { + var_decl.decls.iter().for_each(|decl| { + if let Some(expr) = &decl.init { + match &**expr { + Expr::Object(_) | Expr::Fn(_) | Expr::Class(_) | Expr::Arrow(_) => { + if let Some(export_decl) = opt_export_decl { + self.parse_span_comments(export_decl.span); + } else { + self.parse_span_comments(var_decl.span); + } + } + _ => {} + } + } + }); + } +} + +impl Visit for DocTestVisitor { + fn visit_class(&mut self, class: &Class, parent: &dyn Node) { + self.parse_span_comments(class.span); + swc_ecmascript::visit::visit_class(self, class, parent); + } + + fn visit_function(&mut self, function: &Function, parent: &dyn Node) { + self.parse_span_comments(function.span); + swc_ecmascript::visit::visit_function(self, function, parent); + } + + fn visit_var_decl(&mut self, var_decl: &VarDecl, parent: &dyn Node) { + self.check_var_decl(var_decl, None); + swc_ecmascript::visit::visit_var_decl(self, var_decl, parent); + } + + fn visit_export_decl(&mut self, export_decl: &ExportDecl, parent: &dyn Node) { + match &export_decl.decl { + Decl::Var(var_decl) => self.check_var_decl(var_decl, Some(export_decl)), + Decl::Class(_) | Decl::Fn(_) => { + self.parse_span_comments(export_decl.span) + } + _ => {} + } + swc_ecmascript::visit::visit_export_decl(self, export_decl, parent); + } } pub async fn parse_jsdocs( source_files: &Vec, flags: Flags, -) -> Result, AnyError> { +) -> Result, AnyError> { let global_state = GlobalState::new(flags.clone())?; let loader = Box::new(global_state.file_fetcher.clone()); @@ -41,60 +170,49 @@ pub async fn parse_jsdocs( let path = PathBuf::from(&url.to_string()); let media_type = MediaType::from(&path); let specifier = ModuleSpecifier::resolve_url(&url.to_string())?; - let module = ast::parse(&specifier, &source_code, &media_type)?; - - let result = module - .get_leading_comments() - .into_iter() - .map(|comment| { - jsdoc::parse(Input::from(&comment)) - .expect("Error Parsing Jsdoc") - .1 - }) - .flat_map(|jsdoc| jsdoc.tags) - .filter_map(|tag_item| match tag_item.tag { - Tag::Example(ex_tag) => Some(( - module.get_location(&ex_tag.text.span), - ex_tag.text.value.to_string(), - )), - _ => None, - }) - .collect::>(); - results.extend(result); + let parsed_module = ast::parse(&specifier, &source_code, &media_type)?; + let mut doc_tester = DocTester::new( + parsed_module.module, + parsed_module.comments, + Rc::clone(&parsed_module.source_map), + ); + results.extend(doc_tester.get_comments()); } Ok(results) } pub fn prepare_doctests( - jsdocs: Vec<(ast::Location, String)>, + jsdocs: Vec<(Location, String)>, fail_fast: bool, quiet: bool, filter: Option, ) -> Result { let mut test_file = "import * as assert from \"https://deno.land/std@0.70.0/testing/asserts.ts\";\n".to_string(); let mut import_set = HashSet::new(); + let cwd = std::env::current_dir()?; let cwd_url_str = Url::from_directory_path(cwd) .map(|url| url.to_string()) .unwrap_or("".to_string()); + let tests: String = jsdocs .into_iter() - .map(|(loc, example)| (loc, clean_string(&example))) - .filter_map(|(l, x)| { - let test_tag = extract_test_tag(&x); + .filter_map(|(loc, example)| { + let ex_str = clean_string(&example); + let test_tag = extract_test_tag(&ex_str); if test_tag == Some("text") { return None; } let ignore = test_tag == Some("ignore"); - extract_imports(&x).into_iter().for_each(|import| { import_set.insert(import.to_string()); }); - let caption = extract_caption(&x); - let code_body = extract_code_body(&x); - let is_async = has_await(&x); + extract_imports(&ex_str).into_iter().for_each(|import| { import_set.insert(import.to_string()); }); + let caption = extract_caption(&ex_str); + let code_body = extract_code_body(&ex_str); + let is_async = has_await(&ex_str); let res = format!( - "\nDeno.test({{\n\tname: \"{} - {} (line {})\",\n\tignore: {},\n\t{}fn() {{\n{}\n}}\n}});\n", - l.filename.replace(&cwd_url_str, ""), + "\nDeno.test({{\n\tname: \"{} - {} (line {})\",\n\tignore: {},\n\t{} fn() {{\n{}\n}}\n}});\n", + loc.filename.replace(&cwd_url_str, ""), caption.unwrap_or(""), - l.line, + loc.line, ignore, if is_async { "async"} else {""}, code_body @@ -194,7 +312,7 @@ fn extract_code_body(ex: &str) -> String { mod test { use super::*; #[test] - fn test_extract_jsdoc() { + fn test_extract_fns() { let test = r#"Linkedlists.compareWith * ```ts * import { LinkedList } from './js_test/linkedlist.ts' @@ -206,7 +324,7 @@ mod test { * secondList.insertNode(data); * } * const result = firstList.compareWith(secondList); - * assert(result); + * assert.assert(result); ```"#; let res = clean_string(test); assert_eq!(extract_caption(&res), Some("Linkedlists.compareWith")); From 062ad634a6a8484114e4e55546202938894e908b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Thu, 8 Oct 2020 20:04:01 +0200 Subject: [PATCH 21/44] sync with master --- Cargo.lock | 266 ++++++++++++++++++++++++++-------------------- std/wasi/testdata | 2 +- third_party | 2 +- 3 files changed, 151 insertions(+), 119 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a421d0e8876407..c6e6b3554029ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,9 +60,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.32" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b" +checksum = "a1fd36ffbb1fb7c834eac128ea8d0e310c5aeb635548f9d58861e1308d46e71c" [[package]] name = "anymap" @@ -90,10 +90,10 @@ checksum = "fd6ee2941db3551563d29eaf5214cd3d7b2f322e0c0e3954f5ae020f860bae8c" dependencies = [ "darling", "pmutil", - "proc-macro2 1.0.21", + "proc-macro2 1.0.24", "quote 1.0.7", "swc_macros_common", - "syn 1.0.41", + "syn 1.0.42", ] [[package]] @@ -244,9 +244,9 @@ checksum = "5ba7d7f7b201dfcbc314b14f2176c92f8ba521dab538b40e426ffed25ed7cd80" [[package]] name = "cc" -version = "1.0.59" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66120af515773fb005778dc07c261bd201ec8ce50bd6e7144c927753fe013381" +checksum = "ef611cc68ff783f18535d77ddd080185275713d852c4f5cbb6122c462a7a825c" [[package]] name = "cfg-if" @@ -256,13 +256,15 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "chrono" -version = "0.4.15" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942f72db697d8767c22d46a598e01f2d3b475501ea43d0db4f16d90259182d0b" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" dependencies = [ + "libc", "num-integer", "num-traits", "time", + "winapi 0.3.9", ] [[package]] @@ -291,9 +293,9 @@ dependencies = [ [[package]] name = "const-random" -version = "0.1.8" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f1af9ac737b2dd2d577701e59fd09ba34822f6f2ebdb30a7647405d9e55e16a" +checksum = "02dc82c12dc2ee6e1ded861cf7d582b46f66f796d1b6c93fa28b911ead95da02" dependencies = [ "const-random-macro", "proc-macro-hack", @@ -301,11 +303,11 @@ dependencies = [ [[package]] name = "const-random-macro" -version = "0.1.8" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25e4c606eb459dd29f7c57b2e0879f2b6f14ee130918c2b78ccb58a9624e6c7a" +checksum = "fc757bbb9544aa296c2ae00c679e81f886b37e28e59097defe0cf524306f6685" dependencies = [ - "getrandom", + "getrandom 0.2.0", "proc-macro-hack", ] @@ -363,10 +365,10 @@ checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.21", + "proc-macro2 1.0.24", "quote 1.0.7", "strsim 0.9.3", - "syn 1.0.41", + "syn 1.0.42", ] [[package]] @@ -377,7 +379,7 @@ checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" dependencies = [ "darling_core", "quote 1.0.7", - "syn 1.0.41", + "syn 1.0.42", ] [[package]] @@ -415,7 +417,7 @@ dependencies = [ "fwdansi", "http", "indexmap", - "jsdoc", + "jsdoc 0.5.1", "jsonc-parser", "lazy_static", "libc", @@ -567,9 +569,9 @@ dependencies = [ [[package]] name = "dprint-core" -version = "0.31.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15e15225efcb6eccd138dea49bf7aa390248ab0faf650b1b8a7ad660a5778cc" +checksum = "82289fa5343ce6ca1c3731574a12260f003ab953c16edf3b4561f3dbadcd32ec" dependencies = [ "serde", ] @@ -594,9 +596,9 @@ checksum = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b" [[package]] name = "either" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56b59865bce947ac5958779cfa508f6c3b9497cc762b7e24a12d11ccde2c4f" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] name = "encoding_rs" @@ -614,9 +616,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e57153e35187d51f08471d5840459ff29093473e7bedd004a1414985aab92f3" dependencies = [ "pmutil", - "proc-macro2 1.0.21", + "proc-macro2 1.0.24", "swc_macros_common", - "syn 1.0.41", + "syn 1.0.42", ] [[package]] @@ -663,9 +665,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "766d0e77a2c1502169d4a93ff3b8c15a71fd946cd0126309752104e5f3c46d94" +checksum = "da80be589a72651dcda34d8b35bcdc9b7254ad06325611074d9cc0fbb19f60ee" dependencies = [ "cfg-if", "crc32fast", @@ -686,9 +688,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "039885ad6579a86b94ad8df696cce8c530da496bf7b07b12fec8d6c4cd654bb9" dependencies = [ "pmutil", - "proc-macro2 1.0.21", + "proc-macro2 1.0.24", "swc_macros_common", - "syn 1.0.41", + "syn 1.0.42", ] [[package]] @@ -734,9 +736,9 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" [[package]] name = "futures" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e05b85ec287aac0dc34db7d4a569323df697f9c55b99b15d6b4ef8cde49f613" +checksum = "5d8e3078b7b2a8a671cb7a3d17b4760e4181ea243227776ba83fd043b4ca034e" dependencies = [ "futures-channel", "futures-core", @@ -749,9 +751,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f366ad74c28cca6ba456d95e6422883cfb4b252a83bed929c83abfdbbf2967d5" +checksum = "a7a4d35f7401e948629c9c3d6638fb9bf94e0b2121e96c3b428cc4e631f3eb74" dependencies = [ "futures-core", "futures-sink", @@ -759,15 +761,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399" +checksum = "d674eaa0056896d5ada519900dbf97ead2e46a7b6621e8160d79e2f2e1e2784b" [[package]] name = "futures-executor" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10d6bb888be1153d3abeb9006b11b02cf5e9b209fda28693c31ae1e4e012e314" +checksum = "cc709ca1da6f66143b8c9bec8e6260181869893714e9b5a490b169b0414144ab" dependencies = [ "futures-core", "futures-task", @@ -776,42 +778,42 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de27142b013a8e869c14957e6d2edeef89e97c289e69d042ee3a49acd8b51789" +checksum = "5fc94b64bb39543b4e432f1790b6bf18e3ee3b74653c5449f63310e9a74b123c" [[package]] name = "futures-macro" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0b5a30a4328ab5473878237c447333c093297bded83a4983d10f4deea240d39" +checksum = "f57ed14da4603b2554682e9f2ff3c65d7567b53188db96cb71538217fc64581b" dependencies = [ "proc-macro-hack", - "proc-macro2 1.0.21", + "proc-macro2 1.0.24", "quote 1.0.7", - "syn 1.0.41", + "syn 1.0.42", ] [[package]] name = "futures-sink" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f2032893cb734c7a05d85ce0cc8b8c4075278e93b24b66f9de99d6eb0fa8acc" +checksum = "0d8764258ed64ebc5d9ed185cf86a95db5cac810269c5d20ececb32e0088abbd" [[package]] name = "futures-task" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb66b5f09e22019b1ab0830f7785bcea8e7a42148683f99214f73f8ec21a626" +checksum = "4dd26820a9f3637f1302da8bceba3ff33adbe53464b54ca24d4e2d4f1db30f94" dependencies = [ "once_cell", ] [[package]] name = "futures-util" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6" +checksum = "8a894a0acddba51a2d49a6f4263b1e64b8c579ece8af50fa86503d52cd1eea34" dependencies = [ "futures-channel", "futures-core", @@ -876,6 +878,17 @@ dependencies = [ "wasi 0.9.0+wasi-snapshot-preview1", ] +[[package]] +name = "getrandom" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee8025cf36f917e6a52cce185b7c7177689b838b7ec138364e50cc2277a56cf4" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + [[package]] name = "h2" version = "0.2.6" @@ -897,9 +910,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00d63df3d41950fb462ed38308eea019113ad1508da725bbedcd0fa5a85ef5f7" +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" [[package]] name = "headers" @@ -928,9 +941,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.15" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" +checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" dependencies = [ "libc", ] @@ -962,6 +975,12 @@ version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" +[[package]] +name = "httpdate" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47" + [[package]] name = "humantime" version = "1.3.0" @@ -973,9 +992,9 @@ dependencies = [ [[package]] name = "hyper" -version = "0.13.7" +version = "0.13.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e68a8dd9716185d9e64ea473ea6ef63529252e3e27623295a0378a19665d5eb" +checksum = "2f3afcfae8af5ad0576a31e768415edb627824129e8e5a29b8bfccb2f234e835" dependencies = [ "bytes", "futures-channel", @@ -985,10 +1004,10 @@ dependencies = [ "http", "http-body", "httparse", + "httpdate", "itoa", "pin-project", "socket2", - "time", "tokio", "tower-service", "tracing", @@ -1030,9 +1049,9 @@ dependencies = [ [[package]] name = "if_chain" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3360c7b59e5ffa2653671fb74b4741a5d343c03f331c0a4aeda42b5c2b0ec7d" +checksum = "1f7280c75fb2e2fc47080ec80ccc481376923acb04501957fc38f935c3de5088" [[package]] name = "indexmap" @@ -1096,9 +1115,9 @@ checksum = "04807f3dc9e3ea39af3f8469a5297267faf94859637afb836b33f47d9b2650ee" dependencies = [ "Inflector", "pmutil", - "proc-macro2 1.0.21", + "proc-macro2 1.0.24", "quote 1.0.7", - "syn 1.0.41", + "syn 1.0.42", ] [[package]] @@ -1116,6 +1135,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "jsdoc" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb0392aa1730824b8359786500d1e1812a8fe4f220bb97a799a4390cf302d9d" +dependencies = [ + "nom", + "serde", + "swc_atoms", + "swc_common", +] + [[package]] name = "jsdoc" version = "0.6.0" @@ -1171,9 +1202,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.77" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235" +checksum = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743" [[package]] name = "log" @@ -1220,9 +1251,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c60c0dfe32c10b43a144bad8fc83538c52f58302c92300ea7ec7bf7b38d5a7b9" +checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d" dependencies = [ "adler", "autocfg 1.0.1", @@ -1505,9 +1536,9 @@ dependencies = [ "phf_generator", "phf_shared", "proc-macro-hack", - "proc-macro2 1.0.21", + "proc-macro2 1.0.24", "quote 1.0.7", - "syn 1.0.41", + "syn 1.0.42", ] [[package]] @@ -1521,29 +1552,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "0.4.23" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca4433fff2ae79342e497d9f8ee990d174071408f28f726d6d83af93e58e48aa" +checksum = "13fbdfd6bdee3dc9be46452f86af4a4072975899cf8592466668620bebfbcc17" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "0.4.23" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c0e815c3ee9a031fdf5af21c10aa17c573c9c6a566328d99e3936c34e36461f" +checksum = "c82fb1329f632c3552cf352d14427d57a511b1cf41db93b3a7d77906a82dcc8e" dependencies = [ - "proc-macro2 1.0.21", + "proc-macro2 1.0.24", "quote 1.0.7", - "syn 1.0.41", + "syn 1.0.42", ] [[package]] name = "pin-project-lite" -version = "0.1.7" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282adbf10f2698a7a77f8e983a74b2d18176c19a7fd32a45446139ae7b02b715" +checksum = "e555d9e657502182ac97b539fb3dae8b79cda19e3e4f8ffb5e8de4f18df93c95" [[package]] name = "pin-utils" @@ -1557,9 +1588,9 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3894e5d549cccbe44afecf72922f277f603cd4bb0219c8342631ef18fffbe004" dependencies = [ - "proc-macro2 1.0.21", + "proc-macro2 1.0.24", "quote 1.0.7", - "syn 1.0.41", + "syn 1.0.42", ] [[package]] @@ -1597,9 +1628,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.21" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36e28516df94f3dd551a587da5357459d9b36d945a7c37c3557928c1c2ff2a2c" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" dependencies = [ "unicode-xid 0.2.1", ] @@ -1635,7 +1666,7 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" dependencies = [ - "proc-macro2 1.0.21", + "proc-macro2 1.0.24", ] [[package]] @@ -1663,7 +1694,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom", + "getrandom 0.1.15", "libc", "rand_chacha 0.2.2", "rand_core 0.5.1", @@ -1712,7 +1743,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom", + "getrandom 0.1.15", ] [[package]] @@ -1955,7 +1986,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54a50e29610a5be68d4a586a5cce3bfb572ed2c2a74227e4168444b7bf4e5235" dependencies = [ "quote 1.0.7", - "syn 1.0.41", + "syn 1.0.42", ] [[package]] @@ -2037,16 +2068,16 @@ version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8" dependencies = [ - "proc-macro2 1.0.21", + "proc-macro2 1.0.24", "quote 1.0.7", - "syn 1.0.41", + "syn 1.0.42", ] [[package]] name = "serde_json" -version = "1.0.57" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c" +checksum = "a230ea9107ca2220eea9d46de97eddcb04cd00e92d13dda78e478dd33fa82bd4" dependencies = [ "indexmap", "itoa", @@ -2186,7 +2217,7 @@ checksum = "f24c8e5e19d22a726626f1a5e16fe15b132dcf21d10177fa5a45ce7962996b97" dependencies = [ "phf_generator", "phf_shared", - "proc-macro2 1.0.21", + "proc-macro2 1.0.24", "quote 1.0.7", ] @@ -2197,10 +2228,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94fdb6536756cfd35ee18b9a9972ab2a699d405cc57e0ad0532022960f30d581" dependencies = [ "pmutil", - "proc-macro2 1.0.21", + "proc-macro2 1.0.24", "quote 1.0.7", "swc_macros_common", - "syn 1.0.41", + "syn 1.0.42", ] [[package]] @@ -2283,10 +2314,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04378143fd1296af71dd3aea2e096bef6fbf8aa3c25352d44d62d7f28aa9851b" dependencies = [ "pmutil", - "proc-macro2 1.0.21", + "proc-macro2 1.0.24", "quote 1.0.7", "swc_macros_common", - "syn 1.0.41", + "syn 1.0.42", ] [[package]] @@ -2329,10 +2360,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8798810e2c79b884cf238bcb72b4bd12375121ee91724f1ceeb54b6e38a138e7" dependencies = [ "pmutil", - "proc-macro2 1.0.21", + "proc-macro2 1.0.24", "quote 1.0.7", "swc_macros_common", - "syn 1.0.41", + "syn 1.0.42", ] [[package]] @@ -2348,7 +2379,7 @@ dependencies = [ "fxhash", "indexmap", "is-macro", - "jsdoc", + "jsdoc 0.6.0", "log", "once_cell", "ordered-float", @@ -2376,10 +2407,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38c0b511705a737ef07d347f0fe5af22ef11ead65f6be58010d897426a60a70d" dependencies = [ "pmutil", - "proc-macro2 1.0.21", + "proc-macro2 1.0.24", "quote 1.0.7", "swc_macros_common", - "syn 1.0.41", + "syn 1.0.42", ] [[package]] @@ -2432,9 +2463,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18a9f27d290938370597d363df9a77ba4be8e2bc99f32f69eb5245cdeed3c512" dependencies = [ "pmutil", - "proc-macro2 1.0.21", + "proc-macro2 1.0.24", "quote 1.0.7", - "syn 1.0.41", + "syn 1.0.42", ] [[package]] @@ -2455,10 +2486,10 @@ checksum = "59a75265aea70df7a405e2aafb104c976017fe9a54e7b770017d0583873a3cff" dependencies = [ "Inflector", "pmutil", - "proc-macro2 1.0.21", + "proc-macro2 1.0.24", "quote 1.0.7", "swc_macros_common", - "syn 1.0.41", + "syn 1.0.42", ] [[package]] @@ -2474,11 +2505,11 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.41" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6690e3e9f692504b941dc6c3b188fd28df054f7fb8469ab40680df52fdcc842b" +checksum = "9c51d92969d209b54a98397e1b91c8ae82d8c87a7bb87df0b29aa2ad81454228" dependencies = [ - "proc-macro2 1.0.21", + "proc-macro2 1.0.24", "quote 1.0.7", "unicode-xid 0.2.1", ] @@ -2551,22 +2582,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dfdd070ccd8ccb78f4ad66bf1982dc37f620ef696c6b5028fe2ed83dd3d0d08" +checksum = "318234ffa22e0920fe9a40d7b8369b5f649d490980cf7aadcf1eb91594869b42" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793" +checksum = "cae2447b6282786c3493999f40a9be2a6ad20cb8bd268b0a0dbf5a065535c0ab" dependencies = [ - "proc-macro2 1.0.21", + "proc-macro2 1.0.24", "quote 1.0.7", - "syn 1.0.41", + "syn 1.0.42", ] [[package]] @@ -2625,9 +2656,9 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0c3acc6aa564495a0f2e1d59fab677cd7f81a19994cfc7f3ad0e64301560389" dependencies = [ - "proc-macro2 1.0.21", + "proc-macro2 1.0.24", "quote 1.0.7", - "syn 1.0.41", + "syn 1.0.42", ] [[package]] @@ -2686,20 +2717,21 @@ checksum = "e987b6bf443f4b5b3b6f38704195592cca41c5bb7aedd3c3693c7081f8289860" [[package]] name = "tracing" -version = "0.1.19" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d79ca061b032d6ce30c660fded31189ca0b9922bf483cd70759f13a2d86786c" +checksum = "b0987850db3733619253fe60e17cb59b82d37c7e6c0236bb81e4d6b87c879f27" dependencies = [ "cfg-if", "log", + "pin-project-lite", "tracing-core", ] [[package]] name = "tracing-core" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bcf46c1f1f06aeea2d6b81f3c863d0930a596c86ad1920d4e5bad6dd1d7119a" +checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f" dependencies = [ "lazy_static", ] @@ -2944,9 +2976,9 @@ dependencies = [ "bumpalo", "lazy_static", "log", - "proc-macro2 1.0.21", + "proc-macro2 1.0.24", "quote 1.0.7", - "syn 1.0.41", + "syn 1.0.42", "wasm-bindgen-shared", ] @@ -2978,9 +3010,9 @@ version = "0.2.68" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f249f06ef7ee334cc3b8ff031bfc11ec99d00f34d86da7498396dc1e3b1498fe" dependencies = [ - "proc-macro2 1.0.21", + "proc-macro2 1.0.24", "quote 1.0.7", - "syn 1.0.41", + "syn 1.0.42", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/std/wasi/testdata b/std/wasi/testdata index f5c23108d0f191..7f8aa6ba628a2b 160000 --- a/std/wasi/testdata +++ b/std/wasi/testdata @@ -1 +1 @@ -Subproject commit f5c23108d0f191e1f9ffc0fbc21ff7b123d5c90d +Subproject commit 7f8aa6ba628a2bea3612e50638b8c9c9c4bb71a8 diff --git a/third_party b/third_party index 9ad53352a9bc7c..e80050929aec91 160000 --- a/third_party +++ b/third_party @@ -1 +1 @@ -Subproject commit 9ad53352a9bc7cd179d9e06663a097352514d389 +Subproject commit e80050929aec91d594d68fc01f3919de70a1dc3d From c68e7266d11880390dc43888bfeaa7b2c9f47283 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Thu, 8 Oct 2020 20:06:41 +0200 Subject: [PATCH 22/44] sync with master2 --- Cargo.lock | 250 ++++++++++++++++++++++++----------------------------- 1 file changed, 115 insertions(+), 135 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c6e6b3554029ed..5fb90e3bc92fdf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,9 +60,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.33" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1fd36ffbb1fb7c834eac128ea8d0e310c5aeb635548f9d58861e1308d46e71c" +checksum = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b" [[package]] name = "anymap" @@ -90,10 +90,10 @@ checksum = "fd6ee2941db3551563d29eaf5214cd3d7b2f322e0c0e3954f5ae020f860bae8c" dependencies = [ "darling", "pmutil", - "proc-macro2 1.0.24", + "proc-macro2 1.0.21", "quote 1.0.7", "swc_macros_common", - "syn 1.0.42", + "syn 1.0.41", ] [[package]] @@ -244,9 +244,9 @@ checksum = "5ba7d7f7b201dfcbc314b14f2176c92f8ba521dab538b40e426ffed25ed7cd80" [[package]] name = "cc" -version = "1.0.60" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef611cc68ff783f18535d77ddd080185275713d852c4f5cbb6122c462a7a825c" +checksum = "66120af515773fb005778dc07c261bd201ec8ce50bd6e7144c927753fe013381" [[package]] name = "cfg-if" @@ -256,15 +256,13 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "chrono" -version = "0.4.19" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +checksum = "942f72db697d8767c22d46a598e01f2d3b475501ea43d0db4f16d90259182d0b" dependencies = [ - "libc", "num-integer", "num-traits", "time", - "winapi 0.3.9", ] [[package]] @@ -293,9 +291,9 @@ dependencies = [ [[package]] name = "const-random" -version = "0.1.11" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02dc82c12dc2ee6e1ded861cf7d582b46f66f796d1b6c93fa28b911ead95da02" +checksum = "2f1af9ac737b2dd2d577701e59fd09ba34822f6f2ebdb30a7647405d9e55e16a" dependencies = [ "const-random-macro", "proc-macro-hack", @@ -303,11 +301,11 @@ dependencies = [ [[package]] name = "const-random-macro" -version = "0.1.11" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc757bbb9544aa296c2ae00c679e81f886b37e28e59097defe0cf524306f6685" +checksum = "25e4c606eb459dd29f7c57b2e0879f2b6f14ee130918c2b78ccb58a9624e6c7a" dependencies = [ - "getrandom 0.2.0", + "getrandom", "proc-macro-hack", ] @@ -365,10 +363,10 @@ checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.24", + "proc-macro2 1.0.21", "quote 1.0.7", "strsim 0.9.3", - "syn 1.0.42", + "syn 1.0.41", ] [[package]] @@ -379,7 +377,7 @@ checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" dependencies = [ "darling_core", "quote 1.0.7", - "syn 1.0.42", + "syn 1.0.41", ] [[package]] @@ -569,9 +567,9 @@ dependencies = [ [[package]] name = "dprint-core" -version = "0.31.1" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82289fa5343ce6ca1c3731574a12260f003ab953c16edf3b4561f3dbadcd32ec" +checksum = "a15e15225efcb6eccd138dea49bf7aa390248ab0faf650b1b8a7ad660a5778cc" dependencies = [ "serde", ] @@ -596,9 +594,9 @@ checksum = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b" [[package]] name = "either" -version = "1.6.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +checksum = "cd56b59865bce947ac5958779cfa508f6c3b9497cc762b7e24a12d11ccde2c4f" [[package]] name = "encoding_rs" @@ -616,9 +614,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e57153e35187d51f08471d5840459ff29093473e7bedd004a1414985aab92f3" dependencies = [ "pmutil", - "proc-macro2 1.0.24", + "proc-macro2 1.0.21", "swc_macros_common", - "syn 1.0.42", + "syn 1.0.41", ] [[package]] @@ -665,9 +663,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.18" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da80be589a72651dcda34d8b35bcdc9b7254ad06325611074d9cc0fbb19f60ee" +checksum = "766d0e77a2c1502169d4a93ff3b8c15a71fd946cd0126309752104e5f3c46d94" dependencies = [ "cfg-if", "crc32fast", @@ -688,9 +686,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "039885ad6579a86b94ad8df696cce8c530da496bf7b07b12fec8d6c4cd654bb9" dependencies = [ "pmutil", - "proc-macro2 1.0.24", + "proc-macro2 1.0.21", "swc_macros_common", - "syn 1.0.42", + "syn 1.0.41", ] [[package]] @@ -736,9 +734,9 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" [[package]] name = "futures" -version = "0.3.6" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d8e3078b7b2a8a671cb7a3d17b4760e4181ea243227776ba83fd043b4ca034e" +checksum = "1e05b85ec287aac0dc34db7d4a569323df697f9c55b99b15d6b4ef8cde49f613" dependencies = [ "futures-channel", "futures-core", @@ -751,9 +749,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.6" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a4d35f7401e948629c9c3d6638fb9bf94e0b2121e96c3b428cc4e631f3eb74" +checksum = "f366ad74c28cca6ba456d95e6422883cfb4b252a83bed929c83abfdbbf2967d5" dependencies = [ "futures-core", "futures-sink", @@ -761,15 +759,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.6" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d674eaa0056896d5ada519900dbf97ead2e46a7b6621e8160d79e2f2e1e2784b" +checksum = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399" [[package]] name = "futures-executor" -version = "0.3.6" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc709ca1da6f66143b8c9bec8e6260181869893714e9b5a490b169b0414144ab" +checksum = "10d6bb888be1153d3abeb9006b11b02cf5e9b209fda28693c31ae1e4e012e314" dependencies = [ "futures-core", "futures-task", @@ -778,42 +776,42 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.6" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc94b64bb39543b4e432f1790b6bf18e3ee3b74653c5449f63310e9a74b123c" +checksum = "de27142b013a8e869c14957e6d2edeef89e97c289e69d042ee3a49acd8b51789" [[package]] name = "futures-macro" -version = "0.3.6" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f57ed14da4603b2554682e9f2ff3c65d7567b53188db96cb71538217fc64581b" +checksum = "d0b5a30a4328ab5473878237c447333c093297bded83a4983d10f4deea240d39" dependencies = [ "proc-macro-hack", - "proc-macro2 1.0.24", + "proc-macro2 1.0.21", "quote 1.0.7", - "syn 1.0.42", + "syn 1.0.41", ] [[package]] name = "futures-sink" -version = "0.3.6" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d8764258ed64ebc5d9ed185cf86a95db5cac810269c5d20ececb32e0088abbd" +checksum = "3f2032893cb734c7a05d85ce0cc8b8c4075278e93b24b66f9de99d6eb0fa8acc" [[package]] name = "futures-task" -version = "0.3.6" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dd26820a9f3637f1302da8bceba3ff33adbe53464b54ca24d4e2d4f1db30f94" +checksum = "bdb66b5f09e22019b1ab0830f7785bcea8e7a42148683f99214f73f8ec21a626" dependencies = [ "once_cell", ] [[package]] name = "futures-util" -version = "0.3.6" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a894a0acddba51a2d49a6f4263b1e64b8c579ece8af50fa86503d52cd1eea34" +checksum = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6" dependencies = [ "futures-channel", "futures-core", @@ -878,17 +876,6 @@ dependencies = [ "wasi 0.9.0+wasi-snapshot-preview1", ] -[[package]] -name = "getrandom" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee8025cf36f917e6a52cce185b7c7177689b838b7ec138364e50cc2277a56cf4" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "h2" version = "0.2.6" @@ -910,9 +897,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.9.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" +checksum = "00d63df3d41950fb462ed38308eea019113ad1508da725bbedcd0fa5a85ef5f7" [[package]] name = "headers" @@ -941,9 +928,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.17" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" +checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" dependencies = [ "libc", ] @@ -975,12 +962,6 @@ version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" -[[package]] -name = "httpdate" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "494b4d60369511e7dea41cf646832512a94e542f68bb9c49e54518e0f468eb47" - [[package]] name = "humantime" version = "1.3.0" @@ -992,9 +973,9 @@ dependencies = [ [[package]] name = "hyper" -version = "0.13.8" +version = "0.13.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f3afcfae8af5ad0576a31e768415edb627824129e8e5a29b8bfccb2f234e835" +checksum = "3e68a8dd9716185d9e64ea473ea6ef63529252e3e27623295a0378a19665d5eb" dependencies = [ "bytes", "futures-channel", @@ -1004,10 +985,10 @@ dependencies = [ "http", "http-body", "httparse", - "httpdate", "itoa", "pin-project", "socket2", + "time", "tokio", "tower-service", "tracing", @@ -1049,9 +1030,9 @@ dependencies = [ [[package]] name = "if_chain" -version = "1.0.1" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f7280c75fb2e2fc47080ec80ccc481376923acb04501957fc38f935c3de5088" +checksum = "c3360c7b59e5ffa2653671fb74b4741a5d343c03f331c0a4aeda42b5c2b0ec7d" [[package]] name = "indexmap" @@ -1115,9 +1096,9 @@ checksum = "04807f3dc9e3ea39af3f8469a5297267faf94859637afb836b33f47d9b2650ee" dependencies = [ "Inflector", "pmutil", - "proc-macro2 1.0.24", + "proc-macro2 1.0.21", "quote 1.0.7", - "syn 1.0.42", + "syn 1.0.41", ] [[package]] @@ -1202,9 +1183,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.79" +version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2448f6066e80e3bfc792e9c98bf705b4b0fc6e8ef5b43e5889aff0eaa9c58743" +checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235" [[package]] name = "log" @@ -1251,9 +1232,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.4.3" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f2d26ec3309788e423cfbf68ad1800f061638098d76a83681af979dc4eda19d" +checksum = "c60c0dfe32c10b43a144bad8fc83538c52f58302c92300ea7ec7bf7b38d5a7b9" dependencies = [ "adler", "autocfg 1.0.1", @@ -1536,9 +1517,9 @@ dependencies = [ "phf_generator", "phf_shared", "proc-macro-hack", - "proc-macro2 1.0.24", + "proc-macro2 1.0.21", "quote 1.0.7", - "syn 1.0.42", + "syn 1.0.41", ] [[package]] @@ -1552,29 +1533,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "0.4.26" +version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13fbdfd6bdee3dc9be46452f86af4a4072975899cf8592466668620bebfbcc17" +checksum = "ca4433fff2ae79342e497d9f8ee990d174071408f28f726d6d83af93e58e48aa" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "0.4.26" +version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c82fb1329f632c3552cf352d14427d57a511b1cf41db93b3a7d77906a82dcc8e" +checksum = "2c0e815c3ee9a031fdf5af21c10aa17c573c9c6a566328d99e3936c34e36461f" dependencies = [ - "proc-macro2 1.0.24", + "proc-macro2 1.0.21", "quote 1.0.7", - "syn 1.0.42", + "syn 1.0.41", ] [[package]] name = "pin-project-lite" -version = "0.1.10" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e555d9e657502182ac97b539fb3dae8b79cda19e3e4f8ffb5e8de4f18df93c95" +checksum = "282adbf10f2698a7a77f8e983a74b2d18176c19a7fd32a45446139ae7b02b715" [[package]] name = "pin-utils" @@ -1588,9 +1569,9 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3894e5d549cccbe44afecf72922f277f603cd4bb0219c8342631ef18fffbe004" dependencies = [ - "proc-macro2 1.0.24", + "proc-macro2 1.0.21", "quote 1.0.7", - "syn 1.0.42", + "syn 1.0.41", ] [[package]] @@ -1628,9 +1609,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.24" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +checksum = "36e28516df94f3dd551a587da5357459d9b36d945a7c37c3557928c1c2ff2a2c" dependencies = [ "unicode-xid 0.2.1", ] @@ -1666,7 +1647,7 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" dependencies = [ - "proc-macro2 1.0.24", + "proc-macro2 1.0.21", ] [[package]] @@ -1694,7 +1675,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom 0.1.15", + "getrandom", "libc", "rand_chacha 0.2.2", "rand_core 0.5.1", @@ -1743,7 +1724,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom 0.1.15", + "getrandom", ] [[package]] @@ -1986,7 +1967,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54a50e29610a5be68d4a586a5cce3bfb572ed2c2a74227e4168444b7bf4e5235" dependencies = [ "quote 1.0.7", - "syn 1.0.42", + "syn 1.0.41", ] [[package]] @@ -2068,16 +2049,16 @@ version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8" dependencies = [ - "proc-macro2 1.0.24", + "proc-macro2 1.0.21", "quote 1.0.7", - "syn 1.0.42", + "syn 1.0.41", ] [[package]] name = "serde_json" -version = "1.0.58" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a230ea9107ca2220eea9d46de97eddcb04cd00e92d13dda78e478dd33fa82bd4" +checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c" dependencies = [ "indexmap", "itoa", @@ -2217,7 +2198,7 @@ checksum = "f24c8e5e19d22a726626f1a5e16fe15b132dcf21d10177fa5a45ce7962996b97" dependencies = [ "phf_generator", "phf_shared", - "proc-macro2 1.0.24", + "proc-macro2 1.0.21", "quote 1.0.7", ] @@ -2228,10 +2209,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94fdb6536756cfd35ee18b9a9972ab2a699d405cc57e0ad0532022960f30d581" dependencies = [ "pmutil", - "proc-macro2 1.0.24", + "proc-macro2 1.0.21", "quote 1.0.7", "swc_macros_common", - "syn 1.0.42", + "syn 1.0.41", ] [[package]] @@ -2314,10 +2295,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04378143fd1296af71dd3aea2e096bef6fbf8aa3c25352d44d62d7f28aa9851b" dependencies = [ "pmutil", - "proc-macro2 1.0.24", + "proc-macro2 1.0.21", "quote 1.0.7", "swc_macros_common", - "syn 1.0.42", + "syn 1.0.41", ] [[package]] @@ -2360,10 +2341,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8798810e2c79b884cf238bcb72b4bd12375121ee91724f1ceeb54b6e38a138e7" dependencies = [ "pmutil", - "proc-macro2 1.0.24", + "proc-macro2 1.0.21", "quote 1.0.7", "swc_macros_common", - "syn 1.0.42", + "syn 1.0.41", ] [[package]] @@ -2407,10 +2388,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38c0b511705a737ef07d347f0fe5af22ef11ead65f6be58010d897426a60a70d" dependencies = [ "pmutil", - "proc-macro2 1.0.24", + "proc-macro2 1.0.21", "quote 1.0.7", "swc_macros_common", - "syn 1.0.42", + "syn 1.0.41", ] [[package]] @@ -2463,9 +2444,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18a9f27d290938370597d363df9a77ba4be8e2bc99f32f69eb5245cdeed3c512" dependencies = [ "pmutil", - "proc-macro2 1.0.24", + "proc-macro2 1.0.21", "quote 1.0.7", - "syn 1.0.42", + "syn 1.0.41", ] [[package]] @@ -2486,10 +2467,10 @@ checksum = "59a75265aea70df7a405e2aafb104c976017fe9a54e7b770017d0583873a3cff" dependencies = [ "Inflector", "pmutil", - "proc-macro2 1.0.24", + "proc-macro2 1.0.21", "quote 1.0.7", "swc_macros_common", - "syn 1.0.42", + "syn 1.0.41", ] [[package]] @@ -2505,11 +2486,11 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.42" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c51d92969d209b54a98397e1b91c8ae82d8c87a7bb87df0b29aa2ad81454228" +checksum = "6690e3e9f692504b941dc6c3b188fd28df054f7fb8469ab40680df52fdcc842b" dependencies = [ - "proc-macro2 1.0.24", + "proc-macro2 1.0.21", "quote 1.0.7", "unicode-xid 0.2.1", ] @@ -2582,22 +2563,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.21" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "318234ffa22e0920fe9a40d7b8369b5f649d490980cf7aadcf1eb91594869b42" +checksum = "7dfdd070ccd8ccb78f4ad66bf1982dc37f620ef696c6b5028fe2ed83dd3d0d08" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.21" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cae2447b6282786c3493999f40a9be2a6ad20cb8bd268b0a0dbf5a065535c0ab" +checksum = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793" dependencies = [ - "proc-macro2 1.0.24", + "proc-macro2 1.0.21", "quote 1.0.7", - "syn 1.0.42", + "syn 1.0.41", ] [[package]] @@ -2656,9 +2637,9 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0c3acc6aa564495a0f2e1d59fab677cd7f81a19994cfc7f3ad0e64301560389" dependencies = [ - "proc-macro2 1.0.24", + "proc-macro2 1.0.21", "quote 1.0.7", - "syn 1.0.42", + "syn 1.0.41", ] [[package]] @@ -2717,21 +2698,20 @@ checksum = "e987b6bf443f4b5b3b6f38704195592cca41c5bb7aedd3c3693c7081f8289860" [[package]] name = "tracing" -version = "0.1.21" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0987850db3733619253fe60e17cb59b82d37c7e6c0236bb81e4d6b87c879f27" +checksum = "6d79ca061b032d6ce30c660fded31189ca0b9922bf483cd70759f13a2d86786c" dependencies = [ "cfg-if", "log", - "pin-project-lite", "tracing-core", ] [[package]] name = "tracing-core" -version = "0.1.17" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f50de3927f93d202783f4513cda820ab47ef17f624b03c096e86ef00c67e6b5f" +checksum = "5bcf46c1f1f06aeea2d6b81f3c863d0930a596c86ad1920d4e5bad6dd1d7119a" dependencies = [ "lazy_static", ] @@ -2976,9 +2956,9 @@ dependencies = [ "bumpalo", "lazy_static", "log", - "proc-macro2 1.0.24", + "proc-macro2 1.0.21", "quote 1.0.7", - "syn 1.0.42", + "syn 1.0.41", "wasm-bindgen-shared", ] @@ -3010,9 +2990,9 @@ version = "0.2.68" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f249f06ef7ee334cc3b8ff031bfc11ec99d00f34d86da7498396dc1e3b1498fe" dependencies = [ - "proc-macro2 1.0.24", + "proc-macro2 1.0.21", "quote 1.0.7", - "syn 1.0.42", + "syn 1.0.41", "wasm-bindgen-backend", "wasm-bindgen-shared", ] From 4d0f419424ea5c3304bd1f2c9b907a353d81ee91 Mon Sep 17 00:00:00 2001 From: iykekings Date: Fri, 9 Oct 2020 11:33:47 +0100 Subject: [PATCH 23/44] update fork --- std/wasi/testdata | 2 +- third_party | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/std/wasi/testdata b/std/wasi/testdata index 7f8aa6ba628a2b..f5c23108d0f191 160000 --- a/std/wasi/testdata +++ b/std/wasi/testdata @@ -1 +1 @@ -Subproject commit 7f8aa6ba628a2bea3612e50638b8c9c9c4bb71a8 +Subproject commit f5c23108d0f191e1f9ffc0fbc21ff7b123d5c90d diff --git a/third_party b/third_party index e80050929aec91..9ad53352a9bc7c 160000 --- a/third_party +++ b/third_party @@ -1 +1 @@ -Subproject commit e80050929aec91d594d68fc01f3919de70a1dc3d +Subproject commit 9ad53352a9bc7cd179d9e06663a097352514d389 From 8ec01093d1a4fc2333a31d4d4678e1279d8dcaaa Mon Sep 17 00:00:00 2001 From: iykekings Date: Fri, 9 Oct 2020 12:02:50 +0100 Subject: [PATCH 24/44] harmonize changes --- cli/flags.rs | 1 - cli/main.rs | 18 +++++++----------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/cli/flags.rs b/cli/flags.rs index a047fc96776b90..1782f32ed39443 100644 --- a/cli/flags.rs +++ b/cli/flags.rs @@ -2907,7 +2907,6 @@ mod tests { quiet: false, filter: None, include: Some(svec!["dir1"]), - coverage: false }, ..Flags::default() } diff --git a/cli/main.rs b/cli/main.rs index ef9a7adc3786ea..0d13502047cfe0 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -118,12 +118,7 @@ impl DocFileLoader for SourceFileFetcher { e.to_string(), )) })?; - source_file.source_code.to_string().map_err(|e| { - doc::DocError::Io(std::io::Error::new( - std::io::ErrorKind::Other, - e.to_string(), - )) - }) + Ok(source_file.source_code) } .boxed_local() } @@ -578,7 +573,8 @@ async fn test_command( filter, ) } else { - let jsdocs = doctest_runner::parse_jsdocs(&test_modules, flags).await?; + let jsdocs = + doctest_runner::parse_jsdocs(&test_modules, flags.clone()).await?; doctest_runner::prepare_doctests(jsdocs, fail_fast, quiet, filter)? }; @@ -750,10 +746,10 @@ pub fn main() { include, allow_none, filter, - } => test_command( - docs, flags, include, fail_fast, quiet, allow_none, filter, - ) - .boxed_local(), + } => { + test_command(docs, flags, include, fail_fast, quiet, allow_none, filter) + .boxed_local() + } DenoSubcommand::Completions { buf } => { if let Err(e) = write_to_stdout_ignore_sigpipe(&buf) { eprintln!("{}", e); From 4f6ab341bbf6023a9228b21d8f804bac2e5930f1 Mon Sep 17 00:00:00 2001 From: iykekings Date: Fri, 9 Oct 2020 12:14:39 +0100 Subject: [PATCH 25/44] don't die on invalid jsdoc --- cli/doctest_runner.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cli/doctest_runner.rs b/cli/doctest_runner.rs index 23d15ee2c489eb..9025fa9b6d7b66 100644 --- a/cli/doctest_runner.rs +++ b/cli/doctest_runner.rs @@ -85,10 +85,10 @@ impl DocTestVisitor { .with_leading(span.lo, |comments| comments.to_vec()); let examples = comments .iter() - .map(|comment| { + .filter_map(|comment| { jsdoc::parse(Input::from(comment)) - .expect("Unable to parse jsdoc") - .1 + .map(|parsed| parsed.1) + .ok() }) .flat_map(|js_doc| { js_doc From ea90be5c17591c4133092c59a9aa8bb478859c7e Mon Sep 17 00:00:00 2001 From: iykekings Date: Fri, 9 Oct 2020 12:52:57 +0100 Subject: [PATCH 26/44] refactor --- cli/doctest_runner.rs | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/cli/doctest_runner.rs b/cli/doctest_runner.rs index 9025fa9b6d7b66..a803d14f705dbc 100644 --- a/cli/doctest_runner.rs +++ b/cli/doctest_runner.rs @@ -20,7 +20,7 @@ use std::rc::Rc; use swc_common::{comments::SingleThreadedComments, SourceMap, Span}; use swc_ecmascript::visit::Visit; use swc_ecmascript::{ - ast::{Class, Decl, ExportDecl, Expr, Function, Module, VarDecl}, + ast::{Class, Decl, ExportDecl, Expr, Function, VarDecl}, visit::Node, }; @@ -45,23 +45,23 @@ struct DocTestVisitor { struct DocTester { doctest_visitor: DocTestVisitor, - module: Module, + parsed_module: ast::ParsedModule, } impl DocTester { - fn new( - module: Module, - comments: SingleThreadedComments, - source_map: Rc, - ) -> Self { + fn new(parsed_module: ast::ParsedModule) -> Self { Self { - doctest_visitor: DocTestVisitor::new(comments, source_map), - module, + doctest_visitor: DocTestVisitor::new( + parsed_module.comments.clone(), + Rc::clone(&parsed_module.source_map), + ), + parsed_module, } } pub fn get_comments(&mut self) -> Vec<(Location, String)> { let visitor = self.doctest_visitor.borrow_mut(); - visitor.visit_module(&self.module, &self.module); + visitor + .visit_module(&self.parsed_module.module, &self.parsed_module.module); visitor.examples.clone().into_inner() } } @@ -171,11 +171,7 @@ pub async fn parse_jsdocs( let media_type = MediaType::from(&path); let specifier = ModuleSpecifier::resolve_url(&url.to_string())?; let parsed_module = ast::parse(&specifier, &source_code, &media_type)?; - let mut doc_tester = DocTester::new( - parsed_module.module, - parsed_module.comments, - Rc::clone(&parsed_module.source_map), - ); + let mut doc_tester = DocTester::new(parsed_module); results.extend(doc_tester.get_comments()); } Ok(results) From bf4f3189acd0f5f08c6724a3be47e88e08a4d229 Mon Sep 17 00:00:00 2001 From: iykekings Date: Fri, 9 Oct 2020 13:41:30 +0100 Subject: [PATCH 27/44] use example span for line number --- cli/doctest_runner.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/doctest_runner.rs b/cli/doctest_runner.rs index a803d14f705dbc..fba9fb5c173e18 100644 --- a/cli/doctest_runner.rs +++ b/cli/doctest_runner.rs @@ -96,7 +96,7 @@ impl DocTestVisitor { .into_iter() .filter_map(|tag_item| match tag_item.tag { Tag::Example(ex_tag) => Some(( - self.get_span_location(ex_tag.text.span), + self.get_span_location(ex_tag.span), ex_tag.text.value.to_string(), )), _ => None, From c33e4260f8e9f15c00309f1243178c25d2111cf4 Mon Sep 17 00:00:00 2001 From: iykekings Date: Fri, 9 Oct 2020 13:52:34 +0100 Subject: [PATCH 28/44] remove cli/js --- cli/js/testing.ts | 372 ---------------------------------------------- 1 file changed, 372 deletions(-) delete mode 100644 cli/js/testing.ts diff --git a/cli/js/testing.ts b/cli/js/testing.ts deleted file mode 100644 index e9895c93fb0066..00000000000000 --- a/cli/js/testing.ts +++ /dev/null @@ -1,372 +0,0 @@ -// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { gray, green, italic, red, yellow } from "./colors.ts"; -import { exit } from "./ops/os.ts"; -import { Console, stringifyArgs } from "./web/console.ts"; -import { stdout } from "./files.ts"; -import { exposeForTest } from "./internals.ts"; -import { TextEncoder } from "./web/text_encoding.ts"; -import { metrics } from "./ops/runtime.ts"; -import { resources } from "./ops/resources.ts"; -import { assert } from "./util.ts"; - -const RED_FAILED = red("FAILED"); -const GREEN_OK = green("ok"); -const YELLOW_IGNORED = yellow("ignored"); -const disabledConsole = new Console((): void => {}); - -function delay(n: number): Promise { - return new Promise((resolve: () => void, _) => { - setTimeout(resolve, n); - }); -} - -function formatDuration(time = 0): string { - const timeStr = `(${time}ms)`; - return gray(italic(timeStr)); -} - -// Wrap test function in additional assertion that makes sure -// the test case does not leak async "ops" - ie. number of async -// completed ops after the test is the same as number of dispatched -// ops. Note that "unref" ops are ignored since in nature that are -// optional. -function assertOps(fn: () => void | Promise): () => void | Promise { - return async function asyncOpSanitizer(): Promise { - const pre = metrics(); - await fn(); - // Defer until next event loop turn - that way timeouts and intervals - // cleared can actually be removed from resource table, otherwise - // false positives may occur (https://github.com/denoland/deno/issues/4591) - await delay(0); - const post = metrics(); - // We're checking diff because one might spawn HTTP server in the background - // that will be a pending async op before test starts. - const dispatchedDiff = post.opsDispatchedAsync - pre.opsDispatchedAsync; - const completedDiff = post.opsCompletedAsync - pre.opsCompletedAsync; - assert( - dispatchedDiff === completedDiff, - `Test case is leaking async ops. -Before: - - dispatched: ${pre.opsDispatchedAsync} - - completed: ${pre.opsCompletedAsync} -After: - - dispatched: ${post.opsDispatchedAsync} - - completed: ${post.opsCompletedAsync} - -Make sure to await all promises returned from Deno APIs before -finishing test case.` - ); - }; -} - -// Wrap test function in additional assertion that makes sure -// the test case does not "leak" resources - ie. resource table after -// the test has exactly the same contents as before the test. -function assertResources( - fn: () => void | Promise -): () => void | Promise { - return async function resourceSanitizer(): Promise { - const pre = resources(); - await fn(); - const post = resources(); - - const preStr = JSON.stringify(pre, null, 2); - const postStr = JSON.stringify(post, null, 2); - const msg = `Test case is leaking resources. -Before: ${preStr} -After: ${postStr} - -Make sure to close all open resource handles returned from Deno APIs before -finishing test case.`; - assert(preStr === postStr, msg); - }; -} - -export interface TestDefinition { - fn: () => void | Promise; - name: string; - ignore?: boolean; - sanitizeOps?: boolean; - sanitizeResources?: boolean; -} - -const TEST_REGISTRY: TestDefinition[] = []; - -export function test(t: TestDefinition): void; -export function test(name: string, fn: () => void | Promise): void; -// Main test function provided by Deno, as you can see it merely -// creates a new object with "name" and "fn" fields. -export function test( - t: string | TestDefinition, - fn?: () => void | Promise -): void { - let testDef: TestDefinition; - const defaults = { - ignore: false, - sanitizeOps: true, - sanitizeResources: true, - }; - - if (typeof t === "string") { - if (!fn || typeof fn != "function") { - throw new TypeError("Missing test function"); - } - if (!t) { - throw new TypeError("The test name can't be empty"); - } - testDef = { fn: fn as () => void | Promise, name: t, ...defaults }; - } else { - if (!t.fn) { - throw new TypeError("Missing test function"); - } - if (!t.name) { - throw new TypeError("The test name can't be empty"); - } - testDef = { ...defaults, ...t }; - } - - if (testDef.sanitizeOps) { - testDef.fn = assertOps(testDef.fn); - } - - if (testDef.sanitizeResources) { - testDef.fn = assertResources(testDef.fn); - } - - TEST_REGISTRY.push(testDef); -} - -interface TestMessage { - start?: { - tests: TestDefinition[]; - }; - // Must be extensible, avoiding `testStart?: TestDefinition;`. - testStart?: { - [P in keyof TestDefinition]: TestDefinition[P]; - }; - testEnd?: { - name: string; - status: "passed" | "failed" | "ignored"; - duration: number; - error?: Error; - }; - end?: { - filtered: number; - ignored: number; - measured: number; - passed: number; - failed: number; - duration: number; - results: Array; - }; -} - -const encoder = new TextEncoder(); - -function log(msg: string, noNewLine = false): void { - if (!noNewLine) { - msg += "\n"; - } - - // Using `stdout` here because it doesn't force new lines - // compared to `console.log`; `core.print` on the other hand - // is line-buffered and doesn't output message without newline - stdout.writeSync(encoder.encode(msg)); -} - -function reportToConsole(message: TestMessage, isDoctest: boolean): void { - if (message.start != null) { - log(`running ${message.start.tests.length} tests`); - } else if (message.testStart != null) { - const { name } = message.testStart; - - log(`test ${name} ... `, true); - return; - } else if (message.testEnd != null) { - switch (message.testEnd.status) { - case "passed": - log(`${GREEN_OK} ${formatDuration(message.testEnd.duration)}`); - break; - case "failed": - log(`${RED_FAILED} ${formatDuration(message.testEnd.duration)}`); - break; - case "ignored": - log(`${YELLOW_IGNORED} ${formatDuration(message.testEnd.duration)}`); - break; - } - } else if (message.end != null) { - const failures = message.end.results.filter((m) => m.error != null); - if (failures.length > 0) { - log(`\nfailures:\n`); - - for (const { name, error } of failures) { - log(name); - log(stringifyArgs([error!])); - log(""); - } - - log(`failures:\n`); - - for (const { name } of failures) { - log(`\t${name}`); - } - } - log( - `\n${isDoctest ? "doctest" : "test"} result: ${ - message.end.failed ? RED_FAILED : GREEN_OK - }. ` + - `${message.end.passed} passed; ${message.end.failed} failed; ` + - `${message.end.ignored} ignored; ${message.end.measured} measured; ` + - `${message.end.filtered} filtered out ` + - `${formatDuration(message.end.duration)}\n` - ); - } -} - -exposeForTest("reportToConsole", reportToConsole); - -// TODO: already implements AsyncGenerator, but add as "implements to class" -// TODO: implements PromiseLike -class TestApi { - readonly testsToRun: TestDefinition[]; - readonly stats = { - filtered: 0, - ignored: 0, - measured: 0, - passed: 0, - failed: 0, - }; - - constructor( - public tests: TestDefinition[], - public filterFn: (def: TestDefinition) => boolean, - public failFast: boolean - ) { - this.testsToRun = tests.filter(filterFn); - this.stats.filtered = tests.length - this.testsToRun.length; - } - - async *[Symbol.asyncIterator](): AsyncIterator { - yield { start: { tests: this.testsToRun } }; - - const results: Array = []; - const suiteStart = +new Date(); - for (const test of this.testsToRun) { - const endMessage: Partial = { - name: test.name, - duration: 0, - }; - yield { testStart: { ...test } }; - if (test.ignore) { - endMessage.status = "ignored"; - this.stats.ignored++; - } else { - const start = +new Date(); - try { - await test.fn(); - endMessage.status = "passed"; - this.stats.passed++; - } catch (err) { - endMessage.status = "failed"; - endMessage.error = err; - this.stats.failed++; - } - endMessage.duration = +new Date() - start; - } - results.push(endMessage as TestMessage["testEnd"] & {}); - yield { testEnd: endMessage as TestMessage["testEnd"] }; - if (this.failFast && endMessage.error != null) { - break; - } - } - - const duration = +new Date() - suiteStart; - - yield { end: { ...this.stats, duration, results } }; - } -} - -function createFilterFn( - filter: undefined | string | RegExp, - skip: undefined | string | RegExp -): (def: TestDefinition) => boolean { - return (def: TestDefinition): boolean => { - let passes = true; - - if (filter) { - if (filter instanceof RegExp) { - passes = passes && filter.test(def.name); - } else { - passes = passes && def.name.includes(filter); - } - } - - if (skip) { - if (skip instanceof RegExp) { - passes = passes && !skip.test(def.name); - } else { - passes = passes && !def.name.includes(skip); - } - } - - return passes; - }; -} - -interface RunTestsOptions { - exitOnFail?: boolean; - failFast?: boolean; - filter?: string | RegExp; - skip?: string | RegExp; - disableLog?: boolean; - isDoctest?: boolean; - reportToConsole?: boolean; - onMessage?: (message: TestMessage) => void | Promise; -} - -async function runTests({ - exitOnFail = true, - failFast = false, - filter = undefined, - skip = undefined, - disableLog = false, - isDoctest = false, - reportToConsole: reportToConsole_ = true, - onMessage = undefined, -}: RunTestsOptions = {}): Promise { - const filterFn = createFilterFn(filter, skip); - const testApi = new TestApi(TEST_REGISTRY, filterFn, failFast); - - const originalConsole = globalThis.console; - - if (disableLog) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (globalThis as any).console = disabledConsole; - } - - let endMsg: TestMessage["end"]; - - for await (const message of testApi) { - if (onMessage != null) { - await onMessage(message); - } - if (reportToConsole_) { - reportToConsole(message, isDoctest); - } - if (message.end != null) { - endMsg = message.end; - } - } - - if (disableLog) { - globalThis.console = originalConsole; - } - - if (endMsg!.failed > 0 && exitOnFail) { - exit(1); - } - - return endMsg!; -} - -exposeForTest("runTests", runTests); From 3414beca56f3e8c0979fe2ea2727d426599db9b8 Mon Sep 17 00:00:00 2001 From: iykekings Date: Fri, 9 Oct 2020 14:06:20 +0100 Subject: [PATCH 29/44] require unstable flag --- Cargo.lock | 16 ++-------------- cli/Cargo.toml | 2 +- cli/flags.rs | 3 ++- 3 files changed, 5 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5fb90e3bc92fdf..a421d0e8876407 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -415,7 +415,7 @@ dependencies = [ "fwdansi", "http", "indexmap", - "jsdoc 0.5.1", + "jsdoc", "jsonc-parser", "lazy_static", "libc", @@ -1116,18 +1116,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "jsdoc" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eb0392aa1730824b8359786500d1e1812a8fe4f220bb97a799a4390cf302d9d" -dependencies = [ - "nom", - "serde", - "swc_atoms", - "swc_common", -] - [[package]] name = "jsdoc" version = "0.6.0" @@ -2360,7 +2348,7 @@ dependencies = [ "fxhash", "indexmap", "is-macro", - "jsdoc 0.6.0", + "jsdoc", "log", "once_cell", "ordered-float", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index ddd62223e31983..6c816d8335714a 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -47,7 +47,7 @@ dprint-plugin-typescript = "0.32.4" filetime = "0.2.12" http = "0.2.1" indexmap = "1.6.0" -jsdoc = "0.5.1" +jsdoc = "0.6.0" jsonc-parser = "0.14.0" lazy_static = "1.4.0" libc = "0.2.77" diff --git a/cli/flags.rs b/cli/flags.rs index 1782f32ed39443..40dc399d42e7fe 100644 --- a/cli/flags.rs +++ b/cli/flags.rs @@ -1168,7 +1168,8 @@ fn test_subcommand<'a, 'b>() -> App<'a, 'b> { Arg::with_name("docs") .long("docs") .help("Run code examples from JSDocs as tests") - .takes_value(false), + .takes_value(false) + .requires("unstable"), ) .arg( Arg::with_name("allow_none") From 158128ee7741f15d318af6f00089e5a0d47645f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Sat, 10 Oct 2020 11:54:53 +0200 Subject: [PATCH 30/44] update third_party --- std/wasi/testdata | 2 +- third_party | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/std/wasi/testdata b/std/wasi/testdata index f5c23108d0f191..7f8aa6ba628a2b 160000 --- a/std/wasi/testdata +++ b/std/wasi/testdata @@ -1 +1 @@ -Subproject commit f5c23108d0f191e1f9ffc0fbc21ff7b123d5c90d +Subproject commit 7f8aa6ba628a2bea3612e50638b8c9c9c4bb71a8 diff --git a/third_party b/third_party index 9ad53352a9bc7c..e80050929aec91 160000 --- a/third_party +++ b/third_party @@ -1 +1 @@ -Subproject commit 9ad53352a9bc7cd179d9e06663a097352514d389 +Subproject commit e80050929aec91d594d68fc01f3919de70a1dc3d From ad5ba4863d5ae6d00302b3dcb137cbae3dba5ed5 Mon Sep 17 00:00:00 2001 From: iykekings Date: Sat, 10 Oct 2020 11:37:15 +0100 Subject: [PATCH 31/44] updates --- std/wasi/testdata | 2 +- third_party | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/std/wasi/testdata b/std/wasi/testdata index 7f8aa6ba628a2b..f5c23108d0f191 160000 --- a/std/wasi/testdata +++ b/std/wasi/testdata @@ -1 +1 @@ -Subproject commit 7f8aa6ba628a2bea3612e50638b8c9c9c4bb71a8 +Subproject commit f5c23108d0f191e1f9ffc0fbc21ff7b123d5c90d diff --git a/third_party b/third_party index e80050929aec91..9ad53352a9bc7c 160000 --- a/third_party +++ b/third_party @@ -1 +1 @@ -Subproject commit e80050929aec91d594d68fc01f3919de70a1dc3d +Subproject commit 9ad53352a9bc7cd179d9e06663a097352514d389 From fe03e920f01dac8fcdbbbe3733337d71e1905388 Mon Sep 17 00:00:00 2001 From: Yoshiya Hinosawa Date: Fri, 9 Oct 2020 04:39:02 +0900 Subject: [PATCH 32/44] docs(std/bytes): add missing docs to README (#7885) --- std/bytes/README.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/std/bytes/README.md b/std/bytes/README.md index 54810762d098cd..537c33473d3251 100644 --- a/std/bytes/README.md +++ b/std/bytes/README.md @@ -58,6 +58,17 @@ hasPrefix(new Uint8Array([0, 1, 2]), new Uint8Array([0, 1])); // returns true hasPrefix(new Uint8Array([0, 1, 2]), new Uint8Array([1, 2])); // returns false ``` +## hasSuffix + +Check whether binary array ends with suffix. + +```typescript +import { hasSuffix } from "https://deno.land/std@$STD_VERSION/bytes/mod.ts"; + +hasSuffix(new Uint8Array([0, 1, 2]), new Uint8Array([0, 1])); // returns false +hasSuffix(new Uint8Array([0, 1, 2]), new Uint8Array([1, 2])); // returns true +``` + ## repeat Repeat bytes of given binary array and return new one. @@ -78,6 +89,24 @@ import { concat } from "https://deno.land/std@$STD_VERSION/bytes/mod.ts"; concat(new Uint8Array([1, 2]), new Uint8Array([3, 4])); // returns Uint8Array(4) [ 1, 2, 3, 4 ] ``` +## contains + +Check source array contains pattern array. + +```typescript +import { contains } from "https://deno.land/std@$STD_VERSION/bytes/mod.ts"; + +contains( + new Uint8Array([1, 2, 0, 1, 2, 0, 2, 1, 3]), + new Uint8Array([0, 1, 2]), +); // => returns true + +contains( + new Uint8Array([1, 2, 0, 1, 2, 0, 2, 1, 3]), + new Uint8Array([2, 2]), +); // => returns false +``` + ## copyBytes Copy bytes from one binary array to another. From e2a65c1dc98cbd448aefddd41c1aa52221abfacf Mon Sep 17 00:00:00 2001 From: crowlKats <13135287+crowlKats@users.noreply.github.com> Date: Thu, 8 Oct 2020 21:40:49 +0200 Subject: [PATCH 33/44] Fix typos (#7882) --- cli/permissions.rs | 2 +- core/error.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/permissions.rs b/cli/permissions.rs index d2f58de0a9249d..c2e11080e392d7 100644 --- a/cli/permissions.rs +++ b/cli/permissions.rs @@ -593,7 +593,7 @@ impl Permissions { pub fn check_hrtime(&self) -> Result<(), AnyError> { self .hrtime - .check("access to high precision time", "--allow-run") + .check("access to high precision time", "--allow-hrtime") } #[allow(clippy::too_many_arguments)] diff --git a/core/error.rs b/core/error.rs index 30aa8877353e73..8a80e30246543a 100644 --- a/core/error.rs +++ b/core/error.rs @@ -51,7 +51,7 @@ pub fn bad_resource_id() -> AnyError { } pub fn not_supported() -> AnyError { - custom_error("NotSupported", "The operation is supported") + custom_error("NotSupported", "The operation is not supported") } pub fn resource_unavailable() -> AnyError { From f61678dd84f25b4a4f54a00cc55b31dd66985c64 Mon Sep 17 00:00:00 2001 From: Nayeem Rahman Date: Fri, 9 Oct 2020 06:12:44 +0100 Subject: [PATCH 34/44] fix(op_crates/fetch): Stringify and parse Request URLs (#7838) Fixes #7837 --- cli/tests/unit/body_test.ts | 2 +- cli/tests/unit/request_test.ts | 28 ++++++++++++++++++++++------ op_crates/fetch/26_fetch.js | 5 +++-- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/cli/tests/unit/body_test.ts b/cli/tests/unit/body_test.ts index 404ae305dda73e..4839d4094c4d49 100644 --- a/cli/tests/unit/body_test.ts +++ b/cli/tests/unit/body_test.ts @@ -4,7 +4,7 @@ import { assert, assertEquals, unitTest } from "./test_util.ts"; // just a hack to get a body object // eslint-disable-next-line @typescript-eslint/no-explicit-any function buildBody(body: any, headers?: Headers): Body { - const stub = new Request("", { + const stub = new Request("http://foo/", { body: body, headers, }); diff --git a/cli/tests/unit/request_test.ts b/cli/tests/unit/request_test.ts index c8b8377d4fd703..f1d5ef0551117d 100644 --- a/cli/tests/unit/request_test.ts +++ b/cli/tests/unit/request_test.ts @@ -1,8 +1,8 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. -import { assert, assertEquals, unitTest } from "./test_util.ts"; +import { assert, assertEquals, assertThrows, unitTest } from "./test_util.ts"; unitTest(function fromInit(): void { - const req = new Request("https://example.com", { + const req = new Request("http://foo/", { body: "ahoyhoy", method: "POST", headers: { @@ -12,12 +12,12 @@ unitTest(function fromInit(): void { // eslint-disable-next-line @typescript-eslint/no-explicit-any assertEquals("ahoyhoy", (req as any)._bodySource); - assertEquals(req.url, "https://example.com"); + assertEquals(req.url, "http://foo/"); assertEquals(req.headers.get("test-header"), "value"); }); unitTest(function fromRequest(): void { - const r = new Request("https://example.com"); + const r = new Request("http://foo/"); // eslint-disable-next-line @typescript-eslint/no-explicit-any (r as any)._bodySource = "ahoyhoy"; r.headers.set("test-header", "value"); @@ -30,10 +30,26 @@ unitTest(function fromRequest(): void { assertEquals(req.headers.get("test-header"), r.headers.get("test-header")); }); +unitTest(function requestNonString(): void { + const nonString = { + toString() { + return "http://foo/"; + }, + }; + // deno-lint-ignore ban-ts-comment + // @ts-expect-error + assertEquals(new Request(nonString).url, "http://foo/"); +}); + +unitTest(function requestRelativeUrl(): void { + // TODO(nayeemrmn): Base from `--location` when implemented and set. + assertThrows(() => new Request("relative-url"), TypeError, "Invalid URL."); +}); + unitTest(async function cloneRequestBodyStream(): Promise { // hack to get a stream - const stream = new Request("", { body: "a test body" }).body; - const r1 = new Request("https://example.com", { + const stream = new Request("http://foo/", { body: "a test body" }).body; + const r1 = new Request("http://foo/", { body: stream, }); diff --git a/op_crates/fetch/26_fetch.js b/op_crates/fetch/26_fetch.js index 9916a4f82c0481..88744981b52de3 100644 --- a/op_crates/fetch/26_fetch.js +++ b/op_crates/fetch/26_fetch.js @@ -985,8 +985,9 @@ this.headers = new Headers(input.headers); this.credentials = input.credentials; this._stream = input._stream; - } else if (typeof input === "string") { - this.url = input; + } else { + // TODO(nayeemrmn): Base from `--location` when implemented and set. + this.url = new URL(String(input)).href; } if (init && "method" in init) { From 56c18a3ab999185409efae88f2f4e0c5edb3059f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Fri, 9 Oct 2020 13:00:39 +0200 Subject: [PATCH 35/44] build: invalidate GHA cache (#7894) --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2655f364f067be..400b5c590461fb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -114,9 +114,9 @@ jobs: target/*/.* target/*/build target/*/deps - key: ${{ matrix.os }}-${{ matrix.kind }}-${{ hashFiles('Cargo.lock') }} + key: deno-${{ matrix.os }}-${{ matrix.kind }}-${{ hashFiles('Cargo.lock') }} restore-keys: | - ${{ matrix.os }}-${{ matrix.kind }}- + deno-${{ matrix.os }}-${{ matrix.kind }}- - name: lint.py if: matrix.kind == 'lint' From 0e04e098963bab9c33cc8ead9fd3f9f74ddc91c5 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Fri, 9 Oct 2020 14:42:03 +0200 Subject: [PATCH 36/44] ci: fix rusty_v8 binary download unavailable (#7898) A recent change in rustc or cargo made it so that rusty_v8's `build.rs`, which is responsible for downloading `librusty_v8.a`, does not get rebuilt or re-run when its build output directory is restored from the Github Actions cache. However, rusty_v8's custom build script does not save the download to its build output directory; it puts the file in `target/debug|release/gn_out/obj` instead. To get CI going again we opted to add `target/*/gn_out` to the Github Actions cache. A more robust fix would be make rusty_v8 save the download to the cargo-designated output directory. --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 400b5c590461fb..a381bb757974c5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -114,6 +114,7 @@ jobs: target/*/.* target/*/build target/*/deps + target/*/gn_out key: deno-${{ matrix.os }}-${{ matrix.kind }}-${{ hashFiles('Cargo.lock') }} restore-keys: | deno-${{ matrix.os }}-${{ matrix.kind }}- From 0fc4c46760e088edcaed2efc303f13bd29afd044 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Fri, 9 Oct 2020 15:26:15 +0200 Subject: [PATCH 37/44] ci: add workaround for MacOS + Cargo + Github Actions cache bug (#7898) --- .github/workflows/ci.yml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a381bb757974c5..91f551f2aaf0f0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -119,6 +119,35 @@ jobs: restore-keys: | deno-${{ matrix.os }}-${{ matrix.kind }}- + # It seems that the 'target' directory does not always get restored + # from cache correctly on MacOS. In the build log we see the following: + # + # Fresh serde_derive v1.0.115 + # + # But a little while after that Cargo aborts because 'serde_derive' is + # now nowhere to be found. We're not the only ones experiencing this, + # see https://github.com/actions-rs/cargo/issues/111. + # + # error[E0463]: can't find crate for `serde_derive` + # ##[error] --> /Users/runner/.cargo/registry/src/github.com- + # | 1ecc6299db9ec823/serde-1.0.115/src/lib.rs:285:1 + # | + # 285 | extern crate serde_derive; + # | ^^^^^^^^^^^^^^^^^^^^^^^^^^ can't find crate + - name: Work around MacOS + Cargo + Github Actions cache bug + if: runner.os == 'macOS' + run: | + cargo clean --locked --release \ + -p ast_node \ + -p is-macro \ + -p serde_derive \ + -p swc_ecma_codegen \ + -p swc_ecma_codegen_macros \ + -p swc_ecma_parser \ + -p swc_ecma_parser_macros \ + -p swc_visit \ + -p swc_visit_macros + - name: lint.py if: matrix.kind == 'lint' run: python ./tools/lint.py From 1dc00ffcf153e5f16fa7f7715ff09cf28bd5aa21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Fri, 9 Oct 2020 19:05:50 +0200 Subject: [PATCH 38/44] fix Releases.md (#7883) --- .github/workflows/ci.yml | 2 +- Releases.md | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 91f551f2aaf0f0..55f8a7c37143d4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -160,7 +160,7 @@ jobs: if: | matrix.kind == 'test_release' || matrix.kind == 'bench' - run: cargo build --release --locked --all-targets + run: cargo build --release --locked --all-targets -vv - name: Build debug if: matrix.kind == 'test_debug' diff --git a/Releases.md b/Releases.md index 6eb241a972b4ea..5d77081bb754fe 100644 --- a/Releases.md +++ b/Releases.md @@ -6,13 +6,12 @@ https://github.com/denoland/deno/releases We also have one-line install commands at: https://github.com/denoland/deno_install -### 1.4.4 / 2020.10.03 +### 1.4.5 / 2020.10.08 - feat(unstable): Revert "enable importsNotUsedAsValues by default #7413" (#7800) - fix: Update worker types to better align to lib.dom.d.ts (#7843) -- fix(cli/ops/fs): Don't force Windows paths separate paths with forward slash - (#7833) +- fix(cli/ops/fs): Preserve Windows path separators in Deno.realPath() (#7833) - fix(cli/rt/console): Don't require a prototype to detect a class instance (#7869) - fix(cli/rt/error_stack): Improve message line formatting (#7860) From 713a3bac1cee573ea4b34bdbef7e49f05937612d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Fri, 9 Oct 2020 19:08:10 +0200 Subject: [PATCH 39/44] refactor: Worker is not a Future (#7895) This commit rewrites deno::Worker to not implement Future trait. Instead there are two separate methods: - Worker::poll_event_loop() - does single tick of event loop - Worker::run_event_loop() - runs event loop to completion Additionally some cleanup to Worker's field visibility was done. --- cli/coverage.rs | 4 +- cli/main.rs | 22 ++-- cli/ops/worker_host.rs | 3 +- cli/repl.rs | 11 +- cli/worker.rs | 235 ++++++++++++++++++++--------------------- 5 files changed, 131 insertions(+), 144 deletions(-) diff --git a/cli/coverage.rs b/cli/coverage.rs index 97344b589bccda..85ba3f55929e11 100644 --- a/cli/coverage.rs +++ b/cli/coverage.rs @@ -1,7 +1,6 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. use crate::colors; -use crate::inspector::DenoInspector; use crate::inspector::InspectorSession; use deno_core::error::AnyError; use deno_core::serde_json; @@ -14,8 +13,7 @@ pub struct CoverageCollector { } impl CoverageCollector { - pub fn new(inspector_ptr: *mut DenoInspector) -> Self { - let session = InspectorSession::new(inspector_ptr); + pub fn new(session: Box) -> Self { Self { session } } diff --git a/cli/main.rs b/cli/main.rs index 0d13502047cfe0..ca2b306fb839c8 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -310,7 +310,7 @@ async fn eval_command( debug!("main_module {}", &main_module); worker.execute_module(&main_module).await?; worker.execute("window.dispatchEvent(new Event('load'))")?; - (&mut *worker).await?; + worker.run_event_loop().await?; worker.execute("window.dispatchEvent(new Event('unload'))")?; Ok(()) } @@ -424,7 +424,7 @@ async fn run_repl(flags: Flags) -> Result<(), AnyError> { ModuleSpecifier::resolve_url_or_path("./$deno$repl.ts").unwrap(); let global_state = GlobalState::new(flags)?; let mut worker = MainWorker::new(&global_state, main_module.clone()); - (&mut *worker).await?; + worker.run_event_loop().await?; repl::run(&global_state, worker).await } @@ -455,7 +455,7 @@ async fn run_from_stdin(flags: Flags) -> Result<(), AnyError> { debug!("main_module {}", main_module); worker.execute_module(&main_module).await?; worker.execute("window.dispatchEvent(new Event('load'))")?; - (&mut *worker).await?; + worker.run_event_loop().await?; worker.execute("window.dispatchEvent(new Event('unload'))")?; Ok(()) } @@ -501,7 +501,7 @@ async fn run_with_watch(flags: Flags, script: String) -> Result<(), AnyError> { debug!("main_module {}", main_module); worker.execute_module(&main_module).await?; worker.execute("window.dispatchEvent(new Event('load'))")?; - (&mut *worker).await?; + worker.run_event_loop().await?; worker.execute("window.dispatchEvent(new Event('unload'))")?; Ok(()) } @@ -526,7 +526,7 @@ async fn run_command(flags: Flags, script: String) -> Result<(), AnyError> { debug!("main_module {}", main_module); worker.execute_module(&main_module).await?; worker.execute("window.dispatchEvent(new Event('load'))")?; - (&mut *worker).await?; + worker.run_event_loop().await?; worker.execute("window.dispatchEvent(new Event('unload'))")?; Ok(()) } @@ -596,12 +596,8 @@ async fn test_command( .save_source_file_in_cache(&main_module, source_file); let mut maybe_coverage_collector = if flags.coverage { - let inspector = worker - .inspector - .as_mut() - .expect("Inspector is not created."); - - let mut coverage_collector = CoverageCollector::new(&mut **inspector); + let session = worker.create_inspector_session(); + let mut coverage_collector = CoverageCollector::new(session); coverage_collector.start_collecting().await?; Some(coverage_collector) @@ -612,9 +608,9 @@ async fn test_command( let execute_result = worker.execute_module(&main_module).await; execute_result?; worker.execute("window.dispatchEvent(new Event('load'))")?; - (&mut *worker).await?; + worker.run_event_loop().await?; worker.execute("window.dispatchEvent(new Event('unload'))")?; - (&mut *worker).await?; + worker.run_event_loop().await?; if let Some(coverage_collector) = maybe_coverage_collector.as_mut() { let coverages = coverage_collector.collect().await?; diff --git a/cli/ops/worker_host.rs b/cli/ops/worker_host.rs index 6d74bb9f4d3e98..0b36e2c470b68a 100644 --- a/cli/ops/worker_host.rs +++ b/cli/ops/worker_host.rs @@ -173,7 +173,8 @@ fn run_worker_thread( // TODO(bartlomieju): this thread should return result of event loop // that means that we should store JoinHandle to thread to ensure // that it actually terminates. - rt.block_on(worker).expect("Panic in event loop"); + rt.block_on(worker.run_event_loop()) + .expect("Panic in event loop"); debug!("Worker thread shuts down {}", &name); })?; diff --git a/cli/repl.rs b/cli/repl.rs index fbc37fac599ada..c5107d5af6dc8a 100644 --- a/cli/repl.rs +++ b/cli/repl.rs @@ -47,7 +47,7 @@ async fn post_message_and_poll( return result } - _ = &mut *worker => { + _ = worker.run_event_loop() => { // A zero delay is long enough to yield the thread in order to prevent the loop from // running hot for messages that are taking longer to resolve like for example an // evaluation of top level await. @@ -75,7 +75,7 @@ async fn read_line_and_poll( result = &mut line => { return result.unwrap(); } - _ = &mut *worker, if poll_worker => { + _ = worker.run_event_loop(), if poll_worker => { poll_worker = false; } _ = &mut timeout => { @@ -92,12 +92,7 @@ pub async fn run( // Our inspector is unable to default to the default context id so we have to specify it here. let context_id: u32 = 1; - let inspector = worker - .inspector - .as_mut() - .expect("Inspector is not created."); - - let mut session = InspectorSession::new(&mut **inspector); + let mut session = worker.create_inspector_session(); let history_file = global_state.dir.root.join("deno_history.txt"); diff --git a/cli/worker.rs b/cli/worker.rs index ea9362a6b4dfc6..4af3638256c829 100644 --- a/cli/worker.rs +++ b/cli/worker.rs @@ -3,6 +3,7 @@ use crate::fmt_errors::JsError; use crate::global_state::GlobalState; use crate::inspector::DenoInspector; +use crate::inspector::InspectorSession; use crate::js; use crate::metrics::Metrics; use crate::ops; @@ -11,6 +12,7 @@ use crate::permissions::Permissions; use crate::state::CliModuleLoader; use deno_core::error::AnyError; use deno_core::futures::channel::mpsc; +use deno_core::futures::future::poll_fn; use deno_core::futures::future::FutureExt; use deno_core::futures::stream::StreamExt; use deno_core::futures::task::AtomicWaker; @@ -22,10 +24,8 @@ use deno_core::ModuleSpecifier; use deno_core::RuntimeOptions; use deno_core::Snapshot; use std::env; -use std::future::Future; use std::ops::Deref; use std::ops::DerefMut; -use std::pin::Pin; use std::rc::Rc; use std::sync::atomic::AtomicBool; use std::sync::atomic::Ordering; @@ -95,13 +95,15 @@ fn create_channels() -> (WorkerChannelsInternal, WorkerHandle) { /// - `MainWorker` /// - `WebWorker` pub struct Worker { - pub name: String, - pub js_runtime: JsRuntime, - pub inspector: Option>, - pub waker: AtomicWaker, - pub(crate) internal_channels: WorkerChannelsInternal, external_channels: WorkerHandle, + inspector: Option>, + // Following fields are pub because they are accessed + // when creating a new WebWorker instance. + pub(crate) internal_channels: WorkerChannelsInternal, + pub(crate) js_runtime: JsRuntime, + pub(crate) name: String, should_break_on_first_statement: bool, + waker: AtomicWaker, } impl Worker { @@ -147,13 +149,13 @@ impl Worker { let (internal_channels, external_channels) = create_channels(); Self { - name, - js_runtime, + external_channels, inspector, - waker: AtomicWaker::new(), internal_channels, - external_channels, + js_runtime, + name, should_break_on_first_statement, + waker: AtomicWaker::new(), } } @@ -221,39 +223,35 @@ impl Worker { .wait_for_session_and_break_on_next_statement() } } -} - -impl Drop for Worker { - fn drop(&mut self) { - // The Isolate object must outlive the Inspector object, but this is - // currently not enforced by the type system. - self.inspector.take(); - } -} -impl Future for Worker { - type Output = Result<(), AnyError>; + /// Create new inspector session. This function panics if Worker + /// was not configured to create inspector. + pub fn create_inspector_session(&mut self) -> Box { + let inspector = self.inspector.as_mut().unwrap(); - fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { - let inner = self.get_mut(); + InspectorSession::new(&mut **inspector) + } + pub fn poll_event_loop( + &mut self, + cx: &mut Context, + ) -> Poll> { // We always poll the inspector if it exists. - let _ = inner.inspector.as_mut().map(|i| i.poll_unpin(cx)); - inner.waker.register(cx.waker()); - inner.js_runtime.poll_event_loop(cx) + let _ = self.inspector.as_mut().map(|i| i.poll_unpin(cx)); + self.waker.register(cx.waker()); + self.js_runtime.poll_event_loop(cx) } -} -impl Deref for Worker { - type Target = JsRuntime; - fn deref(&self) -> &Self::Target { - &self.js_runtime + pub async fn run_event_loop(&mut self) -> Result<(), AnyError> { + poll_fn(|cx| self.poll_event_loop(cx)).await } } -impl DerefMut for Worker { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.js_runtime +impl Drop for Worker { + fn drop(&mut self) { + // The Isolate object must outlive the Inspector object, but this is + // currently not enforced by the type system. + self.inspector.take(); } } @@ -278,45 +276,46 @@ impl MainWorker { loader, true, ); + let js_runtime = &mut worker.js_runtime; { // All ops registered in this function depend on these { - let op_state = worker.op_state(); + let op_state = js_runtime.op_state(); let mut op_state = op_state.borrow_mut(); op_state.put::(Default::default()); op_state.put::>(global_state.clone()); op_state.put::(global_state.permissions.clone()); } - ops::runtime::init(&mut worker, main_module); - ops::fetch::init(&mut worker, global_state.flags.ca_file.as_deref()); - ops::timers::init(&mut worker); - ops::worker_host::init(&mut worker); - ops::random::init(&mut worker, global_state.flags.seed); - ops::reg_json_sync(&mut worker, "op_close", deno_core::op_close); - ops::reg_json_sync(&mut worker, "op_resources", deno_core::op_resources); + ops::runtime::init(js_runtime, main_module); + ops::fetch::init(js_runtime, global_state.flags.ca_file.as_deref()); + ops::timers::init(js_runtime); + ops::worker_host::init(js_runtime); + ops::random::init(js_runtime, global_state.flags.seed); + ops::reg_json_sync(js_runtime, "op_close", deno_core::op_close); + ops::reg_json_sync(js_runtime, "op_resources", deno_core::op_resources); ops::reg_json_sync( - &mut worker, + js_runtime, "op_domain_to_ascii", deno_web::op_domain_to_ascii, ); - ops::errors::init(&mut worker); - ops::fs_events::init(&mut worker); - ops::fs::init(&mut worker); - ops::io::init(&mut worker); - ops::net::init(&mut worker); - ops::os::init(&mut worker); - ops::permissions::init(&mut worker); - ops::plugin::init(&mut worker); - ops::process::init(&mut worker); - ops::runtime_compiler::init(&mut worker); - ops::signal::init(&mut worker); - ops::tls::init(&mut worker); - ops::tty::init(&mut worker); - ops::websocket::init(&mut worker); + ops::errors::init(js_runtime); + ops::fs_events::init(js_runtime); + ops::fs::init(js_runtime); + ops::io::init(js_runtime); + ops::net::init(js_runtime); + ops::os::init(js_runtime); + ops::permissions::init(js_runtime); + ops::plugin::init(js_runtime); + ops::process::init(js_runtime); + ops::runtime_compiler::init(js_runtime); + ops::signal::init(js_runtime); + ops::tls::init(js_runtime); + ops::tty::init(js_runtime); + ops::websocket::init(js_runtime); } { - let op_state = worker.op_state(); + let op_state = js_runtime.op_state(); let mut op_state = op_state.borrow_mut(); let t = &mut op_state.resource_table; let (stdin, stdout, stderr) = get_stdio(); @@ -449,49 +448,45 @@ impl WebWorker { { let handle = web_worker.thread_safe_handle(); let sender = web_worker.worker.internal_channels.sender.clone(); - + let js_runtime = &mut web_worker.js_runtime; // All ops registered in this function depend on these { - let op_state = web_worker.op_state(); + let op_state = js_runtime.op_state(); let mut op_state = op_state.borrow_mut(); op_state.put::(Default::default()); op_state.put::>(global_state.clone()); op_state.put::(permissions); } - ops::web_worker::init(&mut web_worker, sender, handle); - ops::runtime::init(&mut web_worker, main_module); - ops::fetch::init(&mut web_worker, global_state.flags.ca_file.as_deref()); - ops::timers::init(&mut web_worker); - ops::worker_host::init(&mut web_worker); - ops::reg_json_sync(&mut web_worker, "op_close", deno_core::op_close); - ops::reg_json_sync( - &mut web_worker, - "op_resources", - deno_core::op_resources, - ); + ops::web_worker::init(js_runtime, sender, handle); + ops::runtime::init(js_runtime, main_module); + ops::fetch::init(js_runtime, global_state.flags.ca_file.as_deref()); + ops::timers::init(js_runtime); + ops::worker_host::init(js_runtime); + ops::reg_json_sync(js_runtime, "op_close", deno_core::op_close); + ops::reg_json_sync(js_runtime, "op_resources", deno_core::op_resources); ops::reg_json_sync( - &mut web_worker, + js_runtime, "op_domain_to_ascii", deno_web::op_domain_to_ascii, ); - ops::errors::init(&mut web_worker); - ops::io::init(&mut web_worker); - ops::websocket::init(&mut web_worker); + ops::errors::init(js_runtime); + ops::io::init(js_runtime); + ops::websocket::init(js_runtime); if has_deno_namespace { - ops::fs_events::init(&mut web_worker); - ops::fs::init(&mut web_worker); - ops::net::init(&mut web_worker); - ops::os::init(&mut web_worker); - ops::permissions::init(&mut web_worker); - ops::plugin::init(&mut web_worker); - ops::process::init(&mut web_worker); - ops::random::init(&mut web_worker, global_state.flags.seed); - ops::runtime_compiler::init(&mut web_worker); - ops::signal::init(&mut web_worker); - ops::tls::init(&mut web_worker); - ops::tty::init(&mut web_worker); + ops::fs_events::init(js_runtime); + ops::fs::init(js_runtime); + ops::net::init(js_runtime); + ops::os::init(js_runtime); + ops::permissions::init(js_runtime); + ops::plugin::init(js_runtime); + ops::process::init(js_runtime); + ops::random::init(js_runtime, global_state.flags.seed); + ops::runtime_compiler::init(js_runtime); + ops::signal::init(js_runtime); + ops::tls::init(js_runtime); + ops::tty::init(js_runtime); } } @@ -504,38 +499,27 @@ impl WebWorker { pub fn thread_safe_handle(&self) -> WebWorkerHandle { self.handle.clone() } -} -impl Deref for WebWorker { - type Target = Worker; - fn deref(&self) -> &Self::Target { - &self.worker + pub async fn run_event_loop(&mut self) -> Result<(), AnyError> { + poll_fn(|cx| self.poll_event_loop(cx)).await } -} - -impl DerefMut for WebWorker { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.worker - } -} -impl Future for WebWorker { - type Output = Result<(), AnyError>; - - fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { - let inner = self.get_mut(); - let worker = &mut inner.worker; + pub fn poll_event_loop( + &mut self, + cx: &mut Context, + ) -> Poll> { + let worker = &mut self.worker; - let terminated = inner.handle.terminated.load(Ordering::Relaxed); + let terminated = self.handle.terminated.load(Ordering::Relaxed); if terminated { return Poll::Ready(Ok(())); } - if !inner.event_loop_idle { - match worker.poll_unpin(cx) { + if !self.event_loop_idle { + match worker.poll_event_loop(cx) { Poll::Ready(r) => { - let terminated = inner.handle.terminated.load(Ordering::Relaxed); + let terminated = self.handle.terminated.load(Ordering::Relaxed); if terminated { return Poll::Ready(Ok(())); } @@ -546,13 +530,13 @@ impl Future for WebWorker { .try_send(WorkerEvent::Error(e)) .expect("Failed to post message to host"); } - inner.event_loop_idle = true; + self.event_loop_idle = true; } Poll::Pending => {} } } - if let Poll::Ready(r) = inner.terminate_rx.poll_next_unpin(cx) { + if let Poll::Ready(r) = self.terminate_rx.poll_next_unpin(cx) { // terminate_rx should never be closed assert!(r.is_some()); return Poll::Ready(Ok(())); @@ -569,7 +553,7 @@ impl Future for WebWorker { if let Err(e) = worker.execute(&script) { // If execution was terminated during message callback then // just ignore it - if inner.handle.terminated.load(Ordering::Relaxed) { + if self.handle.terminated.load(Ordering::Relaxed) { return Poll::Ready(Ok(())); } @@ -581,7 +565,7 @@ impl Future for WebWorker { } // Let event loop be polled again - inner.event_loop_idle = false; + self.event_loop_idle = false; worker.waker.wake(); } None => unreachable!(), @@ -592,6 +576,19 @@ impl Future for WebWorker { } } +impl Deref for WebWorker { + type Target = Worker; + fn deref(&self) -> &Self::Target { + &self.worker + } +} + +impl DerefMut for WebWorker { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.worker + } +} + #[cfg(test)] mod tests { use super::*; @@ -628,7 +625,7 @@ mod tests { if let Err(err) = result { eprintln!("execute_mod err {:?}", err); } - if let Err(e) = (&mut *worker).await { + if let Err(e) = worker.run_event_loop().await { panic!("Future got unexpected error: {:?}", e); } } @@ -646,7 +643,7 @@ mod tests { if let Err(err) = result { eprintln!("execute_mod err {:?}", err); } - if let Err(e) = (&mut *worker).await { + if let Err(e) = worker.run_event_loop().await { panic!("Future got unexpected error: {:?}", e); } } @@ -665,7 +662,7 @@ mod tests { if let Err(err) = result { eprintln!("execute_mod err {:?}", err); } - if let Err(e) = (&mut *worker).await { + if let Err(e) = worker.run_event_loop().await { panic!("Future got unexpected error: {:?}", e); } } @@ -733,7 +730,7 @@ mod tests { worker.execute(source).unwrap(); let handle = worker.thread_safe_handle(); handle_sender.send(handle).unwrap(); - let r = tokio_util::run_basic(worker); + let r = tokio_util::run_basic(worker.run_event_loop()); assert!(r.is_ok()) }); @@ -780,7 +777,7 @@ mod tests { worker.execute("onmessage = () => { close(); }").unwrap(); let handle = worker.thread_safe_handle(); handle_sender.send(handle).unwrap(); - let r = tokio_util::run_basic(worker); + let r = tokio_util::run_basic(worker.run_event_loop()); assert!(r.is_ok()) }); From 6ad8de15e4a0976f7859dfdebd0f0c4f218ecc9e Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Fri, 9 Oct 2020 15:45:40 -0400 Subject: [PATCH 40/44] Implement Serialize for ModuleSpecifier (#7900) Also re-export serde from deno_core, since its now a dependency. --- Cargo.lock | 2 ++ core/Cargo.toml | 5 +++-- core/lib.rs | 1 + core/module_specifier.rs | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a421d0e8876407..3025a6c04d136b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -460,6 +460,7 @@ dependencies = [ "libc", "log", "rusty_v8", + "serde", "serde_json", "smallvec", "tokio", @@ -2820,6 +2821,7 @@ dependencies = [ "idna", "matches", "percent-encoding", + "serde", ] [[package]] diff --git a/core/Cargo.toml b/core/Cargo.toml index 5a13be0d18b7d9..0a66596aa97783 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -20,9 +20,10 @@ lazy_static = "1.4.0" libc = "0.2.77" log = "0.4.11" rusty_v8 = "0.11.0" -serde_json = { version = "1.0.57", features = ["preserve_order"] } +serde_json = { version = "1.0", features = ["preserve_order"] } +serde = { version = "1.0", features = ["derive"] } smallvec = "1.4.2" -url = "2.1.1" +url = { version = "2.1.1", features = ["serde"] } [[example]] name = "http_bench_bin_ops" diff --git a/core/lib.rs b/core/lib.rs index 94cd07992a7252..e03ce2a7d7b6a6 100644 --- a/core/lib.rs +++ b/core/lib.rs @@ -22,6 +22,7 @@ mod zero_copy_buf; // Re-exports pub use futures; pub use rusty_v8 as v8; +pub use serde; pub use serde_json; pub use url; diff --git a/core/module_specifier.rs b/core/module_specifier.rs index 0dfc7a592c3048..82452c0677445b 100644 --- a/core/module_specifier.rs +++ b/core/module_specifier.rs @@ -48,7 +48,7 @@ impl fmt::Display for ModuleResolutionError { } } -#[derive(Debug, Clone, Eq, Hash, PartialEq)] +#[derive(Debug, Clone, Eq, Hash, PartialEq, serde::Serialize)] /// Resolved module specifier pub struct ModuleSpecifier(Url); From 80c285e975f1c6e011eaea1a9f2abca897aa09fb Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Fri, 9 Oct 2020 20:03:56 -0700 Subject: [PATCH 41/44] docs: add Deno internals talk from Paris Deno (#7889) --- docs/contributing/architecture.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/contributing/architecture.md b/docs/contributing/architecture.md index 86afe1f20cbb8c..84d13ded2e41c3 100644 --- a/docs/contributing/architecture.md +++ b/docs/contributing/architecture.md @@ -50,6 +50,9 @@ Metrics is Deno's internal counter for various statistics. ### Conference -Ryan Dahl. (May 27, 2020). -[An interesting case with Deno](https://www.youtube.com/watch?v=1b7FoBwxc7E). -Deno Israel. +- Ryan Dahl. (May 27, 2020). + [An interesting case with Deno](https://www.youtube.com/watch?v=1b7FoBwxc7E). + Deno Israel. +- Bartek IwaƄczuk. (Oct 6, 2020). + [Deno internals - how modern JS/TS runtime is + built](https://www.youtube.com/watch?v=AOvg_GbnsbA&t=35m13s). Paris Deno. From 57496b85cccbba079e64e39300bb16c0cc6a9ae9 Mon Sep 17 00:00:00 2001 From: Lively Date: Sat, 10 Oct 2020 14:20:24 +0900 Subject: [PATCH 42/44] fix(op_crate/web): add padding on URLSearchParam (#7905) Fixes #7888 --- cli/tests/unit/url_search_params_test.ts | 6 ++++++ op_crates/web/11_url.js | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/cli/tests/unit/url_search_params_test.ts b/cli/tests/unit/url_search_params_test.ts index 96b52426510bb0..41b277129447f3 100644 --- a/cli/tests/unit/url_search_params_test.ts +++ b/cli/tests/unit/url_search_params_test.ts @@ -179,6 +179,12 @@ unitTest(function urlSearchParamsMissingPair(): void { assertEquals(searchParams.toString(), "c=4&a=54"); }); +unitTest(function urlSearchParamsForShortEncodedChar(): void { + const init = { linefeed: "\n", tab: "\t" }; + const searchParams = new URLSearchParams(init); + assertEquals(searchParams.toString(), "linefeed=%0A&tab=%09"); +}); + // If pair does not contain exactly two items, then throw a TypeError. // ref https://url.spec.whatwg.org/#interface-urlsearchparams unitTest(function urlSearchParamsShouldThrowTypeError(): void { diff --git a/op_crates/web/11_url.js b/op_crates/web/11_url.js index fb5bece2510f18..fe7ef041acc535 100644 --- a/op_crates/web/11_url.js +++ b/op_crates/web/11_url.js @@ -803,7 +803,7 @@ function encodeChar(c) { return [...encoder.encode(c)] - .map((n) => `%${n.toString(16)}`) + .map((n) => `%${n.toString(16).padStart(2, "0")}`) .join("") .toUpperCase(); } From 19846bcc5931108b382cb34e2c8eada6d7007cc4 Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Sat, 10 Oct 2020 05:41:11 -0400 Subject: [PATCH 43/44] Fix 100% CPU idling problem by reverting #7672 (#7911) * Revert "refactor: Worker is not a Future (#7895)" This reverts commit f4357f0ff9d39411f22504fcc20db6bd5dec6ddb. * Revert "refactor(core): JsRuntime is not a Future (#7855)" This reverts commit d8879feb8c832dbb38649551b1cb0730874f7be6. * Revert "fix(core): module execution with top level await (#7672)" This reverts commit c7c767782538243ded64742dca9b34d6af74d62d. --- cli/coverage.rs | 4 +- cli/main.rs | 22 +- cli/ops/worker_host.rs | 10 +- cli/repl.rs | 11 +- cli/tests/integration_tests.rs | 10 - cli/tests/top_level_await_bug.js | 2 - cli/tests/top_level_await_bug.out | 1 - cli/tests/top_level_await_bug2.js | 15 - cli/tests/top_level_await_bug2.out | 4 - cli/tests/top_level_await_bug_nested.js | 5 - cli/worker.rs | 239 ++++++++-------- core/README.md | 9 +- core/examples/http_bench_bin_ops.rs | 2 +- core/examples/http_bench_json_ops.rs | 2 +- core/modules.rs | 15 +- core/runtime.rs | 352 ++++-------------------- op_crates/web/lib.rs | 11 +- 17 files changed, 222 insertions(+), 492 deletions(-) delete mode 100644 cli/tests/top_level_await_bug.js delete mode 100644 cli/tests/top_level_await_bug.out delete mode 100644 cli/tests/top_level_await_bug2.js delete mode 100644 cli/tests/top_level_await_bug2.out delete mode 100644 cli/tests/top_level_await_bug_nested.js diff --git a/cli/coverage.rs b/cli/coverage.rs index 85ba3f55929e11..97344b589bccda 100644 --- a/cli/coverage.rs +++ b/cli/coverage.rs @@ -1,6 +1,7 @@ // Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. use crate::colors; +use crate::inspector::DenoInspector; use crate::inspector::InspectorSession; use deno_core::error::AnyError; use deno_core::serde_json; @@ -13,7 +14,8 @@ pub struct CoverageCollector { } impl CoverageCollector { - pub fn new(session: Box) -> Self { + pub fn new(inspector_ptr: *mut DenoInspector) -> Self { + let session = InspectorSession::new(inspector_ptr); Self { session } } diff --git a/cli/main.rs b/cli/main.rs index ca2b306fb839c8..0d13502047cfe0 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -310,7 +310,7 @@ async fn eval_command( debug!("main_module {}", &main_module); worker.execute_module(&main_module).await?; worker.execute("window.dispatchEvent(new Event('load'))")?; - worker.run_event_loop().await?; + (&mut *worker).await?; worker.execute("window.dispatchEvent(new Event('unload'))")?; Ok(()) } @@ -424,7 +424,7 @@ async fn run_repl(flags: Flags) -> Result<(), AnyError> { ModuleSpecifier::resolve_url_or_path("./$deno$repl.ts").unwrap(); let global_state = GlobalState::new(flags)?; let mut worker = MainWorker::new(&global_state, main_module.clone()); - worker.run_event_loop().await?; + (&mut *worker).await?; repl::run(&global_state, worker).await } @@ -455,7 +455,7 @@ async fn run_from_stdin(flags: Flags) -> Result<(), AnyError> { debug!("main_module {}", main_module); worker.execute_module(&main_module).await?; worker.execute("window.dispatchEvent(new Event('load'))")?; - worker.run_event_loop().await?; + (&mut *worker).await?; worker.execute("window.dispatchEvent(new Event('unload'))")?; Ok(()) } @@ -501,7 +501,7 @@ async fn run_with_watch(flags: Flags, script: String) -> Result<(), AnyError> { debug!("main_module {}", main_module); worker.execute_module(&main_module).await?; worker.execute("window.dispatchEvent(new Event('load'))")?; - worker.run_event_loop().await?; + (&mut *worker).await?; worker.execute("window.dispatchEvent(new Event('unload'))")?; Ok(()) } @@ -526,7 +526,7 @@ async fn run_command(flags: Flags, script: String) -> Result<(), AnyError> { debug!("main_module {}", main_module); worker.execute_module(&main_module).await?; worker.execute("window.dispatchEvent(new Event('load'))")?; - worker.run_event_loop().await?; + (&mut *worker).await?; worker.execute("window.dispatchEvent(new Event('unload'))")?; Ok(()) } @@ -596,8 +596,12 @@ async fn test_command( .save_source_file_in_cache(&main_module, source_file); let mut maybe_coverage_collector = if flags.coverage { - let session = worker.create_inspector_session(); - let mut coverage_collector = CoverageCollector::new(session); + let inspector = worker + .inspector + .as_mut() + .expect("Inspector is not created."); + + let mut coverage_collector = CoverageCollector::new(&mut **inspector); coverage_collector.start_collecting().await?; Some(coverage_collector) @@ -608,9 +612,9 @@ async fn test_command( let execute_result = worker.execute_module(&main_module).await; execute_result?; worker.execute("window.dispatchEvent(new Event('load'))")?; - worker.run_event_loop().await?; + (&mut *worker).await?; worker.execute("window.dispatchEvent(new Event('unload'))")?; - worker.run_event_loop().await?; + (&mut *worker).await?; if let Some(coverage_collector) = maybe_coverage_collector.as_mut() { let coverages = coverage_collector.collect().await?; diff --git a/cli/ops/worker_host.rs b/cli/ops/worker_host.rs index 0b36e2c470b68a..11529c686bd097 100644 --- a/cli/ops/worker_host.rs +++ b/cli/ops/worker_host.rs @@ -155,13 +155,6 @@ fn run_worker_thread( if let Err(e) = result { let mut sender = worker.internal_channels.sender.clone(); - - // If sender is closed it means that worker has already been closed from - // within using "globalThis.close()" - if sender.is_closed() { - return; - } - sender .try_send(WorkerEvent::TerminalError(e)) .expect("Failed to post message to host"); @@ -173,8 +166,7 @@ fn run_worker_thread( // TODO(bartlomieju): this thread should return result of event loop // that means that we should store JoinHandle to thread to ensure // that it actually terminates. - rt.block_on(worker.run_event_loop()) - .expect("Panic in event loop"); + rt.block_on(worker).expect("Panic in event loop"); debug!("Worker thread shuts down {}", &name); })?; diff --git a/cli/repl.rs b/cli/repl.rs index c5107d5af6dc8a..fbc37fac599ada 100644 --- a/cli/repl.rs +++ b/cli/repl.rs @@ -47,7 +47,7 @@ async fn post_message_and_poll( return result } - _ = worker.run_event_loop() => { + _ = &mut *worker => { // A zero delay is long enough to yield the thread in order to prevent the loop from // running hot for messages that are taking longer to resolve like for example an // evaluation of top level await. @@ -75,7 +75,7 @@ async fn read_line_and_poll( result = &mut line => { return result.unwrap(); } - _ = worker.run_event_loop(), if poll_worker => { + _ = &mut *worker, if poll_worker => { poll_worker = false; } _ = &mut timeout => { @@ -92,7 +92,12 @@ pub async fn run( // Our inspector is unable to default to the default context id so we have to specify it here. let context_id: u32 = 1; - let mut session = worker.create_inspector_session(); + let inspector = worker + .inspector + .as_mut() + .expect("Inspector is not created."); + + let mut session = InspectorSession::new(&mut **inspector); let history_file = global_state.dir.root.join("deno_history.txt"); diff --git a/cli/tests/integration_tests.rs b/cli/tests/integration_tests.rs index 9ad7bac8cdaaae..8e2007b427cda3 100644 --- a/cli/tests/integration_tests.rs +++ b/cli/tests/integration_tests.rs @@ -2662,16 +2662,6 @@ itest!(ignore_require { exit_code: 0, }); -itest!(top_level_await_bug { - args: "run --allow-read top_level_await_bug.js", - output: "top_level_await_bug.out", -}); - -itest!(top_level_await_bug2 { - args: "run --allow-read top_level_await_bug2.js", - output: "top_level_await_bug2.out", -}); - #[test] fn cafile_env_fetch() { use deno_core::url::Url; diff --git a/cli/tests/top_level_await_bug.js b/cli/tests/top_level_await_bug.js deleted file mode 100644 index 3c6860a5b4c273..00000000000000 --- a/cli/tests/top_level_await_bug.js +++ /dev/null @@ -1,2 +0,0 @@ -const mod = await import("./top_level_await_bug_nested.js"); -console.log(mod); diff --git a/cli/tests/top_level_await_bug.out b/cli/tests/top_level_await_bug.out deleted file mode 100644 index f0369645c96b6d..00000000000000 --- a/cli/tests/top_level_await_bug.out +++ /dev/null @@ -1 +0,0 @@ -Module { default: 1, [Symbol(Symbol.toStringTag)]: "Module" } diff --git a/cli/tests/top_level_await_bug2.js b/cli/tests/top_level_await_bug2.js deleted file mode 100644 index c847bbd34b4b55..00000000000000 --- a/cli/tests/top_level_await_bug2.js +++ /dev/null @@ -1,15 +0,0 @@ -const mod = await import("./top_level_await_bug_nested.js"); -console.log(mod); - -const sleep = (n) => new Promise((r) => setTimeout(r, n)); - -await sleep(100); -console.log("slept"); - -window.addEventListener("load", () => { - console.log("load event"); -}); - -setTimeout(() => { - console.log("timeout"); -}, 1000); diff --git a/cli/tests/top_level_await_bug2.out b/cli/tests/top_level_await_bug2.out deleted file mode 100644 index 509ee27c265342..00000000000000 --- a/cli/tests/top_level_await_bug2.out +++ /dev/null @@ -1,4 +0,0 @@ -Module { default: 1, [Symbol(Symbol.toStringTag)]: "Module" } -slept -load event -timeout diff --git a/cli/tests/top_level_await_bug_nested.js b/cli/tests/top_level_await_bug_nested.js deleted file mode 100644 index 894f0de2d54385..00000000000000 --- a/cli/tests/top_level_await_bug_nested.js +++ /dev/null @@ -1,5 +0,0 @@ -const sleep = (n) => new Promise((r) => setTimeout(r, n)); - -await sleep(100); - -export default 1; diff --git a/cli/worker.rs b/cli/worker.rs index 4af3638256c829..20832016a0bc65 100644 --- a/cli/worker.rs +++ b/cli/worker.rs @@ -3,7 +3,6 @@ use crate::fmt_errors::JsError; use crate::global_state::GlobalState; use crate::inspector::DenoInspector; -use crate::inspector::InspectorSession; use crate::js; use crate::metrics::Metrics; use crate::ops; @@ -12,7 +11,6 @@ use crate::permissions::Permissions; use crate::state::CliModuleLoader; use deno_core::error::AnyError; use deno_core::futures::channel::mpsc; -use deno_core::futures::future::poll_fn; use deno_core::futures::future::FutureExt; use deno_core::futures::stream::StreamExt; use deno_core::futures::task::AtomicWaker; @@ -24,8 +22,10 @@ use deno_core::ModuleSpecifier; use deno_core::RuntimeOptions; use deno_core::Snapshot; use std::env; +use std::future::Future; use std::ops::Deref; use std::ops::DerefMut; +use std::pin::Pin; use std::rc::Rc; use std::sync::atomic::AtomicBool; use std::sync::atomic::Ordering; @@ -95,15 +95,13 @@ fn create_channels() -> (WorkerChannelsInternal, WorkerHandle) { /// - `MainWorker` /// - `WebWorker` pub struct Worker { - external_channels: WorkerHandle, - inspector: Option>, - // Following fields are pub because they are accessed - // when creating a new WebWorker instance. + pub name: String, + pub js_runtime: JsRuntime, + pub inspector: Option>, + pub waker: AtomicWaker, pub(crate) internal_channels: WorkerChannelsInternal, - pub(crate) js_runtime: JsRuntime, - pub(crate) name: String, + external_channels: WorkerHandle, should_break_on_first_statement: bool, - waker: AtomicWaker, } impl Worker { @@ -149,13 +147,13 @@ impl Worker { let (internal_channels, external_channels) = create_channels(); Self { - external_channels, + name, + js_runtime, inspector, + waker: AtomicWaker::new(), internal_channels, - js_runtime, - name, + external_channels, should_break_on_first_statement, - waker: AtomicWaker::new(), } } @@ -191,7 +189,7 @@ impl Worker { ) -> Result<(), AnyError> { let id = self.preload_module(module_specifier).await?; self.wait_for_inspector_session(); - self.js_runtime.mod_evaluate(id).await + self.js_runtime.mod_evaluate(id) } /// Loads, instantiates and executes provided source code @@ -206,7 +204,7 @@ impl Worker { .load_module(module_specifier, Some(code)) .await?; self.wait_for_inspector_session(); - self.js_runtime.mod_evaluate(id).await + self.js_runtime.mod_evaluate(id) } /// Returns a way to communicate with the Worker from other threads. @@ -223,35 +221,39 @@ impl Worker { .wait_for_session_and_break_on_next_statement() } } +} - /// Create new inspector session. This function panics if Worker - /// was not configured to create inspector. - pub fn create_inspector_session(&mut self) -> Box { - let inspector = self.inspector.as_mut().unwrap(); - - InspectorSession::new(&mut **inspector) +impl Drop for Worker { + fn drop(&mut self) { + // The Isolate object must outlive the Inspector object, but this is + // currently not enforced by the type system. + self.inspector.take(); } +} + +impl Future for Worker { + type Output = Result<(), AnyError>; + + fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { + let inner = self.get_mut(); - pub fn poll_event_loop( - &mut self, - cx: &mut Context, - ) -> Poll> { // We always poll the inspector if it exists. - let _ = self.inspector.as_mut().map(|i| i.poll_unpin(cx)); - self.waker.register(cx.waker()); - self.js_runtime.poll_event_loop(cx) + let _ = inner.inspector.as_mut().map(|i| i.poll_unpin(cx)); + inner.waker.register(cx.waker()); + inner.js_runtime.poll_unpin(cx) } +} - pub async fn run_event_loop(&mut self) -> Result<(), AnyError> { - poll_fn(|cx| self.poll_event_loop(cx)).await +impl Deref for Worker { + type Target = JsRuntime; + fn deref(&self) -> &Self::Target { + &self.js_runtime } } -impl Drop for Worker { - fn drop(&mut self) { - // The Isolate object must outlive the Inspector object, but this is - // currently not enforced by the type system. - self.inspector.take(); +impl DerefMut for Worker { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.js_runtime } } @@ -276,46 +278,45 @@ impl MainWorker { loader, true, ); - let js_runtime = &mut worker.js_runtime; { // All ops registered in this function depend on these { - let op_state = js_runtime.op_state(); + let op_state = worker.op_state(); let mut op_state = op_state.borrow_mut(); op_state.put::(Default::default()); op_state.put::>(global_state.clone()); op_state.put::(global_state.permissions.clone()); } - ops::runtime::init(js_runtime, main_module); - ops::fetch::init(js_runtime, global_state.flags.ca_file.as_deref()); - ops::timers::init(js_runtime); - ops::worker_host::init(js_runtime); - ops::random::init(js_runtime, global_state.flags.seed); - ops::reg_json_sync(js_runtime, "op_close", deno_core::op_close); - ops::reg_json_sync(js_runtime, "op_resources", deno_core::op_resources); + ops::runtime::init(&mut worker, main_module); + ops::fetch::init(&mut worker, global_state.flags.ca_file.as_deref()); + ops::timers::init(&mut worker); + ops::worker_host::init(&mut worker); + ops::random::init(&mut worker, global_state.flags.seed); + ops::reg_json_sync(&mut worker, "op_close", deno_core::op_close); + ops::reg_json_sync(&mut worker, "op_resources", deno_core::op_resources); ops::reg_json_sync( - js_runtime, + &mut worker, "op_domain_to_ascii", deno_web::op_domain_to_ascii, ); - ops::errors::init(js_runtime); - ops::fs_events::init(js_runtime); - ops::fs::init(js_runtime); - ops::io::init(js_runtime); - ops::net::init(js_runtime); - ops::os::init(js_runtime); - ops::permissions::init(js_runtime); - ops::plugin::init(js_runtime); - ops::process::init(js_runtime); - ops::runtime_compiler::init(js_runtime); - ops::signal::init(js_runtime); - ops::tls::init(js_runtime); - ops::tty::init(js_runtime); - ops::websocket::init(js_runtime); + ops::errors::init(&mut worker); + ops::fs_events::init(&mut worker); + ops::fs::init(&mut worker); + ops::io::init(&mut worker); + ops::net::init(&mut worker); + ops::os::init(&mut worker); + ops::permissions::init(&mut worker); + ops::plugin::init(&mut worker); + ops::process::init(&mut worker); + ops::runtime_compiler::init(&mut worker); + ops::signal::init(&mut worker); + ops::tls::init(&mut worker); + ops::tty::init(&mut worker); + ops::websocket::init(&mut worker); } { - let op_state = js_runtime.op_state(); + let op_state = worker.op_state(); let mut op_state = op_state.borrow_mut(); let t = &mut op_state.resource_table; let (stdin, stdout, stderr) = get_stdio(); @@ -448,45 +449,49 @@ impl WebWorker { { let handle = web_worker.thread_safe_handle(); let sender = web_worker.worker.internal_channels.sender.clone(); - let js_runtime = &mut web_worker.js_runtime; + // All ops registered in this function depend on these { - let op_state = js_runtime.op_state(); + let op_state = web_worker.op_state(); let mut op_state = op_state.borrow_mut(); op_state.put::(Default::default()); op_state.put::>(global_state.clone()); op_state.put::(permissions); } - ops::web_worker::init(js_runtime, sender, handle); - ops::runtime::init(js_runtime, main_module); - ops::fetch::init(js_runtime, global_state.flags.ca_file.as_deref()); - ops::timers::init(js_runtime); - ops::worker_host::init(js_runtime); - ops::reg_json_sync(js_runtime, "op_close", deno_core::op_close); - ops::reg_json_sync(js_runtime, "op_resources", deno_core::op_resources); + ops::web_worker::init(&mut web_worker, sender, handle); + ops::runtime::init(&mut web_worker, main_module); + ops::fetch::init(&mut web_worker, global_state.flags.ca_file.as_deref()); + ops::timers::init(&mut web_worker); + ops::worker_host::init(&mut web_worker); + ops::reg_json_sync(&mut web_worker, "op_close", deno_core::op_close); + ops::reg_json_sync( + &mut web_worker, + "op_resources", + deno_core::op_resources, + ); ops::reg_json_sync( - js_runtime, + &mut web_worker, "op_domain_to_ascii", deno_web::op_domain_to_ascii, ); - ops::errors::init(js_runtime); - ops::io::init(js_runtime); - ops::websocket::init(js_runtime); + ops::errors::init(&mut web_worker); + ops::io::init(&mut web_worker); + ops::websocket::init(&mut web_worker); if has_deno_namespace { - ops::fs_events::init(js_runtime); - ops::fs::init(js_runtime); - ops::net::init(js_runtime); - ops::os::init(js_runtime); - ops::permissions::init(js_runtime); - ops::plugin::init(js_runtime); - ops::process::init(js_runtime); - ops::random::init(js_runtime, global_state.flags.seed); - ops::runtime_compiler::init(js_runtime); - ops::signal::init(js_runtime); - ops::tls::init(js_runtime); - ops::tty::init(js_runtime); + ops::fs_events::init(&mut web_worker); + ops::fs::init(&mut web_worker); + ops::net::init(&mut web_worker); + ops::os::init(&mut web_worker); + ops::permissions::init(&mut web_worker); + ops::plugin::init(&mut web_worker); + ops::process::init(&mut web_worker); + ops::random::init(&mut web_worker, global_state.flags.seed); + ops::runtime_compiler::init(&mut web_worker); + ops::signal::init(&mut web_worker); + ops::tls::init(&mut web_worker); + ops::tty::init(&mut web_worker); } } @@ -499,27 +504,38 @@ impl WebWorker { pub fn thread_safe_handle(&self) -> WebWorkerHandle { self.handle.clone() } +} - pub async fn run_event_loop(&mut self) -> Result<(), AnyError> { - poll_fn(|cx| self.poll_event_loop(cx)).await +impl Deref for WebWorker { + type Target = Worker; + fn deref(&self) -> &Self::Target { + &self.worker } +} - pub fn poll_event_loop( - &mut self, - cx: &mut Context, - ) -> Poll> { - let worker = &mut self.worker; +impl DerefMut for WebWorker { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.worker + } +} - let terminated = self.handle.terminated.load(Ordering::Relaxed); +impl Future for WebWorker { + type Output = Result<(), AnyError>; + + fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { + let inner = self.get_mut(); + let worker = &mut inner.worker; + + let terminated = inner.handle.terminated.load(Ordering::Relaxed); if terminated { return Poll::Ready(Ok(())); } - if !self.event_loop_idle { - match worker.poll_event_loop(cx) { + if !inner.event_loop_idle { + match worker.poll_unpin(cx) { Poll::Ready(r) => { - let terminated = self.handle.terminated.load(Ordering::Relaxed); + let terminated = inner.handle.terminated.load(Ordering::Relaxed); if terminated { return Poll::Ready(Ok(())); } @@ -530,13 +546,13 @@ impl WebWorker { .try_send(WorkerEvent::Error(e)) .expect("Failed to post message to host"); } - self.event_loop_idle = true; + inner.event_loop_idle = true; } Poll::Pending => {} } } - if let Poll::Ready(r) = self.terminate_rx.poll_next_unpin(cx) { + if let Poll::Ready(r) = inner.terminate_rx.poll_next_unpin(cx) { // terminate_rx should never be closed assert!(r.is_some()); return Poll::Ready(Ok(())); @@ -553,7 +569,7 @@ impl WebWorker { if let Err(e) = worker.execute(&script) { // If execution was terminated during message callback then // just ignore it - if self.handle.terminated.load(Ordering::Relaxed) { + if inner.handle.terminated.load(Ordering::Relaxed) { return Poll::Ready(Ok(())); } @@ -565,7 +581,7 @@ impl WebWorker { } // Let event loop be polled again - self.event_loop_idle = false; + inner.event_loop_idle = false; worker.waker.wake(); } None => unreachable!(), @@ -576,19 +592,6 @@ impl WebWorker { } } -impl Deref for WebWorker { - type Target = Worker; - fn deref(&self) -> &Self::Target { - &self.worker - } -} - -impl DerefMut for WebWorker { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.worker - } -} - #[cfg(test)] mod tests { use super::*; @@ -625,7 +628,7 @@ mod tests { if let Err(err) = result { eprintln!("execute_mod err {:?}", err); } - if let Err(e) = worker.run_event_loop().await { + if let Err(e) = (&mut *worker).await { panic!("Future got unexpected error: {:?}", e); } } @@ -643,7 +646,7 @@ mod tests { if let Err(err) = result { eprintln!("execute_mod err {:?}", err); } - if let Err(e) = worker.run_event_loop().await { + if let Err(e) = (&mut *worker).await { panic!("Future got unexpected error: {:?}", e); } } @@ -662,7 +665,7 @@ mod tests { if let Err(err) = result { eprintln!("execute_mod err {:?}", err); } - if let Err(e) = worker.run_event_loop().await { + if let Err(e) = (&mut *worker).await { panic!("Future got unexpected error: {:?}", e); } } @@ -730,7 +733,7 @@ mod tests { worker.execute(source).unwrap(); let handle = worker.thread_safe_handle(); handle_sender.send(handle).unwrap(); - let r = tokio_util::run_basic(worker.run_event_loop()); + let r = tokio_util::run_basic(worker); assert!(r.is_ok()) }); @@ -777,7 +780,7 @@ mod tests { worker.execute("onmessage = () => { close(); }").unwrap(); let handle = worker.thread_safe_handle(); handle_sender.send(handle).unwrap(); - let r = tokio_util::run_basic(worker.run_event_loop()); + let r = tokio_util::run_basic(worker); assert!(r.is_ok()) }); diff --git a/core/README.md b/core/README.md index 2438ecede5db41..f6b429bb83d38a 100644 --- a/core/README.md +++ b/core/README.md @@ -9,12 +9,9 @@ bindings. This Rust crate contains the essential V8 bindings for Deno's command-line interface (Deno CLI). The main abstraction here is the JsRuntime which provides -a way to execute JavaScript. - -The JsRuntime implements an event loop abstraction for the executed code that -keeps track of all pending tasks (async ops, dynamic module loads). It is user's -responsibility to drive that loop by using `JsRuntime::run_event_loop` method - -it must be executed in the context of Rust's future executor (eg. tokio, smol). +a way to execute JavaScript. The JsRuntime is modeled as a +`Future` which completes once all of its ops have +completed. In order to bind Rust functions into JavaScript, use the `Deno.core.dispatch()` function to trigger the "dispatch" callback in Rust. The user is responsible for diff --git a/core/examples/http_bench_bin_ops.rs b/core/examples/http_bench_bin_ops.rs index 7335b86703cb71..8d612f14608717 100644 --- a/core/examples/http_bench_bin_ops.rs +++ b/core/examples/http_bench_bin_ops.rs @@ -260,7 +260,7 @@ fn main() { include_str!("http_bench_bin_ops.js"), ) .unwrap(); - js_runtime.run_event_loop().await + js_runtime.await }; runtime.block_on(future).unwrap(); } diff --git a/core/examples/http_bench_json_ops.rs b/core/examples/http_bench_json_ops.rs index 2cf3d09e339b2d..106b96f365377a 100644 --- a/core/examples/http_bench_json_ops.rs +++ b/core/examples/http_bench_json_ops.rs @@ -193,7 +193,7 @@ fn main() { include_str!("http_bench_json_ops.js"), ) .unwrap(); - js_runtime.run_event_loop().await + js_runtime.await }; runtime.block_on(future).unwrap(); } diff --git a/core/modules.rs b/core/modules.rs index 1038dd84f5985e..130becab885a1f 100644 --- a/core/modules.rs +++ b/core/modules.rs @@ -341,13 +341,6 @@ pub struct ModuleInfo { pub name: String, pub handle: v8::Global, pub import_specifiers: Vec, - // TODO(bartlomieju): there should be "state" - // field that describes if module is already being loaded, - // so concurent dynamic imports don't introduce dead lock - // pub state: LoadState { - // Loading(shared_future), - // Loaded, - // }, } /// A symbolic module entity. @@ -674,7 +667,7 @@ mod tests { let a_id_fut = runtime.load_module(&spec, None); let a_id = futures::executor::block_on(a_id_fut).expect("Failed to load"); - futures::executor::block_on(runtime.mod_evaluate(a_id)).unwrap(); + runtime.mod_evaluate(a_id).unwrap(); let l = loads.lock().unwrap(); assert_eq!( l.to_vec(), @@ -741,7 +734,7 @@ mod tests { let result = runtime.load_module(&spec, None).await; assert!(result.is_ok()); let circular1_id = result.unwrap(); - runtime.mod_evaluate(circular1_id).await.unwrap(); + runtime.mod_evaluate(circular1_id).unwrap(); let l = loads.lock().unwrap(); assert_eq!( @@ -818,7 +811,7 @@ mod tests { println!(">> result {:?}", result); assert!(result.is_ok()); let redirect1_id = result.unwrap(); - runtime.mod_evaluate(redirect1_id).await.unwrap(); + runtime.mod_evaluate(redirect1_id).unwrap(); let l = loads.lock().unwrap(); assert_eq!( l.to_vec(), @@ -968,7 +961,7 @@ mod tests { let main_id = futures::executor::block_on(main_id_fut).expect("Failed to load"); - futures::executor::block_on(runtime.mod_evaluate(main_id)).unwrap(); + runtime.mod_evaluate(main_id).unwrap(); let l = loads.lock().unwrap(); assert_eq!( diff --git a/core/runtime.rs b/core/runtime.rs index f04788d4e53dab..193e33420964be 100644 --- a/core/runtime.rs +++ b/core/runtime.rs @@ -23,8 +23,6 @@ use crate::shared_queue::SharedQueue; use crate::shared_queue::RECOMMENDED_SIZE; use crate::BufVec; use crate::OpState; -use futures::channel::mpsc; -use futures::future::poll_fn; use futures::stream::FuturesUnordered; use futures::stream::StreamExt; use futures::stream::StreamFuture; @@ -84,11 +82,6 @@ pub struct JsRuntime { allocations: IsolateAllocations, } -type DynImportModEvaluate = - (ModuleId, v8::Global, v8::Global); -type ModEvaluate = - (v8::Global, mpsc::Sender>); - /// Internal state for JsRuntime which is stored in one of v8::Isolate's /// embedder slots. pub(crate) struct JsRuntimeState { @@ -97,8 +90,6 @@ pub(crate) struct JsRuntimeState { pub(crate) js_recv_cb: Option>, pub(crate) js_macrotask_cb: Option>, pub(crate) pending_promise_exceptions: HashMap>, - pub(crate) pending_dyn_mod_evaluate: HashMap, - pub(crate) pending_mod_evaluate: HashMap, pub(crate) js_error_create_fn: Box, pub(crate) shared: SharedQueue, pub(crate) pending_ops: FuturesUnordered, @@ -272,8 +263,6 @@ impl JsRuntime { isolate.set_slot(Rc::new(RefCell::new(JsRuntimeState { global_context: Some(global_context), pending_promise_exceptions: HashMap::new(), - pending_dyn_mod_evaluate: HashMap::new(), - pending_mod_evaluate: HashMap::new(), shared_ab: None, js_recv_cb: None, js_macrotask_cb: None, @@ -453,51 +442,50 @@ impl JsRuntime { .remove_near_heap_limit_callback(cb, heap_limit); } } +} - /// Runs event loop to completion - /// - /// This future resolves when: - /// - there are no more pending dynamic imports - /// - there are no more pending ops - pub async fn run_event_loop(&mut self) -> Result<(), AnyError> { - poll_fn(|cx| self.poll_event_loop(cx)).await - } +extern "C" fn near_heap_limit_callback( + data: *mut c_void, + current_heap_limit: usize, + initial_heap_limit: usize, +) -> usize +where + F: FnMut(usize, usize) -> usize, +{ + let callback = unsafe { &mut *(data as *mut F) }; + callback(current_heap_limit, initial_heap_limit) +} - /// Runs a single tick of event loop - pub fn poll_event_loop( - &mut self, - cx: &mut Context, - ) -> Poll> { - self.shared_init(); +impl Future for JsRuntime { + type Output = Result<(), AnyError>; - let state_rc = Self::state(self.v8_isolate()); + fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll { + let runtime = self.get_mut(); + runtime.shared_init(); + + let state_rc = Self::state(runtime.v8_isolate()); { let state = state_rc.borrow(); state.waker.register(cx.waker()); } - // Top level modules - self.evaluate_pending_modules()?; - // Dynamic module loading - ie. modules loaded using "import()" { - let poll_imports = self.prepare_dyn_imports(cx)?; + let poll_imports = runtime.prepare_dyn_imports(cx)?; assert!(poll_imports.is_ready()); - let poll_imports = self.poll_dyn_imports(cx)?; + let poll_imports = runtime.poll_dyn_imports(cx)?; assert!(poll_imports.is_ready()); - self.evaluate_dyn_imports()?; - - self.check_promise_exceptions()?; + runtime.check_promise_exceptions()?; } // Ops { - let overflow_response = self.poll_pending_ops(cx); - self.async_op_response(overflow_response)?; - self.drain_macrotasks()?; - self.check_promise_exceptions()?; + let overflow_response = runtime.poll_pending_ops(cx); + runtime.async_op_response(overflow_response)?; + runtime.drain_macrotasks()?; + runtime.check_promise_exceptions()?; } let state = state_rc.borrow(); @@ -505,8 +493,6 @@ impl JsRuntime { state.pending_ops.is_empty() && state.pending_dyn_imports.is_empty() && state.preparing_dyn_imports.is_empty() - && state.pending_dyn_mod_evaluate.is_empty() - && state.pending_mod_evaluate.is_empty() }; if is_idle { @@ -523,18 +509,6 @@ impl JsRuntime { } } -extern "C" fn near_heap_limit_callback( - data: *mut c_void, - current_heap_limit: usize, - initial_heap_limit: usize, -) -> usize -where - F: FnMut(usize, usize) -> usize, -{ - let callback = unsafe { &mut *(data as *mut F) }; - callback(current_heap_limit, initial_heap_limit) -} - impl JsRuntimeState { // Called by V8 during `Isolate::mod_instantiate`. pub fn module_resolve_cb( @@ -711,93 +685,7 @@ impl JsRuntime { /// `AnyError` can be downcast to a type that exposes additional information /// about the V8 exception. By default this type is `JsError`, however it may /// be a different type if `RuntimeOptions::js_error_create_fn` has been set. - pub fn dyn_mod_evaluate( - &mut self, - load_id: ModuleLoadId, - id: ModuleId, - ) -> Result<(), AnyError> { - self.shared_init(); - - let state_rc = Self::state(self.v8_isolate()); - let context = self.global_context(); - let context1 = self.global_context(); - - let module_handle = state_rc - .borrow() - .modules - .get_info(id) - .expect("ModuleInfo not found") - .handle - .clone(); - - let status = { - let scope = - &mut v8::HandleScope::with_context(self.v8_isolate(), context); - let module = module_handle.get(scope); - module.get_status() - }; - - if status == v8::ModuleStatus::Instantiated { - // IMPORTANT: Top-level-await is enabled, which means that return value - // of module evaluation is a promise. - // - // Because that promise is created internally by V8, when error occurs during - // module evaluation the promise is rejected, and since the promise has no rejection - // handler it will result in call to `bindings::promise_reject_callback` adding - // the promise to pending promise rejection table - meaning JsRuntime will return - // error on next poll(). - // - // This situation is not desirable as we want to manually return error at the - // end of this function to handle it further. It means we need to manually - // remove this promise from pending promise rejection table. - // - // For more details see: - // https://github.com/denoland/deno/issues/4908 - // https://v8.dev/features/top-level-await#module-execution-order - let scope = - &mut v8::HandleScope::with_context(self.v8_isolate(), context1); - let module = v8::Local::new(scope, &module_handle); - let maybe_value = module.evaluate(scope); - - // Update status after evaluating. - let status = module.get_status(); - - if let Some(value) = maybe_value { - assert!( - status == v8::ModuleStatus::Evaluated - || status == v8::ModuleStatus::Errored - ); - let promise = v8::Local::::try_from(value) - .expect("Expected to get promise as module evaluation result"); - let promise_id = promise.get_identity_hash(); - let mut state = state_rc.borrow_mut(); - state.pending_promise_exceptions.remove(&promise_id); - let promise_global = v8::Global::new(scope, promise); - let module_global = v8::Global::new(scope, module); - state - .pending_dyn_mod_evaluate - .insert(load_id, (id, promise_global, module_global)); - } else { - assert!(status == v8::ModuleStatus::Errored); - } - } - - if status == v8::ModuleStatus::Evaluated { - self.dyn_import_done(load_id, id)?; - } - - Ok(()) - } - - /// Evaluates an already instantiated ES module. - /// - /// `AnyError` can be downcast to a type that exposes additional information - /// about the V8 exception. By default this type is `JsError`, however it may - /// be a different type if `RuntimeOptions::js_error_create_fn` has been set. - fn mod_evaluate_inner( - &mut self, - id: ModuleId, - ) -> Result>, AnyError> { + pub fn mod_evaluate(&mut self, id: ModuleId) -> Result<(), AnyError> { self.shared_init(); let state_rc = Self::state(self.v8_isolate()); @@ -813,8 +701,6 @@ impl JsRuntime { .expect("ModuleInfo not found"); let mut status = module.get_status(); - let (sender, receiver) = mpsc::channel(1); - if status == v8::ModuleStatus::Instantiated { // IMPORTANT: Top-level-await is enabled, which means that return value // of module evaluation is a promise. @@ -847,30 +733,20 @@ impl JsRuntime { let promise_id = promise.get_identity_hash(); let mut state = state_rc.borrow_mut(); state.pending_promise_exceptions.remove(&promise_id); - let promise_global = v8::Global::new(scope, promise); - state - .pending_mod_evaluate - .insert(id, (promise_global, sender)); } else { assert!(status == v8::ModuleStatus::Errored); } } - Ok(receiver) - } - - pub async fn mod_evaluate(&mut self, id: ModuleId) -> Result<(), AnyError> { - let mut receiver = self.mod_evaluate_inner(id)?; - - poll_fn(|cx| { - if let Poll::Ready(result) = receiver.poll_next_unpin(cx) { - debug!("received module evaluate"); - return Poll::Ready(result.unwrap()); + match status { + v8::ModuleStatus::Evaluated => Ok(()), + v8::ModuleStatus::Errored => { + let exception = module.get_exception(); + exception_to_err_result(scope, exception) + .map_err(|err| attach_handle_to_error(scope, err, exception)) } - let _r = self.poll_event_loop(cx)?; - Poll::Pending - }) - .await + other => panic!("Unexpected module status {:?}", other), + } } fn dyn_import_error( @@ -1031,122 +907,16 @@ impl JsRuntime { // Load is done. let module_id = load.root_module_id.unwrap(); self.mod_instantiate(module_id)?; - self.dyn_mod_evaluate(dyn_import_id, module_id)?; + match self.mod_evaluate(module_id) { + Ok(()) => self.dyn_import_done(dyn_import_id, module_id)?, + Err(err) => self.dyn_import_error(dyn_import_id, err)?, + }; } } } } } - fn evaluate_pending_modules(&mut self) -> Result<(), AnyError> { - let state_rc = Self::state(self.v8_isolate()); - - let context = self.global_context(); - { - let scope = - &mut v8::HandleScope::with_context(self.v8_isolate(), context); - - let mut state = state_rc.borrow_mut(); - - if let Some(&module_id) = state.pending_mod_evaluate.keys().next() { - let handle = state.pending_mod_evaluate.remove(&module_id).unwrap(); - drop(state); - - let promise = handle.0.get(scope); - let mut sender = handle.1.clone(); - - let promise_state = promise.state(); - - match promise_state { - v8::PromiseState::Pending => { - state_rc - .borrow_mut() - .pending_mod_evaluate - .insert(module_id, handle); - state_rc.borrow().waker.wake(); - } - v8::PromiseState::Fulfilled => { - sender.try_send(Ok(())).unwrap(); - } - v8::PromiseState::Rejected => { - let exception = promise.result(scope); - let err1 = exception_to_err_result::<()>(scope, exception) - .map_err(|err| attach_handle_to_error(scope, err, exception)) - .unwrap_err(); - sender.try_send(Err(err1)).unwrap(); - } - } - } - }; - - Ok(()) - } - - fn evaluate_dyn_imports(&mut self) -> Result<(), AnyError> { - let state_rc = Self::state(self.v8_isolate()); - - loop { - let context = self.global_context(); - let maybe_result = { - let scope = - &mut v8::HandleScope::with_context(self.v8_isolate(), context); - - let mut state = state_rc.borrow_mut(); - if let Some(&dyn_import_id) = - state.pending_dyn_mod_evaluate.keys().next() - { - let handle = state - .pending_dyn_mod_evaluate - .remove(&dyn_import_id) - .unwrap(); - drop(state); - - let module_id = handle.0; - let promise = handle.1.get(scope); - let _module = handle.2.get(scope); - - let promise_state = promise.state(); - - match promise_state { - v8::PromiseState::Pending => { - state_rc - .borrow_mut() - .pending_dyn_mod_evaluate - .insert(dyn_import_id, handle); - state_rc.borrow().waker.wake(); - None - } - v8::PromiseState::Fulfilled => Some(Ok((dyn_import_id, module_id))), - v8::PromiseState::Rejected => { - let exception = promise.result(scope); - let err1 = exception_to_err_result::<()>(scope, exception) - .map_err(|err| attach_handle_to_error(scope, err, exception)) - .unwrap_err(); - Some(Err((dyn_import_id, err1))) - } - } - } else { - None - } - }; - - if let Some(result) = maybe_result { - match result { - Ok((dyn_import_id, module_id)) => { - self.dyn_import_done(dyn_import_id, module_id)?; - } - Err((dyn_import_id, err1)) => { - self.dyn_import_error(dyn_import_id, err1)?; - } - } - } else { - break; - } - } - - Ok(()) - } - fn register_during_load( &mut self, info: ModuleSource, @@ -1445,13 +1215,13 @@ pub mod tests { futures::executor::block_on(lazy(move |cx| f(cx))); } - fn poll_until_ready( - runtime: &mut JsRuntime, - max_poll_count: usize, - ) -> Result<(), AnyError> { + fn poll_until_ready(future: &mut F, max_poll_count: usize) -> F::Output + where + F: Future + Unpin, + { let mut cx = Context::from_waker(futures::task::noop_waker_ref()); for _ in 0..max_poll_count { - match runtime.poll_event_loop(&mut cx) { + match future.poll_unpin(&mut cx) { Poll::Pending => continue, Poll::Ready(val) => return val, } @@ -1667,7 +1437,7 @@ pub mod tests { ) .unwrap(); assert_eq!(dispatch_count.load(Ordering::Relaxed), 1); - assert!(matches!(runtime.poll_event_loop(cx), Poll::Ready(Ok(_)))); + assert!(matches!(runtime.poll_unpin(cx), Poll::Ready(Ok(_)))); assert_eq!(dispatch_count.load(Ordering::Relaxed), 1); runtime .execute( @@ -1680,11 +1450,11 @@ pub mod tests { ) .unwrap(); assert_eq!(dispatch_count.load(Ordering::Relaxed), 2); - assert!(matches!(runtime.poll_event_loop(cx), Poll::Ready(Ok(_)))); + assert!(matches!(runtime.poll_unpin(cx), Poll::Ready(Ok(_)))); runtime.execute("check3.js", "assert(nrecv == 2)").unwrap(); assert_eq!(dispatch_count.load(Ordering::Relaxed), 2); // We are idle, so the next poll should be the last. - assert!(matches!(runtime.poll_event_loop(cx), Poll::Ready(Ok(_)))); + assert!(matches!(runtime.poll_unpin(cx), Poll::Ready(Ok(_)))); }); } @@ -1708,7 +1478,7 @@ pub mod tests { assert_eq!(dispatch_count.load(Ordering::Relaxed), 1); // The above op never finish, but runtime can finish // because the op is an unreffed async op. - assert!(matches!(runtime.poll_event_loop(cx), Poll::Ready(Ok(_)))); + assert!(matches!(runtime.poll_unpin(cx), Poll::Ready(Ok(_)))); }) } @@ -1838,7 +1608,7 @@ pub mod tests { ) .unwrap(); assert_eq!(dispatch_count.load(Ordering::Relaxed), 1); - assert!(matches!(runtime.poll_event_loop(cx), Poll::Ready(Ok(_)))); + assert!(matches!(runtime.poll_unpin(cx), Poll::Ready(Ok(_)))); runtime .execute("check.js", "assert(asyncRecv == 1);") .unwrap(); @@ -1930,7 +1700,7 @@ pub mod tests { "#, ) .unwrap(); - if let Poll::Ready(Err(_)) = runtime.poll_event_loop(&mut cx) { + if let Poll::Ready(Err(_)) = runtime.poll_unpin(&mut cx) { unreachable!(); } }); @@ -1943,7 +1713,7 @@ pub mod tests { runtime .execute("core_test.js", include_str!("core_test.js")) .unwrap(); - if let Poll::Ready(Err(_)) = runtime.poll_event_loop(&mut cx) { + if let Poll::Ready(Err(_)) = runtime.poll_unpin(&mut cx) { unreachable!(); } }); @@ -1969,7 +1739,7 @@ pub mod tests { include_str!("encode_decode_test.js"), ) .unwrap(); - if let Poll::Ready(Err(_)) = runtime.poll_event_loop(&mut cx) { + if let Poll::Ready(Err(_)) = runtime.poll_unpin(&mut cx) { unreachable!(); } }); @@ -2218,7 +1988,7 @@ pub mod tests { runtime.mod_instantiate(mod_a).unwrap(); assert_eq!(dispatch_count.load(Ordering::Relaxed), 0); - runtime.mod_evaluate_inner(mod_a).unwrap(); + runtime.mod_evaluate(mod_a).unwrap(); assert_eq!(dispatch_count.load(Ordering::Relaxed), 1); } @@ -2277,7 +2047,7 @@ pub mod tests { assert_eq!(count.load(Ordering::Relaxed), 0); // We should get an error here. - let result = runtime.poll_event_loop(cx); + let result = runtime.poll_unpin(cx); if let Poll::Ready(Ok(_)) = result { unreachable!(); } @@ -2370,14 +2140,14 @@ pub mod tests { .unwrap(); // First poll runs `prepare_load` hook. - assert!(matches!(runtime.poll_event_loop(cx), Poll::Pending)); + assert!(matches!(runtime.poll_unpin(cx), Poll::Pending)); assert_eq!(prepare_load_count.load(Ordering::Relaxed), 1); // Second poll actually loads modules into the isolate. - assert!(matches!(runtime.poll_event_loop(cx), Poll::Ready(Ok(_)))); + assert!(matches!(runtime.poll_unpin(cx), Poll::Ready(Ok(_)))); assert_eq!(resolve_count.load(Ordering::Relaxed), 4); assert_eq!(load_count.load(Ordering::Relaxed), 2); - assert!(matches!(runtime.poll_event_loop(cx), Poll::Ready(Ok(_)))); + assert!(matches!(runtime.poll_unpin(cx), Poll::Ready(Ok(_)))); assert_eq!(resolve_count.load(Ordering::Relaxed), 4); assert_eq!(load_count.load(Ordering::Relaxed), 2); }) @@ -2409,10 +2179,10 @@ pub mod tests { ) .unwrap(); // First poll runs `prepare_load` hook. - let _ = runtime.poll_event_loop(cx); + let _ = runtime.poll_unpin(cx); assert_eq!(prepare_load_count.load(Ordering::Relaxed), 1); // Second poll triggers error - let _ = runtime.poll_event_loop(cx); + let _ = runtime.poll_unpin(cx); }) } @@ -2461,7 +2231,7 @@ pub mod tests { ) .unwrap(); - futures::executor::block_on(runtime.mod_evaluate(module_id)).unwrap(); + runtime.mod_evaluate(module_id).unwrap(); let _snapshot = runtime.snapshot(); } @@ -2543,7 +2313,7 @@ main(); at async error_async_stack.js:10:5 "#; - match runtime.poll_event_loop(cx) { + match runtime.poll_unpin(cx) { Poll::Ready(Err(e)) => { assert_eq!(e.to_string(), expected_error); } diff --git a/op_crates/web/lib.rs b/op_crates/web/lib.rs index eaf7e9f140cbc3..26e36365bd3ec6 100644 --- a/op_crates/web/lib.rs +++ b/op_crates/web/lib.rs @@ -75,6 +75,7 @@ pub fn get_declaration() -> PathBuf { mod tests { use deno_core::JsRuntime; use futures::future::lazy; + use futures::future::FutureExt; use futures::task::Context; use futures::task::Poll; @@ -101,7 +102,7 @@ mod tests { include_str!("abort_controller_test.js"), ) .unwrap(); - if let Poll::Ready(Err(_)) = isolate.poll_event_loop(&mut cx) { + if let Poll::Ready(Err(_)) = isolate.poll_unpin(&mut cx) { unreachable!(); } }); @@ -114,7 +115,7 @@ mod tests { isolate .execute("event_test.js", include_str!("event_test.js")) .unwrap(); - if let Poll::Ready(Err(_)) = isolate.poll_event_loop(&mut cx) { + if let Poll::Ready(Err(_)) = isolate.poll_unpin(&mut cx) { unreachable!(); } }); @@ -133,7 +134,7 @@ mod tests { } else { unreachable!(); } - if let Poll::Ready(Err(_)) = isolate.poll_event_loop(&mut cx) { + if let Poll::Ready(Err(_)) = isolate.poll_unpin(&mut cx) { unreachable!(); } }); @@ -146,7 +147,7 @@ mod tests { isolate .execute("event_target_test.js", include_str!("event_target_test.js")) .unwrap(); - if let Poll::Ready(Err(_)) = isolate.poll_event_loop(&mut cx) { + if let Poll::Ready(Err(_)) = isolate.poll_unpin(&mut cx) { unreachable!(); } }); @@ -162,7 +163,7 @@ mod tests { include_str!("text_encoding_test.js"), ) .unwrap(); - if let Poll::Ready(Err(_)) = isolate.poll_event_loop(&mut cx) { + if let Poll::Ready(Err(_)) = isolate.poll_unpin(&mut cx) { unreachable!(); } }); From 109f2ba87e53d53ef534f37784386946a500851a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Iwa=C5=84czuk?= Date: Sat, 10 Oct 2020 12:30:55 +0200 Subject: [PATCH 44/44] v1.4.6 --- Cargo.lock | 8 ++++---- Releases.md | 8 ++++++++ cli/Cargo.toml | 14 +++++++------- core/Cargo.toml | 2 +- op_crates/fetch/Cargo.toml | 4 ++-- op_crates/web/Cargo.toml | 4 ++-- 6 files changed, 24 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3025a6c04d136b..e444ad4569fbea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -393,7 +393,7 @@ dependencies = [ [[package]] name = "deno" -version = "1.4.5" +version = "1.4.6" dependencies = [ "atty", "base64 0.12.3", @@ -451,7 +451,7 @@ dependencies = [ [[package]] name = "deno_core" -version = "0.62.0" +version = "0.63.0" dependencies = [ "anyhow", "futures", @@ -486,7 +486,7 @@ dependencies = [ [[package]] name = "deno_fetch" -version = "0.6.0" +version = "0.7.0" dependencies = [ "deno_core", "reqwest", @@ -511,7 +511,7 @@ dependencies = [ [[package]] name = "deno_web" -version = "0.14.0" +version = "0.15.0" dependencies = [ "deno_core", "futures", diff --git a/Releases.md b/Releases.md index 5d77081bb754fe..e7209ce7a0b6b6 100644 --- a/Releases.md +++ b/Releases.md @@ -6,6 +6,14 @@ https://github.com/denoland/deno/releases We also have one-line install commands at: https://github.com/denoland/deno_install +### 1.4.6 / 2020.10.10 + +- fix: 100% CPU idling problem by reverting #7672 (#7911) +- fix(op_crate/web): add padding on URLSearchParam (#7905) +- fix(op_crates/fetch): Stringify and parse Request URLs (#7838) +- refactor(core): Implement Serialize for ModuleSpecifier (#7900) +- upgrade: Rust 1.47.0 (#7886) + ### 1.4.5 / 2020.10.08 - feat(unstable): Revert "enable importsNotUsedAsValues by default #7413" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 6c816d8335714a..8e8113ec956abb 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno" -version = "1.4.5" +version = "1.4.6" license = "MIT" authors = ["the Deno authors"] edition = "2018" @@ -20,20 +20,20 @@ harness = false path = "./bench/main.rs" [build-dependencies] -deno_core = { path = "../core", version = "0.62.0" } -deno_web = { path = "../op_crates/web", version = "0.14.0" } -deno_fetch = { path = "../op_crates/fetch", version = "0.6.0" } +deno_core = { path = "../core", version = "0.63.0" } +deno_web = { path = "../op_crates/web", version = "0.15.0" } +deno_fetch = { path = "../op_crates/fetch", version = "0.7.0" } [target.'cfg(windows)'.build-dependencies] winres = "0.1.11" winapi = "0.3.9" [dependencies] -deno_core = { path = "../core", version = "0.62.0" } +deno_core = { path = "../core", version = "0.63.0" } deno_doc = "0.1.11" deno_lint = { version = "0.2.3", features = ["json"] } -deno_web = { path = "../op_crates/web", version = "0.14.0" } -deno_fetch = { path = "../op_crates/fetch", version = "0.6.0" } +deno_web = { path = "../op_crates/web", version = "0.15.0" } +deno_fetch = { path = "../op_crates/fetch", version = "0.7.0" } atty = "0.2.14" base64 = "0.12.3" diff --git a/core/Cargo.toml b/core/Cargo.toml index 0a66596aa97783..c114a64d0b0c40 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -1,7 +1,7 @@ # Copyright 2018-2020 the Deno authors. All rights reserved. MIT license. [package] name = "deno_core" -version = "0.62.0" +version = "0.63.0" edition = "2018" description = "A secure JavaScript/TypeScript runtime built with V8, Rust, and Tokio" authors = ["the Deno authors"] diff --git a/op_crates/fetch/Cargo.toml b/op_crates/fetch/Cargo.toml index d84d27a1aa53ea..79197e52832a87 100644 --- a/op_crates/fetch/Cargo.toml +++ b/op_crates/fetch/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_fetch" -version = "0.6.0" +version = "0.7.0" edition = "2018" description = "provides fetch Web API to deno_core" authors = ["the Deno authors"] @@ -14,6 +14,6 @@ repository = "https://github.com/denoland/deno" path = "lib.rs" [dependencies] -deno_core = { version = "0.62.0", path = "../../core" } +deno_core = { version = "0.63.0", path = "../../core" } reqwest = { version = "0.10.8", default-features = false, features = ["rustls-tls", "stream", "gzip", "brotli"] } serde = { version = "1.0.116", features = ["derive"] } diff --git a/op_crates/web/Cargo.toml b/op_crates/web/Cargo.toml index 6c9285c36c44ae..7d0c3de6c76f21 100644 --- a/op_crates/web/Cargo.toml +++ b/op_crates/web/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "deno_web" -version = "0.14.0" +version = "0.15.0" edition = "2018" description = "Collection of Web APIs" authors = ["the Deno authors"] @@ -14,7 +14,7 @@ repository = "https://github.com/denoland/deno" path = "lib.rs" [dependencies] -deno_core = { version = "0.62.0", path = "../../core" } +deno_core = { version = "0.63.0", path = "../../core" } idna = "0.2.0" serde = { version = "1.0.116", features = ["derive"] }