UNPKG

markdown-doctest

Version:
158 lines (157 loc) 6.43 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.printResults = exports.runTests = void 0; var fs_1 = require("fs"); var vm_1 = require("vm"); var core_1 = require("@babel/core"); var preset_env_1 = require("@babel/preset-env"); var chalk_1 = require("chalk"); function flatten(arr) { return Array.prototype.concat.apply([], arr); } var parse_code_snippets_from_markdown_1 = require("./parse-code-snippets-from-markdown"); function runTests(files, config) { var results = files .map(read) .map(parse_code_snippets_from_markdown_1.default) .map(testFile(config)); return flatten(results); } exports.runTests = runTests; function read(fileName) { return { contents: fs_1.readFileSync(fileName, "utf8"), fileName: fileName }; } function makeTestSandbox(config) { function sandboxRequire(moduleName) { for (var regexRequire in config.regexRequire) { var regex = new RegExp(regexRequire); var match = regex.exec(moduleName); var handler = config.regexRequire[regexRequire]; if (match) { return handler.apply(void 0, match); } } if (config.require[moduleName] === undefined) { throw moduleNotFoundError(moduleName); } return config.require[moduleName]; } var sandboxConsole = { log: function () { return null; }, }; var sandboxGlobals = { require: sandboxRequire, console: sandboxConsole }; var sandbox = Object.assign({}, sandboxGlobals, config.globals); return sandbox; } function testFile(config) { return function testFileWithConfig(args) { var codeSnippets = args.codeSnippets; var fileName = args.fileName; var shareCodeInFile = args.shareCodeInFile; var results; if (shareCodeInFile) { var sandbox = makeTestSandbox(config); results = codeSnippets.map(test(config, fileName, sandbox)); } else { results = codeSnippets.map(test(config, fileName)); } return results; }; } function test(config, filename, sandbox) { return function (codeSnippet) { if (codeSnippet.skip) { return { status: "skip", codeSnippet: codeSnippet, stack: "" }; } var success = false; var stack = ""; var code = codeSnippet.code; if (config.transformCode) { try { code = config.transformCode(code); } catch (e) { return { status: "fail", codeSnippet: codeSnippet, stack: "Encountered an error while transforming snippet: \n" + e.stack }; } } var perSnippetSandbox; if (sandbox === undefined) { perSnippetSandbox = makeTestSandbox(config); } if (config.beforeEach) { config.beforeEach(); } var options = { presets: [preset_env_1.default], }; try { if (config.babel !== false) { code = core_1.transformSync(code, options).code; } vm_1.runInNewContext(code, perSnippetSandbox || sandbox); success = true; } catch (e) { stack = e.stack || ""; } var status = success ? "pass" : "fail"; process.stdout.write(success ? chalk_1.default.green(".") : chalk_1.default.red("x")); return { status: status, codeSnippet: codeSnippet, stack: stack }; }; } function printResults(results) { results.filter(function (result) { return result.status === "fail"; }).forEach(printFailure); var passingCount = results.filter(function (result) { return result.status === "pass"; }) .length; var failingCount = results.filter(function (result) { return result.status === "fail"; }) .length; var skippingCount = results.filter(function (result) { return result.status === "skip"; }) .length; function successfulRun() { return failingCount === 0; } console.log(chalk_1.default.green("Passed: " + passingCount)); if (skippingCount > 0) { console.log(chalk_1.default.yellow("Skipped: " + skippingCount)); } if (successfulRun()) { console.log(chalk_1.default.green("\nSuccess!")); } else { console.log(chalk_1.default.red("Failed: " + failingCount)); } } exports.printResults = printResults; function printFailure(result) { console.log(chalk_1.default.red("Failed - " + markDownErrorLocation(result))); var stackDetails = relevantStackDetails(result.stack); console.log(stackDetails); var variableNotDefined = stackDetails.match(/(\w+) is not defined/); if (variableNotDefined) { var variableName = variableNotDefined[1]; console.log("You can declare " + chalk_1.default.blue(variableName) + " in the " + chalk_1.default.blue("globals") + " section in " + chalk_1.default.grey(".markdown-doctest-setup.js")); console.log("\nFor example:\n" + chalk_1.default.grey("// .markdown-doctest-setup.js") + "\nmodule.exports = {\n globals: {\n " + chalk_1.default.blue(variableName) + ": ...\n }\n}\n "); } } function relevantStackDetails(stack) { var match = stack.match(/([\w\W]*?)at eval/) || stack.match(/([\w\W]*)at [\w*\/]*?doctest.js/); if (match !== null) { return match[1]; } return stack; } function moduleNotFoundError(moduleName) { return new Error("\nAttempted to require '" + chalk_1.default.blue(moduleName) + "' but was not found in config.\nYou need to include it in the require section of your " + chalk_1.default.grey(".markdown-doctest-setup.js") + " file.\n\nFor example:\n" + chalk_1.default.grey("// .markdown-doctest-setup.js") + "\nmodule.exports = {\n require: {\n " + chalk_1.default.blue("'" + moduleName + "': require('" + moduleName + "')") + "\n }\n}\n "); } function markDownErrorLocation(result) { var match = result.stack.match(/eval.*<.*>:(\d+):(\d+)/); if (match) { var mdLineNumber = parseInt(match[1], 10); var columnNumber = parseInt(match[2], 10); var lineNumber = result.codeSnippet.lineNumber + mdLineNumber; return result.codeSnippet.fileName + ":" + lineNumber + ":" + columnNumber; } return result.codeSnippet.fileName + ":" + result.codeSnippet.lineNumber; }