diff --git a/src/Cargo.lock b/src/Cargo.lock index 8fbf3535264fc..5b44f0ea34e04 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -838,7 +838,7 @@ dependencies = [ [[package]] name = "html-diff" -version = "0.0.5" +version = "0.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kuchiki 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2127,7 +2127,7 @@ version = "0.0.0" dependencies = [ "build_helper 0.1.0", "cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "html-diff 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "html-diff 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2855,7 +2855,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum handlebars 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fb04af2006ea09d985fef82b81e0eb25337e51b691c76403332378a53d521edc" "checksum hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa" "checksum home 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f25ae61099d8f3fee8b483df0bd4ecccf4b2731897aad40d50eca1b641fe6db" -"checksum html-diff 0.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "9778743e3b3c3679f471f0ed1833c690f19f4a0919e33b281f12ef5f77ad64c6" +"checksum html-diff 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ee4cfdf62a484a3ac0d9b80f562d37f99366db08a63621b917ea3056565345f7" "checksum html5ever 0.20.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5bfb46978eb757a603b7dfe2dafb1c62cb4dee3428d8ac1de734d83d6b022d06" "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" "checksum if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "61bb90bdd39e3af69b0172dfc6130f6cd6332bf040fbb9bdd4401d37adbd48b8" diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 8e35ecc8090c6..deade80334e96 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -254,7 +254,9 @@ impl<'a> Builder<'a> { Kind::Test => describe!(check::Tidy, check::Bootstrap, check::DefaultCompiletest, check::HostCompiletest, check::Crate, check::CrateLibrustc, check::Rustdoc, check::Linkcheck, check::Cargotest, check::Cargo, check::Rls, check::Docs, - check::ErrorIndex, check::Distcheck, check::Rustfmt, check::Miri, check::Clippy), + check::ErrorIndex, check::Distcheck, check::Rustfmt, check::Miri, check::Clippy, + check::RustdocJS), + Kind::Bench => describe!(check::Crate, check::CrateLibrustc), Kind::Doc => describe!(doc::UnstableBook, doc::UnstableBookGen, doc::TheBook, doc::Standalone, doc::Std, doc::Test, doc::Rustc, doc::ErrorIndex, doc::Nomicon, @@ -443,7 +445,8 @@ impl<'a> Builder<'a> { let out_dir = self.stage_out(compiler, mode); cargo.env("CARGO_TARGET_DIR", out_dir) .arg(cmd) - .arg("--target").arg(target); + .arg("--target") + .arg(target); // If we were invoked from `make` then that's already got a jobserver // set up for us so no need to tell Cargo about jobs all over again. diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index ed110762cb3c0..78ad71172a848 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -424,6 +424,43 @@ fn path_for_cargo(builder: &Builder, compiler: Compiler) -> OsString { env::join_paths(iter::once(path).chain(env::split_paths(&old_path))).expect("") } +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct RustdocJS { + pub host: Interned, + pub target: Interned, +} + +impl Step for RustdocJS { + type Output = (); + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun) -> ShouldRun { + run.path("src/test/rustdoc-js") + } + + fn make_run(run: RunConfig) { + run.builder.ensure(RustdocJS { + host: run.host, + target: run.target, + }); + } + + fn run(self, builder: &Builder) { + if let Some(ref nodejs) = builder.config.nodejs { + let mut command = Command::new(nodejs); + command.args(&["src/tools/rustdoc-js/tester.js", &*self.host]); + builder.ensure(::doc::Std { + target: self.target, + stage: builder.top_stage, + }); + builder.run(&mut command); + } else { + println!("No nodejs found, skipping \"src/test/rustdoc-js\" tests"); + } + } +} + #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct Tidy { host: Interned, diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index d66c01eb4990e..2b765fa498e96 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -419,8 +419,8 @@ impl Step for Standalone { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct Std { - stage: u32, - target: Interned, + pub stage: u32, + pub target: Interned, } impl Step for Std { diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 2b0c839152ccb..ceb39aea108c8 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -691,8 +691,7 @@ impl<'a> Resolver<'a> { if let Some(suggestion) = suggestion { if suggestion != name { if let MacroKind::Bang = kind { - err.span_suggestion(span, "you could try the macro", - format!("{}!", suggestion)); + err.span_suggestion(span, "you could try the macro", suggestion.to_string()); } else { err.span_suggestion(span, "try", suggestion.to_string()); } diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 1ee04a46243a2..db0b045ef1e73 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -1360,15 +1360,10 @@ fn start_executing_work(tcx: TyCtxt, let sess = tcx.sess; // First up, convert our jobserver into a helper thread so we can use normal - // mpsc channels to manage our messages and such. Once we've got the helper - // thread then request `n-1` tokens because all of our work items are ready - // to go. - // - // Note that the `n-1` is here because we ourselves have a token (our - // process) and we'll use that token to execute at least one unit of work. - // - // After we've requested all these tokens then we'll, when we can, get - // tokens on `rx` above which will get managed in the main loop below. + // mpsc channels to manage our messages and such. + // After we've requested tokens then we'll, when we can, + // get tokens on `coordinator_receive` which will + // get managed in the main loop below. let coordinator_send2 = coordinator_send.clone(); let helper = jobserver.into_helper_thread(move |token| { drop(coordinator_send2.send(Box::new(Message::Token(token)))); diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 1e574964b12dc..608adcb43d6c3 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -12,7 +12,7 @@ doctest = false [dependencies] pulldown-cmark = { version = "0.1.0", default-features = false } -html-diff = "0.0.5" +html-diff = "0.0.6" tempdir = "0.3" [build-dependencies] diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index b4dbd76d0b4d0..a9a5bd5de0552 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -353,35 +353,33 @@ * This code is an unmodified version of the code written by Marco de Wit * and was found at http://stackoverflow.com/a/18514751/745719 */ - var levenshtein = (function() { - var row2 = []; - return function(s1, s2) { - if (s1 === s2) { - return 0; + var levenshtein_row2 = []; + function levenshtein(s1, s2) { + if (s1 === s2) { + return 0; + } + var s1_len = s1.length, s2_len = s2.length; + if (s1_len && s2_len) { + var i1 = 0, i2 = 0, a, b, c, c2, row = levenshtein_row2; + while (i1 < s1_len) { + row[i1] = ++i1; } - var s1_len = s1.length, s2_len = s2.length; - if (s1_len && s2_len) { - var i1 = 0, i2 = 0, a, b, c, c2, row = row2; - while (i1 < s1_len) { - row[i1] = ++i1; - } - while (i2 < s2_len) { - c2 = s2.charCodeAt(i2); - a = i2; - ++i2; - b = i2; - for (i1 = 0; i1 < s1_len; ++i1) { - c = a + (s1.charCodeAt(i1) !== c2 ? 1 : 0); - a = row[i1]; - b = b < a ? (b < c ? b + 1 : c) : (a < c ? a + 1 : c); - row[i1] = b; - } + while (i2 < s2_len) { + c2 = s2.charCodeAt(i2); + a = i2; + ++i2; + b = i2; + for (i1 = 0; i1 < s1_len; ++i1) { + c = a + (s1.charCodeAt(i1) !== c2 ? 1 : 0); + a = row[i1]; + b = b < a ? (b < c ? b + 1 : c) : (a < c ? a + 1 : c); + row[i1] = b; } - return b; } - return s1_len + s2_len; - }; - })(); + return b; + } + return s1_len + s2_len; + } function initSearch(rawSearchIndex) { var currentResults, index, searchIndex; @@ -400,12 +398,20 @@ /** * Executes the query and builds an index of results * @param {[Object]} query [The user query] - * @param {[type]} max [The maximum results returned] * @param {[type]} searchWords [The list of search words to query * against] * @return {[type]} [A search index of results] */ - function execQuery(query, max, searchWords) { + function execQuery(query, searchWords) { + function itemTypeFromName(typename) { + for (var i = 0; i < itemTypes.length; ++i) { + if (itemTypes[i] === typename) { + return i; + } + } + return -1; + } + var valLower = query.query.toLowerCase(), val = valLower, typeFilter = itemTypeFromName(query.type), @@ -1021,9 +1027,8 @@ return true; } - function getQuery() { - var matches, type, query, raw = - document.getElementsByClassName('search-input')[0].value; + function getQuery(raw) { + var matches, type, query; query = raw; matches = query.match(/^(fn|mod|struct|enum|trait|type|const|macro)\s*:\s*/i); @@ -1227,7 +1232,7 @@ } function showResults(results) { - var output, query = getQuery(); + var output, query = getQuery(document.getElementsByClassName('search-input')[0].value); currentResults = query.id; output = '

