'use strict'; var flatten = require('lodash').flatten; var promisify = require('util.promisify'); var nodeFs = require('fs'); var MarkdownIt = require('markdown-it'); var promiseRipple = require('./promise-ripple'); var resolveParse = require('./eslint-parse'); var createLogger = require('./log'); var _a = require('./md-nodes'), previousIndex = _a.previousIndex, previousIndexType = _a.previousIndexType, previousIndexClose = _a.previousIndexClose, groupChildren = _a.groupChildren, searchLink = _a.searchLink, searchComment = _a.searchComment, createLineDoc = _a.createLineDoc, replaceLines = _a.replaceLines, getHash = _a.getHash, mapNodes = _a.mapNodes, getNodeId = _a.getNodeId, getFences = _a.getFences, filterPrevented = _a.filterPrevented, buildPreserveLines = _a.buildPreserveLines, buildConcat = _a.buildConcat; var _b = require('./eval-errors'), stackSplit = _b.stackSplit, stackJoin = _b.stackJoin, findErrorNode = _b.findErrorNode, acornError = _b.acornError, parseLineChar = _b.parseLineChar, getCleanLines = _b.getCleanLines; var _c = require('./shell-eval'), KIND_LANGS = _c.KIND_LANGS, normalizeKinds = _c.normalizeKinds, parsePromptBlock = _c.parsePromptBlock; var _d = require('./module-rewrite'), replacePosition = _d.replacePosition, regExpEscape = _d.regExpEscape, getDeps = _d.getDeps, alterAssignedModule = _d.alterAssignedModule, alterSelfModules = _d.alterSelfModules, alterPrependModules = _d.alterPrependModules, alterNpmModules = _d.alterNpmModules, alterModules = _d.alterModules, buildEvalable = _d.buildEvalable; var _e = require('./eval-run'), evalError = _e.evalError, evalFileAsync = _e.evalFileAsync, getCleanErr = _e.getCleanErr, nonstopErr = _e.nonstopErr, evaluate = _e.evaluate, evaluateScope = _e.evaluateScope, outputCode = _e.outputCode, outputScope = _e.outputScope, evaluateShell = _e.evaluateShell, evaluateAllKinds = _e.evaluateAllKinds; var fs = { readFileAsync: promisify(nodeFs.readFile), }; /** @import { AssembleData, Logger, Package } from './types' */ /** @param {readonly AssembleData[]} mdResults */ function getExitCode(mdResults) { var evaluations = flatten(mdResults.map(function (mdResult) { return mdResult.evaluated || []; })); var evalResults = flatten(evaluations.map(function (evaluation) { return evaluation.evalResult; })); var evalResultsInstanceofError = evalResults.map(function (evalResult) { return evalResult instanceof Error; }); var evalResultsHasInstanceofError = evalResultsInstanceofError.indexOf(true) !== -1; if (evalResultsHasInstanceofError) { return 1; } return 0; } /** @param {string} [packagePath] */ function getPackage(packagePath) { packagePath = (packagePath) ? packagePath : './package.json'; return fs.readFileAsync(packagePath, 'utf8') .then(JSON.parse) .then(function (pkg) { pkg.path = packagePath; return pkg; }) .catch(function () { return false; }); } /** * @param {string} filePath * @param {Package | false} pkg * @param {string} prepend * @param {boolean} blockScope * @param {boolean} nonstop * @param {boolean} preventEval * @param {boolean} includePrevented * @param {string | boolean} output * @param {string | boolean} delimeter * @param {readonly string[]} evalLangs * @param {boolean} useEslint * @param {Logger} logger * @param {boolean} sloppy * @returns {Promise} */ function assemble(filePath, pkg, prepend, blockScope, nonstop, preventEval, includePrevented, output, delimeter, evalLangs, useEslint, logger, sloppy) { // get the markdown file contents /** @type {AssembleData} */ var initial = {}; return promiseRipple(initial, { markdown: function () { return fs.readFileAsync(filePath, 'utf8'); }, /** @param {AssembleData} data */ processNodes: function (data) { // create new md instance var md = new MarkdownIt(); // split the markdown file by lines data.markdownLines = String(data.markdown || '').split(/\r\n?|\n/); // get all the nodes data.nodes = md.parse(String(data.markdown || ''), {}); // map all the nodes data.nodes = mapNodes(data.nodes); // get all js / javascript fenced blocks data.allFences = getFences(data.nodes, ['js', 'javascript']); // get all hashes data.allJsFences = getNodeId(data.allFences); // get all permitted blocks data.permittedFences = filterPrevented(data.allJsFences); // eval nodes data.kinds = normalizeKinds(evalLangs); var evalJs = data.kinds.indexOf('js') !== -1; data.evalNodes = (evalJs) ? ((includePrevented) ? data.allJsFences : data.permittedFences) : []; data.kindFences = {}; var kindFences = data.kindFences; var kindNodes = data.nodes || []; data.kinds.forEach(function (kind) { if (kind === 'js') { return; } kindFences[kind] = getNodeId(getFences(kindNodes, KIND_LANGS[kind] || [kind])); }); // get the blockscope data.blockScope = blockScope || Boolean(data.evalNodes.map(function (node) { return node.fileEval; }).filter(function (fileEval) { return fileEval !== false; }).length); return data; }, /** @param {AssembleData} data */ resolvedParsers: function (data) { if (!useEslint) { return false; } return Promise.all((data.evalNodes || []).map(function (node) { return resolveParse(filePath, String(node.id), process.cwd()).then(function (parse) { node.parse = parse; return node.id; }); })); }, /** @param {AssembleData} data */ evaluated: function (data) { if (preventEval) { logger.info('eval prevented'); return false; } return evaluateAllKinds(data, pkg, prepend, nonstop, filePath, logger, sloppy); }, /** @param {AssembleData} data */ outputed: function (data) { if (!output) { return false; } if (!data.evalNodes || !data.markdownLines) { return false; } return outputScope(data.evalNodes, data.markdownLines.length, pkg, prepend, nonstop, filePath, Boolean(data.blockScope), output, delimeter, logger, sloppy); }, }); } /** * :fishing_pole_and_fish: Evaluates javascript code blocks from markdown files. * @module evalmd * @package.keywords eval, evaulate, javascript, markdown, test * @package.preferGlobal * @package.bin.evalmd ./bin/eval-markdown.js * @package.bin.test-markdown ./bin/eval-markdown.js * @package.bin.eval-markdown ./bin/eval-markdown.js * @param {string | readonly string[]} filePath$ * @param {string} packagePath * @param {string} prepend * @param {boolean} blockScope * @param {boolean} nonstop * @param {boolean} preventEval * @param {boolean} includePrevented * @param {boolean} silence * @param {boolean} debug * @param {string | boolean} output * @param {string | boolean} delimeter * @param {readonly string[]} evalLangs * @param {boolean} sloppy * @param {boolean} useEslint */ function main(filePath$, packagePath, prepend, blockScope, nonstop, preventEval, includePrevented, silence, debug, output, delimeter, evalLangs, sloppy, useEslint) { evalLangs = (evalLangs && evalLangs.length) ? evalLangs : ['js']; var logger = createLogger({ debug: debug, silence: silence }); var filePaths = flatten([filePath$]); logger.info('it worked if it ends with', 'ok'); return getPackage(packagePath) .then(function (pkg) { return Promise.all(filePaths.map(function (filePath) { return assemble(filePath, pkg, prepend, blockScope, nonstop, preventEval, includePrevented, output, delimeter, evalLangs, useEslint, logger, sloppy); })); }) .then(function (mdResults) { // console.log(mdResults) var exitCode = getExitCode(mdResults); if (exitCode === 0) { logger.info('ok'); } logger.debug('exit code', exitCode); return { dataSets: mdResults, exitCode: exitCode, log: logger.store, }; }) .catch(function (error) { logger.err(error); var exitCode = 1; logger.debug('exit code', exitCode); return { dataSets: null, exitCode: 1, log: null, }; }); } module.exports = main; module.exports.getExitCode = getExitCode; module.exports.getPackage = getPackage; module.exports.previousIndex = previousIndex; module.exports.previousIndexType = previousIndexType; module.exports.previousIndexClose = previousIndexClose; module.exports.groupChildren = groupChildren; module.exports.searchLink = searchLink; module.exports.searchComment = searchComment; module.exports.createLineDoc = createLineDoc; module.exports.replaceLines = replaceLines; module.exports.getHash = getHash; module.exports.mapNodes = mapNodes; module.exports.getNodeId = getNodeId; module.exports.getFences = getFences; module.exports.filterPrevented = filterPrevented; module.exports.buildPreserveLines = buildPreserveLines; module.exports.buildConcat = buildConcat; module.exports.getDeps = getDeps; module.exports.parsePromptBlock = parsePromptBlock; module.exports.evaluateShell = evaluateShell; module.exports.replacePosition = replacePosition; module.exports.regExpEscape = regExpEscape; module.exports.alterAssignedModule = alterAssignedModule; module.exports.alterSelfModules = alterSelfModules; module.exports.alterPrependModules = alterPrependModules; module.exports.alterNpmModules = alterNpmModules; module.exports.alterModules = alterModules; module.exports.buildEvalable = buildEvalable; module.exports.stackSplit = stackSplit; module.exports.stackJoin = stackJoin; module.exports.findErrorNode = findErrorNode; module.exports.acornError = acornError; module.exports.parseLineChar = parseLineChar; module.exports.getCleanLines = getCleanLines; module.exports.evalError = evalError; module.exports.evalFileAsync = evalFileAsync; module.exports.getCleanErr = getCleanErr; module.exports.nonstopErr = nonstopErr; module.exports.evaluate = evaluate; module.exports.evaluateScope = evaluateScope; module.exports.outputCode = outputCode; module.exports.outputScope = outputScope; module.exports.assemble = assemble;