src/tools/rustdoc-js/tester.js JAVASCRIPT 649 lines View on github.com → Search inside
1/* global globalThis */23const fs = require("fs");4const path = require("path");5const { isGeneratorObject } = require("util/types");67const CHANNEL_REGEX = new RegExp("/nightly/|/beta/|/stable/|/1\\.[0-9]+\\.[0-9]+/");89function arrayToCode(array) {10    return array.map((value, index) => {11        value = value.split("&nbsp;").join(" ");12        return (index % 2 === 1) ? ("`" + value + "`") : value;13    }).join("");14}1516function loadContent(content) {17    const Module = module.constructor;18    const m = new Module();19    m._compile(content, "tmp.js");20    m.exports.ignore_order = content.indexOf("\n// ignore-order\n") !== -1 ||21        content.startsWith("// ignore-order\n");22    m.exports.exact_check = content.indexOf("\n// exact-check\n") !== -1 ||23        content.startsWith("// exact-check\n");24    m.exports.should_fail = content.indexOf("\n// should-fail\n") !== -1 ||25        content.startsWith("// should-fail\n");26    return m.exports;27}2829function readFile(filePath) {30    return fs.readFileSync(filePath, "utf8");31}3233function contentToDiffLine(key, value) {34    if (typeof value === "object" && !Array.isArray(value) && value !== null) {35        const out = Object.entries(value)36            .filter(([subKey, _]) => ["path", "name"].includes(subKey))37            .map(([subKey, subValue]) => `"${subKey}": ${JSON.stringify(subValue)}`)38            .join(", ");39        return `"${key}": ${out},`;40    }41    return `"${key}": ${JSON.stringify(value)},`;42}4344function shouldIgnoreField(fieldName) {45    return fieldName === "query" || fieldName === "correction" ||46        fieldName === "proposeCorrectionFrom" ||47        fieldName === "proposeCorrectionTo";48}4950function valueMapper(key, testOutput) {51    let value = testOutput[key];52    // To make our life easier, if there is a "parent" type, we add it to the path.53    if (key === "path") {54        if (testOutput["parent"]) {55            if (value.length > 0) {56                value += "::" + testOutput["parent"]["name"];57            } else {58                value = testOutput["parent"]["name"];59            }60        }61    } else if (key === "href") {62        value = value.replace(CHANNEL_REGEX, "/$CHANNEL/");63    }64    return value;65}6667// This function is only called when no matching result was found and therefore will only display68// the diff between the two items.69function betterLookingDiff(expected, testOutput) {70    let output = " {\n";71    const spaces = "    ";72    for (const key in expected) {73        if (!Object.prototype.hasOwnProperty.call(expected, key)) {74            continue;75        }76        const expectedValue = expected[key];77        if (!testOutput || !Object.prototype.hasOwnProperty.call(testOutput, key)) {78            output += "-" + spaces + contentToDiffLine(key, expectedValue) + "\n";79            continue;80        }81        const value = valueMapper(key, testOutput);82        if (value !== expectedValue) {83            output += "-" + spaces + contentToDiffLine(key, expectedValue) + "\n";84            output += "+" + spaces + contentToDiffLine(key, value) + "\n";85        } else {86            output += spaces + " " + contentToDiffLine(key, value) + "\n";87        }88    }89    return output + " }";90}9192function lookForEntry(expected, testOutput) {93    return testOutput.findIndex(testOutputEntry => {94        let allGood = true;95        for (const key in expected) {96            if (!Object.prototype.hasOwnProperty.call(expected, key)) {97                continue;98            }99            const value = valueMapper(key, testOutputEntry);100            let expectedValue = expected[key];101            if (key === "href") {102                expectedValue = expectedValue.replace(CHANNEL_REGEX, "/$CHANNEL/");103            }104            if (value !== expectedValue) {105                allGood = false;106                break;107            }108        }109        return allGood === true;110    });111}112113// This function checks if `expected` has all the required fields needed for the checks.114function checkNeededFields(fullPath, expected, error_text, queryName, position) {115    let fieldsToCheck;116    if (fullPath.length === 0) {117        fieldsToCheck = [118            "foundElems",119            "returned",120            "userQuery",121            "error",122        ];123    } else if (fullPath.endsWith("elems") || fullPath.endsWith("returned")) {124        fieldsToCheck = [125            "name",126            "fullPath",127            "pathWithoutLast",128            "pathLast",129            "generics",130        ];131    } else if (fullPath.endsWith("generics")) {132        fieldsToCheck = [133            "name",134            "fullPath",135            "pathWithoutLast",136            "pathLast",137            "generics",138        ];139    } else {140        fieldsToCheck = [];141    }142    for (const field of fieldsToCheck) {143        if (!Object.prototype.hasOwnProperty.call(expected, field)) {144            let text = `${queryName}==> Mandatory key \`${field}\` is not present`;145            if (fullPath.length > 0) {146                text += ` in field \`${fullPath}\``;147                if (position !== null) {148                    text += ` (position ${position})`;149                }150            }151            error_text.push(text);152        }153    }154}155156function valueCheck(fullPath, expected, result, error_text, queryName) {157    if (Array.isArray(expected) && result instanceof Map) {158        const expected_set = new Set();159        for (const [key, expected_value] of expected) {160            expected_set.add(key);161            checkNeededFields(fullPath, expected_value, error_text, queryName, key);162            if (result.has(key)) {163                valueCheck(164                    fullPath + "[" + key + "]",165                    expected_value,166                    result.get(key),167                    error_text,168                    queryName,169                );170            } else {171                error_text.push(`${queryName}==> EXPECTED has extra key in map from field ` +172                    `\`${fullPath}\` (key ${key}): \`${JSON.stringify(expected_value)}\``);173            }174        }175        for (const [key, result_value] of result.entries()) {176            if (!expected_set.has(key)) {177                error_text.push(`${queryName}==> EXPECTED missing key in map from field ` +178                    `\`${fullPath}\` (key ${key}): \`${JSON.stringify(result_value)}\``);179            }180        }181    } else if (Array.isArray(expected)) {182        let i;183        for (i = 0; i < expected.length; ++i) {184            checkNeededFields(fullPath, expected[i], error_text, queryName, i);185            if (i >= result.length) {186                error_text.push(`${queryName}==> EXPECTED has extra value in array from field ` +187                    `\`${fullPath}\` (position ${i}): \`${JSON.stringify(expected[i])}\``);188            } else {189                valueCheck(fullPath + "[" + i + "]", expected[i], result[i], error_text, queryName);190            }191        }192        for (; i < result.length; ++i) {193            error_text.push(`${queryName}==> RESULT has extra value in array from field ` +194                `\`${fullPath}\` (position ${i}): \`${JSON.stringify(result[i])}\` ` +195                "compared to EXPECTED");196        }197    } else if (expected !== null && typeof expected !== "undefined" &&198               expected.constructor == Object) { // eslint-disable-line eqeqeq199        for (const key in expected) {200            if (shouldIgnoreField(key)) {201                continue;202            }203            if (!Object.prototype.hasOwnProperty.call(expected, key)) {204                continue;205            }206            if (!Object.prototype.hasOwnProperty.call(result, key)) {207                error_text.push("==> Unknown key \"" + key + "\"");208                break;209            }210            let result_v = result[key];211            if (result_v !== null && key === "error") {212                if (!result_v.forEach) {213                    throw result_v;214                }215                result_v = arrayToCode(result_v);216            }217            const obj_path = fullPath + (fullPath.length > 0 ? "." : "") + key;218            valueCheck(obj_path, expected[key], result_v, error_text, queryName);219        }220    } else {221        const expectedValue = JSON.stringify(expected);222        const resultValue = JSON.stringify(result);223        if (expectedValue !== resultValue) {224            error_text.push(`${queryName}==> Different values for field \`${fullPath}\`:\n` +225                `EXPECTED: \`${expectedValue}\`\nRESULT:   \`${resultValue}\``);226        }227    }228}229230function runParser(query, expected, parseQuery, queryName) {231    const error_text = [];232    checkNeededFields("", expected, error_text, queryName, null);233    if (error_text.length === 0) {234        valueCheck("", expected, parseQuery(query), error_text, queryName);235    }236    return error_text;237}238239async function runSearch(query, expected, doSearch, loadedFile, queryName) {240    const ignore_order = loadedFile.ignore_order;241    const exact_check = loadedFile.exact_check;242243    const { resultsTable } = await doSearch(query, loadedFile.FILTER_CRATE);244    const error_text = [];245246    for (const key in expected) {247        if (shouldIgnoreField(key)) {248            continue;249        }250        if (!Object.prototype.hasOwnProperty.call(expected, key)) {251            continue;252        }253        if (!Object.prototype.hasOwnProperty.call(resultsTable, key)) {254            error_text.push("==> Unknown key \"" + key + "\"");255            break;256        }257        const entry = expected[key];258259        if (exact_check && entry.length !== resultsTable[key].length) {260            error_text.push(queryName + "==> Expected exactly " + entry.length +261                            " results but found " + resultsTable[key].length + " in '" + key + "'");262        }263264        let prev_pos = -1;265        for (const [index, elem] of entry.entries()) {266            const entry_pos = lookForEntry(elem, resultsTable[key]);267            if (entry_pos === -1) {268                error_text.push(queryName + "==> Result not found in '" + key + "': '" +269                                JSON.stringify(elem) + "'");270                // By default, we just compare the two first items.271                let item_to_diff = 0;272                if ((!ignore_order || exact_check) && index < resultsTable[key].length) {273                    item_to_diff = index;274                }275                error_text.push("Diff of first error:\n" +276                    betterLookingDiff(elem, resultsTable[key][item_to_diff]));277            } else if (exact_check === true && prev_pos + 1 !== entry_pos) {278                error_text.push(queryName + "==> Exact check failed at position " + (prev_pos + 1) +279                                ": expected '" + JSON.stringify(elem) + "' but found '" +280                                JSON.stringify(resultsTable[key][index]) + "'");281            } else if (ignore_order === false && entry_pos < prev_pos) {282                error_text.push(queryName + "==> '" +283                                JSON.stringify(elem) + "' was supposed to be before '" +284                                JSON.stringify(resultsTable[key][prev_pos]) + "'");285            } else {286                prev_pos = entry_pos;287            }288        }289    }290    return error_text;291}292293async function runCorrections(query, corrections, doSearch, loadedFile) {294    const { parsedQuery } = await doSearch(query, loadedFile.FILTER_CRATE);295    const qc = parsedQuery.correction;296    const error_text = [];297298    if (corrections === null) {299        if (qc !== null) {300            error_text.push(`==> [correction] expected = null, found = ${qc}`);301        }302        return error_text;303    }304305    if (qc.toLowerCase() !== corrections.toLowerCase()) {306        error_text.push(`==> [correction] expected = ${corrections}, found = ${qc}`);307    }308309    return error_text;310}311312function checkResult(error_text, loadedFile, displaySuccess) {313    if (error_text.length === 0 && loadedFile.should_fail === true) {314        console.log("FAILED");315        console.log("==> Test was supposed to fail but all items were found...");316    } else if (error_text.length !== 0 && loadedFile.should_fail === false) {317        console.log("FAILED");318        console.log(error_text.join("\n"));319    } else {320        if (displaySuccess) {321            console.log("OK");322        }323        return 0;324    }325    return 1;326}327328async function runCheckInner(callback, loadedFile, entry, extra, doSearch) {329    if (typeof entry.query !== "string") {330        console.log("FAILED");331        console.log("==> Missing `query` field");332        return false;333    }334    let error_text = await callback(335        entry.query,336        entry,337        extra ? "[ query `" + entry.query + "`]" : "",338    );339    if (checkResult(error_text, loadedFile, false) !== 0) {340        return false;341    }342    if (entry.correction !== undefined) {343        error_text = await runCorrections(344            entry.query,345            entry.correction,346            doSearch,347            loadedFile,348        );349        if (checkResult(error_text, loadedFile, false) !== 0) {350            return false;351        }352    }353    return true;354}355356async function runCheck(loadedFile, key, doSearch, callback) {357    const expected = loadedFile[key];358359    if (Array.isArray(expected)) {360        for (const entry of expected) {361            if (!await runCheckInner(callback, loadedFile, entry, true, doSearch)) {362                return 1;363            }364        }365    } else if (!await runCheckInner(callback, loadedFile, expected, false, doSearch)) {366        return 1;367    }368    console.log("OK");369    return 0;370}371372function hasCheck(content, checkName) {373    return content.startsWith(`const ${checkName}`) || content.includes(`\nconst ${checkName}`);374}375376async function runChecks(testFile, doSearch, parseQuery, revision) {377    let checkExpected = false;378    let checkParsed = false;379    let testFileContent = `const REVISION = "${revision}";\n${readFile(testFile)}`;380381    if (testFileContent.indexOf("FILTER_CRATE") !== -1) {382        testFileContent += "exports.FILTER_CRATE = FILTER_CRATE;";383    } else {384        testFileContent += "exports.FILTER_CRATE = null;";385    }386387    if (hasCheck(testFileContent, "EXPECTED")) {388        testFileContent += "exports.EXPECTED = EXPECTED;";389        checkExpected = true;390    }391    if (hasCheck(testFileContent, "PARSED")) {392        testFileContent += "exports.PARSED = PARSED;";393        checkParsed = true;394    }395    if (!checkParsed && !checkExpected) {396        console.log("FAILED");397        console.log("==> At least `PARSED` or `EXPECTED` is needed!");398        return 1;399    }400401    const loadedFile = loadContent(testFileContent);402    let res = 0;403404    if (checkExpected) {405        res += await runCheck(loadedFile, "EXPECTED", doSearch, (query, expected, text) => {406            return runSearch(query, expected, doSearch, loadedFile, text);407        });408    }409    if (checkParsed) {410        res += await runCheck(loadedFile, "PARSED", doSearch, (query, expected, text) => {411            return runParser(query, expected, parseQuery, text);412        });413    }414    return res;415}416417function mostRecentMatch(staticFiles, regex) {418    const matchingEntries = fs.readdirSync(staticFiles)419        .filter(f => f.match(regex))420        .map(f => {421            const stats = fs.statSync(path.join(staticFiles, f));422            return {423                path: f,424                time: stats.mtimeMs,425            };426        });427    if (matchingEntries.length === 0) {428        throw "No static file matching regex";429    }430    // We sort entries in descending order.431    matchingEntries.sort((a, b) => b.time - a.time);432    return matchingEntries[0].path;433}434435/**436 * Load searchNNN.js and search-indexNNN.js.437 *438 * @param {string} doc_folder      - Path to a folder generated by running rustdoc439 * @param {string} resource_suffix - Version number between filename and .js, e.g. "1.59.0"440 * @returns {Object}               - Object containing keys: `doSearch`, which runs a search441 *   with the loaded index and returns a table of results; `parseQuery`, which is the442 *   `parseQuery` function exported from the search module, which runs443 *   a search but returns type name corrections instead of results.444 */445async function loadSearchJS(doc_folder, resource_suffix) {446    const staticFiles = path.join(doc_folder, "static.files");447    const stringdexJs = mostRecentMatch(staticFiles, /stringdex.*\.js$/);448    const stringdexModule = require(path.join(staticFiles, stringdexJs));449    const searchJs = mostRecentMatch(staticFiles, /search-[0-9a-f]{8}.*\.js$/);450    const searchModule = require(path.join(staticFiles, searchJs));451    globalThis.nonnull = (x, msg) => {452        if (x === null) {453            throw (msg || "unexpected null value!");454        } else {455            return x;456        }457    };458    const { docSearch, DocSearch } = await searchModule.initSearch(459        stringdexModule.Stringdex,460        stringdexModule.RoaringBitmap,461        {462            loadRoot: callbacks => {463                for (const key in callbacks) {464                    if (Object.hasOwn(callbacks, key)) {465                        globalThis[key] = callbacks[key];466                    }467                }468                const rootJs = readFile(path.join(doc_folder, "search.index/root" +469                    resource_suffix + ".js"));470                eval(rootJs);471            },472            loadTreeByHash: hashHex => {473                const shardJs = readFile(path.join(doc_folder, "search.index/" + hashHex + ".js"));474                eval(shardJs);475            },476            loadDataByNameAndHash: (name, hashHex) => {477                const shardJs = readFile(path.join(doc_folder, "search.index/" + name + "/" +478                    hashHex + ".js"));479                eval(shardJs);480            },481        },482    );483    return {484        doSearch: async function(queryStr, filterCrate, currentCrate) {485            const parsedQuery = DocSearch.parseQuery(queryStr);486            const result = await docSearch.execQuery(parsedQuery, filterCrate, currentCrate);487            const resultsTable = {};488            for (const tab in result) {489                if (!Object.prototype.hasOwnProperty.call(result, tab)) {490                    continue;491                }492                if (!isGeneratorObject(result[tab])) {493                    continue;494                }495                resultsTable[tab] = [];496                for await (const entry of result[tab]) {497                    const flatEntry = Object.assign({498                        crate: entry.item.crate,499                        name: entry.item.name,500                        path: entry.item.modulePath,501                        exactPath: entry.item.exactModulePath,502                        ty: entry.item.ty,503                    }, entry);504                    for (const key in entry) {505                        if (!Object.prototype.hasOwnProperty.call(entry, key)) {506                            continue;507                        }508                        if (key === "desc" && entry.desc !== null) {509                            flatEntry.desc = await entry.desc;510                        } else if (key === "displayTypeSignature" &&511                            entry.displayTypeSignature !== null512                        ) {513                            flatEntry.displayTypeSignature = await entry.displayTypeSignature;514                            const {515                                type,516                                mappedNames,517                                whereClause,518                            } = flatEntry.displayTypeSignature;519                            flatEntry.displayType = arrayToCode(type);520                            flatEntry.displayMappedNames = [...mappedNames.entries()]521                                .map(([name, qname]) => {522                                    return `${name} = ${qname}`;523                                }).join(", ");524                            flatEntry.displayWhereClause = [...whereClause.entries()]525                                .flatMap(([name, value]) => {526                                    if (value.length === 0) {527                                        return [];528                                    }529                                    return [`${name}: ${arrayToCode(value)}`];530                                }).join(", ");531                        }532                    }533                    resultsTable[tab].push(flatEntry);534                }535            }536            return { resultsTable, parsedQuery };537        },538        parseQuery: DocSearch.parseQuery,539    };540}541542function showHelp() {543    console.log("rustdoc-js options:");544    console.log("  --doc-folder [PATH]        : location of the generated doc folder");545    console.log("  --help                     : show this message then quit");546    console.log("  --crate-name [STRING]      : crate name to be used");547    console.log("  --test-file [PATHs]        : location of the JS test files (can be called " +548                "multiple times)");549    console.log("  --test-folder [PATH]       : location of the JS tests folder");550    console.log("  --resource-suffix [STRING] : suffix to refer to the correct files");551}552553function parseOptions(args) {554    const opts = {555        "crate_name": "",556        "resource_suffix": "",557        "doc_folder": "",558        "test_folder": "",559        "test_file": [],560        "revision": "",561    };562    const correspondences = {563        "--resource-suffix": "resource_suffix",564        "--doc-folder": "doc_folder",565        "--test-folder": "test_folder",566        "--test-file": "test_file",567        "--crate-name": "crate_name",568        "--revision": "revision",569    };570571    for (let i = 0; i < args.length; ++i) {572        const arg = args[i];573        if (Object.prototype.hasOwnProperty.call(correspondences, arg)) {574            i += 1;575            if (i >= args.length) {576                console.log("Missing argument after `" + arg + "` option.");577                return null;578            }579            const arg_value = args[i];580            if (arg !== "--test-file") {581                opts[correspondences[arg]] = arg_value;582            } else {583                opts[correspondences[arg]].push(arg_value);584            }585        } else if (arg === "--help") {586            showHelp();587            process.exit(0);588        } else {589            console.log("Unknown option `" + arg + "`.");590            console.log("Use `--help` to see the list of options");591            return null;592        }593    }594    if (opts["doc_folder"].length < 1) {595        console.log("Missing `--doc-folder` option.");596    } else if (opts["crate_name"].length < 1) {597        console.log("Missing `--crate-name` option.");598    } else if (opts["test_folder"].length < 1 && opts["test_file"].length < 1) {599        console.log("At least one of `--test-folder` or `--test-file` option is required.");600    } else {601        return opts;602    }603    return null;604}605606async function main(argv) {607    const opts = parseOptions(argv.slice(2));608    if (opts === null) {609        return 1;610    }611612    const parseAndSearch = await loadSearchJS(613        opts["doc_folder"],614        opts["resource_suffix"],615    );616    let errors = 0;617618    const doSearch = function(queryStr, filterCrate) {619        return parseAndSearch.doSearch(queryStr, filterCrate, opts["crate_name"]);620    };621622    if (opts["test_file"].length !== 0) {623        for (const file of opts["test_file"]) {624            process.stdout.write(`Testing ${file} ... `);625            errors += await runChecks(file, doSearch, parseAndSearch.parseQuery, opts.revision);626        }627    } else if (opts["test_folder"].length !== 0) {628        for (const file of fs.readdirSync(opts["test_folder"])) {629            if (!file.endsWith(".js")) {630                continue;631            }632            process.stdout.write(`Testing ${file} ... `);633            errors += await runChecks(path.join(opts["test_folder"], file, ""), doSearch,634                    parseAndSearch.parseQuery);635        }636    }637    return errors > 0 ? 1 : 0;638}639640main(process.argv).catch(e => {641    console.log(e);642    process.exit(1);643}).then(x => process.exit(x));644645process.on("beforeExit", () => {646    console.log("process did not complete");647    process.exit(1);648});

Code quality findings 82

Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
return (index % 2 === 1) ? ("`" + value + "`") : value;
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
m.exports.ignore_order = content.indexOf("\n// ignore-order\n") !== -1 ||
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
m.exports.exact_check = content.indexOf("\n// exact-check\n") !== -1 ||
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
m.exports.should_fail = content.indexOf("\n// should-fail\n") !== -1 ||
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (typeof value === "object" && !Array.isArray(value) && value !== null) {
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
if (typeof value === "object" && !Array.isArray(value) && value !== null) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
return fieldName === "query" || fieldName === "correction" ||
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
fieldName === "proposeCorrectionFrom" ||
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
fieldName === "proposeCorrectionTo";
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (key === "path") {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
} else if (key === "href") {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (value !== expectedValue) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (key === "href") {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (value !== expectedValue) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
return allGood === true;
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (fullPath.length === 0) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (position !== null) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
} else if (expected !== null && typeof expected !== "undefined" &&
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
} else if (expected !== null && typeof expected !== "undefined" &&
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
expected.constructor == Object) { // eslint-disable-line eqeqeq
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (result_v !== null && key === "error") {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (expectedValue !== resultValue) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (error_text.length === 0) {
Ensure all async functions handle errors properly
info correctness async-without-catch
async function runSearch(query, expected, doSearch, loadedFile, queryName) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (exact_check && entry.length !== resultsTable[key].length) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (entry_pos === -1) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
} else if (exact_check === true && prev_pos + 1 !== entry_pos) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
} else if (ignore_order === false && entry_pos < prev_pos) {
Ensure all async functions handle errors properly
info correctness async-without-catch
async function runCorrections(query, corrections, doSearch, loadedFile) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (corrections === null) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (qc !== null) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (qc.toLowerCase() !== corrections.toLowerCase()) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (error_text.length === 0 && loadedFile.should_fail === true) {
Remove debugging statements or use a logging library
info correctness console-log
console.log("FAILED");
Remove debugging statements or use a logging library
info correctness console-log
console.log("==> Test was supposed to fail but all items were found...");
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
} else if (error_text.length !== 0 && loadedFile.should_fail === false) {
Remove debugging statements or use a logging library
info correctness console-log
console.log("FAILED");
Remove debugging statements or use a logging library
info correctness console-log
console.log(error_text.join("\n"));
Remove debugging statements or use a logging library
info correctness console-log
console.log("OK");
Ensure all async functions handle errors properly
info correctness async-without-catch
async function runCheckInner(callback, loadedFile, entry, extra, doSearch) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (typeof entry.query !== "string") {
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
if (typeof entry.query !== "string") {
Remove debugging statements or use a logging library
info correctness console-log
console.log("FAILED");
Remove debugging statements or use a logging library
info correctness console-log
console.log("==> Missing `query` field");
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (checkResult(error_text, loadedFile, false) !== 0) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (entry.correction !== undefined) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (checkResult(error_text, loadedFile, false) !== 0) {
Remove debugging statements or use a logging library
info correctness console-log
console.log("OK");
Ensure all async functions handle errors properly
info correctness async-without-catch
async function runChecks(testFile, doSearch, parseQuery, revision) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (testFileContent.indexOf("FILTER_CRATE") !== -1) {
Remove debugging statements or use a logging library
info correctness console-log
console.log("FAILED");
Remove debugging statements or use a logging library
info correctness console-log
console.log("==> At least `PARSED` or `EXPECTED` is needed!");
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (matchingEntries.length === 0) {
Ensure all async functions handle errors properly
info correctness async-without-catch
async function loadSearchJS(doc_folder, resource_suffix) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (x === null) {
Ensure all async functions handle errors properly
info correctness async-without-catch
doSearch: async function(queryStr, filterCrate, currentCrate) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (key === "desc" && entry.desc !== null) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
} else if (key === "displayTypeSignature" &&
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
entry.displayTypeSignature !== null
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (value.length === 0) {
Remove debugging statements or use a logging library
info correctness console-log
console.log("rustdoc-js options:");
Remove debugging statements or use a logging library
info correctness console-log
console.log(" --doc-folder [PATH] : location of the generated doc folder");
Remove debugging statements or use a logging library
info correctness console-log
console.log(" --help : show this message then quit");
Remove debugging statements or use a logging library
info correctness console-log
console.log(" --crate-name [STRING] : crate name to be used");
Remove debugging statements or use a logging library
info correctness console-log
console.log(" --test-file [PATHs] : location of the JS test files (can be called " +
Remove debugging statements or use a logging library
info correctness console-log
console.log(" --test-folder [PATH] : location of the JS tests folder");
Remove debugging statements or use a logging library
info correctness console-log
console.log(" --resource-suffix [STRING] : suffix to refer to the correct files");
Remove debugging statements or use a logging library
info correctness console-log
console.log("Missing argument after `" + arg + "` option.");
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (arg !== "--test-file") {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
} else if (arg === "--help") {
Remove debugging statements or use a logging library
info correctness console-log
console.log("Unknown option `" + arg + "`.");
Remove debugging statements or use a logging library
info correctness console-log
console.log("Use `--help` to see the list of options");
Remove debugging statements or use a logging library
info correctness console-log
console.log("Missing `--doc-folder` option.");
Remove debugging statements or use a logging library
info correctness console-log
console.log("Missing `--crate-name` option.");
Remove debugging statements or use a logging library
info correctness console-log
console.log("At least one of `--test-folder` or `--test-file` option is required.");
Ensure all async functions handle errors properly
info correctness async-without-catch
async function main(argv) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (opts === null) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (opts["test_file"].length !== 0) {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
} else if (opts["test_folder"].length !== 0) {
Remove debugging statements or use a logging library
info correctness console-log
console.log(e);
Chain Promises properly to avoid callback hell
info correctness unresolved-promise
}).then(x => process.exit(x));
Remove debugging statements or use a logging library
info correctness console-log
console.log("process did not complete");

Security findings 3

Avoid due to security risks; use safer alternatives like JSON.parse or function constructors
security eval-usage
eval(rootJs);
Avoid due to security risks; use safer alternatives like JSON.parse or function constructors
security eval-usage
eval(shardJs);
Avoid due to security risks; use safer alternatives like JSON.parse or function constructors
security eval-usage
eval(shardJs);

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.