Results for ' + escape(query.query) + @@ -1271,7 +1276,7 @@ resultIndex; var params = getQueryStringParams(); - query = getQuery(); + query = getQuery(document.getElementsByClassName('search-input')[0].value); if (e) { e.preventDefault(); } @@ -1293,19 +1298,10 @@ } } - results = execQuery(query, 20000, index); + results = execQuery(query, index); showResults(results); } - function itemTypeFromName(typename) { - for (var i = 0; i < itemTypes.length; ++i) { - if (itemTypes[i] === typename) { - return i; - } - } - return -1; - } - function buildIndex(rawSearchIndex) { searchIndex = []; var searchWords = []; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 3b43eafb849bd..0b57d5d26cecf 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -242,8 +242,8 @@ pub fn opts() -> Vec { or `#![doc(html_playground_url=...)]`", "URL") }), - unstable("enable-commonmark", |o| { - o.optflag("", "enable-commonmark", "to enable commonmark doc rendering/testing") + unstable("disable-commonmark", |o| { + o.optflag("", "disable-commonmark", "to disable commonmark doc rendering/testing") }), unstable("display-warnings", |o| { o.optflag("", "display-warnings", "to print code warnings when testing doc") @@ -347,10 +347,10 @@ pub fn main_args(args: &[String]) -> isize { let css_file_extension = matches.opt_str("e").map(|s| PathBuf::from(&s)); let cfgs = matches.opt_strs("cfg"); - let render_type = if matches.opt_present("enable-commonmark") { - RenderType::Pulldown - } else { + let render_type = if matches.opt_present("disable-commonmark") { RenderType::Hoedown + } else { + RenderType::Pulldown }; if let Some(ref p) = css_file_extension { diff --git a/src/test/rustdoc-js/basic.js b/src/test/rustdoc-js/basic.js new file mode 100644 index 0000000000000..863437cac91d4 --- /dev/null +++ b/src/test/rustdoc-js/basic.js @@ -0,0 +1,25 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +const QUERY = 'String'; + +const EXPECTED = { + 'others': [ + { 'path': 'std::string', 'name': 'String' }, + { 'path': 'std::ffi', 'name': 'OsString' }, + { 'path': 'std::ffi', 'name': 'CString' }, + ], + 'in_args': [ + { 'path': 'std::str', 'name': 'eq' }, + ], + 'returned': [ + { 'path': 'std::string::String', 'name': 'add' }, + ], +}; diff --git a/src/test/rustdoc-js/enum-option.js b/src/test/rustdoc-js/enum-option.js new file mode 100644 index 0000000000000..3dac983b11b0e --- /dev/null +++ b/src/test/rustdoc-js/enum-option.js @@ -0,0 +1,17 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +const QUERY = 'enum:Option'; + +const EXPECTED = { + 'others': [ + { 'path': 'std::option', 'name': 'Option' }, + ], +}; diff --git a/src/test/rustdoc-js/fn-forget.js b/src/test/rustdoc-js/fn-forget.js new file mode 100644 index 0000000000000..10310d5eaf7b9 --- /dev/null +++ b/src/test/rustdoc-js/fn-forget.js @@ -0,0 +1,18 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +const QUERY = 'fn:forget'; + +const EXPECTED = { + 'others': [ + { 'path': 'std::mem', 'name': 'forget' }, + { 'path': 'std::fmt', 'name': 'format' }, + ], +}; diff --git a/src/test/rustdoc-js/from_u.js b/src/test/rustdoc-js/from_u.js new file mode 100644 index 0000000000000..920620a9aeed5 --- /dev/null +++ b/src/test/rustdoc-js/from_u.js @@ -0,0 +1,22 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +const QUERY = 'from_u'; + +const EXPECTED = { + 'others': [ + { 'path': 'std::char', 'name': 'from_u32' }, + { 'path': 'std::str', 'name': 'from_utf8' }, + { 'path': 'std::string::String', 'name': 'from_utf8' }, + { 'path': 'std::boxed::Box', 'name': 'from_unique' }, + { 'path': 'std::i32', 'name': 'from_unsigned' }, + { 'path': 'std::i128', 'name': 'from_unsigned' }, + ], +}; diff --git a/src/test/rustdoc-js/macro-print.js b/src/test/rustdoc-js/macro-print.js new file mode 100644 index 0000000000000..811ba3474afa0 --- /dev/null +++ b/src/test/rustdoc-js/macro-print.js @@ -0,0 +1,20 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +const QUERY = 'macro:print'; + +const EXPECTED = { + 'others': [ + { 'path': 'std', 'name': 'print' }, + { 'path': 'std', 'name': 'eprint' }, + { 'path': 'std', 'name': 'println' }, + { 'path': 'std', 'name': 'eprintln' }, + ], +}; diff --git a/src/test/rustdoc-js/string-from_ut.js b/src/test/rustdoc-js/string-from_ut.js new file mode 100644 index 0000000000000..3d08ee3736612 --- /dev/null +++ b/src/test/rustdoc-js/string-from_ut.js @@ -0,0 +1,21 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +const QUERY = 'String::from_ut'; + +const EXPECTED = { + 'others': [ + { 'path': 'std::string::String', 'name': 'from_utf8' }, + { 'path': 'std::string::String', 'name': 'from_utf8' }, + { 'path': 'std::string::String', 'name': 'from_utf8_lossy' }, + { 'path': 'std::string::String', 'name': 'from_utf16_lossy' }, + { 'path': 'std::string::String', 'name': 'from_utf8_unchecked' }, + ], +}; diff --git a/src/test/rustdoc-js/struct-vec.js b/src/test/rustdoc-js/struct-vec.js new file mode 100644 index 0000000000000..a91bc2d0da288 --- /dev/null +++ b/src/test/rustdoc-js/struct-vec.js @@ -0,0 +1,19 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +const QUERY = 'struct:Vec'; + +const EXPECTED = { + 'others': [ + { 'path': 'std::vec', 'name': 'Vec' }, + { 'path': 'std::collections', 'name': 'VecDeque' }, + { 'path': 'alloc::raw_vec', 'name': 'RawVec' }, + ], +}; diff --git a/src/test/ui-fulldeps/resolve-error.stderr b/src/test/ui-fulldeps/resolve-error.stderr index be7ebae70adf5..9121ce1720c98 100644 --- a/src/test/ui-fulldeps/resolve-error.stderr +++ b/src/test/ui-fulldeps/resolve-error.stderr @@ -38,13 +38,13 @@ error: cannot find macro `FooWithLongNama!` in this scope --> $DIR/resolve-error.rs:62:5 | 62 | FooWithLongNama!(); - | ^^^^^^^^^^^^^^^ help: you could try the macro: `FooWithLongNam!` + | ^^^^^^^^^^^^^^^ help: you could try the macro: `FooWithLongNam` error: cannot find macro `attr_proc_macra!` in this scope --> $DIR/resolve-error.rs:65:5 | 65 | attr_proc_macra!(); - | ^^^^^^^^^^^^^^^ help: you could try the macro: `attr_proc_mac!` + | ^^^^^^^^^^^^^^^ help: you could try the macro: `attr_proc_mac` error: cannot find macro `Dlona!` in this scope --> $DIR/resolve-error.rs:68:5 @@ -56,7 +56,7 @@ error: cannot find macro `bang_proc_macrp!` in this scope --> $DIR/resolve-error.rs:71:5 | 71 | bang_proc_macrp!(); - | ^^^^^^^^^^^^^^^ help: you could try the macro: `bang_proc_macro!` + | ^^^^^^^^^^^^^^^ help: you could try the macro: `bang_proc_macro` error: aborting due to 10 previous errors diff --git a/src/test/ui/macros/macro-name-typo.stderr b/src/test/ui/macros/macro-name-typo.stderr index 84851749c7074..ebe95356c26eb 100644 --- a/src/test/ui/macros/macro-name-typo.stderr +++ b/src/test/ui/macros/macro-name-typo.stderr @@ -2,7 +2,7 @@ error: cannot find macro `printlx!` in this scope --> $DIR/macro-name-typo.rs:12:5 | 12 | printlx!("oh noes!"); //~ ERROR cannot find - | ^^^^^^^ help: you could try the macro: `println!` + | ^^^^^^^ help: you could try the macro: `println` error: aborting due to previous error diff --git a/src/test/ui/macros/macro_undefined.stderr b/src/test/ui/macros/macro_undefined.stderr index 6cfb05e786703..8d6da6a4732fc 100644 --- a/src/test/ui/macros/macro_undefined.stderr +++ b/src/test/ui/macros/macro_undefined.stderr @@ -10,7 +10,7 @@ error: cannot find macro `k!` in this scope --> $DIR/macro_undefined.rs:21:5 | 21 | k!(); //~ ERROR cannot find - | ^ help: you could try the macro: `kl!` + | ^ help: you could try the macro: `kl` error: aborting due to 2 previous errors diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 6458ec02669aa..f6eaa09f55d99 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -192,7 +192,17 @@ fn check(cache: &mut Cache, for part in Path::new(base).join(url).components() { match part { Component::Prefix(_) | - Component::RootDir => panic!(), + Component::RootDir => { + // Avoid absolute paths as they make the docs not + // relocatable by making assumptions on where the docs + // are hosted relative to the site root. + *errors = true; + println!("{}:{}: absolute path - {}", + pretty_file.display(), + i + 1, + Path::new(base).join(url).display()); + return; + } Component::CurDir => {} Component::ParentDir => { path.pop(); } Component::Normal(s) => { path.push(s); } diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js new file mode 100644 index 0000000000000..7c9ee2a49430b --- /dev/null +++ b/src/tools/rustdoc-js/tester.js @@ -0,0 +1,210 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +const fs = require('fs'); + +const TEST_FOLDER = 'src/test/rustdoc-js/'; + +// Stupid function extractor based on indent. +function extractFunction(content, functionName) { + var x = content.split('\n'); + var in_func = false; + var indent = 0; + var lines = []; + + for (var i = 0; i < x.length; ++i) { + if (in_func === false) { + var splitter = "function " + functionName + "("; + if (x[i].trim().startsWith(splitter)) { + in_func = true; + indent = x[i].split(splitter)[0].length; + lines.push(x[i]); + } + } else { + lines.push(x[i]); + if (x[i].trim() === "}" && x[i].split("}")[0].length === indent) { + return lines.join("\n"); + } + } + } + return null; +} + +// Stupid function extractor for array. +function extractArrayVariable(content, arrayName) { + var x = content.split('\n'); + var found_var = false; + var lines = []; + + for (var i = 0; i < x.length; ++i) { + if (found_var === false) { + var splitter = "var " + arrayName + " = ["; + if (x[i].trim().startsWith(splitter)) { + found_var = true; + i -= 1; + } + } else { + lines.push(x[i]); + if (x[i].endsWith('];')) { + return lines.join("\n"); + } + } + } + return null; +} + +// Stupid function extractor for variable. +function extractVariable(content, varName) { + var x = content.split('\n'); + var found_var = false; + var lines = []; + + for (var i = 0; i < x.length; ++i) { + if (found_var === false) { + var splitter = "var " + varName + " = "; + if (x[i].trim().startsWith(splitter)) { + found_var = true; + i -= 1; + } + } else { + lines.push(x[i]); + if (x[i].endsWith(';')) { + return lines.join("\n"); + } + } + } + return null; +} + +function loadContent(content) { + var Module = module.constructor; + var m = new Module(); + m._compile(content, "tmp.js"); + return m.exports; +} + +function readFile(filePath) { + return fs.readFileSync(filePath, 'utf8'); +} + +function loadThings(thingsToLoad, kindOfLoad, funcToCall, fileContent) { + var content = ''; + for (var i = 0; i < thingsToLoad.length; ++i) { + var tmp = funcToCall(fileContent, thingsToLoad[i]); + if (tmp === null) { + console.error('enable to find ' + kindOfLoad + ' "' + thingsToLoad[i] + '"'); + process.exit(1); + } + content += tmp; + content += 'exports.' + thingsToLoad[i] + ' = ' + thingsToLoad[i] + ';'; + } + return content; +} + +function lookForEntry(entry, data) { + for (var i = 0; i < data.length; ++i) { + var allGood = true; + for (var key in entry) { + if (!entry.hasOwnProperty(key)) { + continue; + } + var value = data[i][key]; + // To make our life easier, if there is a "parent" type, we add it to the path. + if (key === 'path' && data[i]['parent'] !== undefined) { + if (value.length > 0) { + value += '::' + data[i]['parent']['name']; + } else { + value = data[i]['parent']['name']; + } + } + if (value !== entry[key]) { + allGood = false; + break; + } + } + if (allGood === true) { + return true; + } + } + return false; +} + +function main(argv) { + if (argv.length !== 3) { + console.error("Expected toolchain to check as argument (for example 'x86_64-apple-darwin'"); + return 1; + } + var toolchain = argv[2]; + + var mainJs = readFile("build/" + toolchain + "/doc/main.js"); + var searchIndex = readFile("build/" + toolchain + "/doc/search-index.js").split("\n"); + if (searchIndex[searchIndex.length - 1].length === 0) { + searchIndex.pop(); + } + searchIndex.pop(); + searchIndex = loadContent(searchIndex.join("\n") + '\nexports.searchIndex = searchIndex;'); + finalJS = ""; + + var arraysToLoad = ["itemTypes"]; + var variablesToLoad = ["MAX_LEV_DISTANCE", "MAX_RESULTS", "TY_PRIMITIVE", "levenshtein_row2"]; + // execQuery first parameter is built in getQuery (which takes in the search input). + // execQuery last parameter is built in buildIndex. + // buildIndex requires the hashmap from search-index. + var functionsToLoad = ["levenshtein", "validateResult", "getQuery", "buildIndex", "execQuery"]; + + finalJS += 'window = { "currentCrate": "std" };\n'; + finalJS += loadThings(arraysToLoad, 'array', extractArrayVariable, mainJs); + finalJS += loadThings(variablesToLoad, 'variable', extractVariable, mainJs); + finalJS += loadThings(functionsToLoad, 'function', extractFunction, mainJs); + + var loaded = loadContent(finalJS); + var index = loaded.buildIndex(searchIndex.searchIndex); + + var errors = 0; + + fs.readdirSync(TEST_FOLDER).forEach(function(file) { + var loadedFile = loadContent(readFile(TEST_FOLDER + file) + + 'exports.QUERY = QUERY;exports.EXPECTED = EXPECTED;'); + const expected = loadedFile.EXPECTED; + const query = loadedFile.QUERY; + var results = loaded.execQuery(loaded.getQuery(query), index); + process.stdout.write('Checking "' + file + '" ... '); + var error_text = []; + for (var key in expected) { + if (!expected.hasOwnProperty(key)) { + continue; + } + if (!results.hasOwnProperty(key)) { + error_text.push('==> Unknown key "' + key + '"'); + break; + } + var entry = expected[key]; + var found = false; + for (var i = 0; i < entry.length; ++i) { + if (lookForEntry(entry[i], results[key]) === true) { + found = true; + } else { + error_text.push("==> Result not found in '" + key + "': '" + + JSON.stringify(entry[i]) + "'"); + } + } + } + if (error_text.length !== 0) { + errors += 1; + console.error("FAILED"); + console.error(error_text.join("\n")); + } else { + console.log("OK"); + } + }); + return errors; +} + +process.exit(main(process.argv));