'use strict'; var path = require('path'); var acorn = require('acorn'); var isCore = require('is-core-module'); var umd = require("./acorn-umd/acorn-umd.js").default; var _a = require('./md-nodes'), buildPreserveLines = _a.buildPreserveLines, buildConcat = _a.buildConcat; /** @import { Dep, EvalBuild, MdNode, Package, ParseOptions } from './types' */ /** * @param {string} str * @param {number} start * @param {number} end * @param {string} value */ function replacePosition(str, start, end, value) { return str.substr(0, start) + value + str.substr(end); } /** @param {string} replacement */ function toRequirePath(replacement) { return replacement.split(path.sep).join('/'); } /** @param {string} s */ function regExpEscape(s) { return s.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'); } /** * @param {string} code * @param {ParseOptions} [parseOpts] * @returns {readonly Dep[]} */ function getDeps(code, parseOpts) { var opts = parseOpts || {}; var ast = opts.parse ? opts.parse(code) : acorn.parse(code, { sourceType: opts.sloppy ? 'script' : 'module', ecmaVersion: 6 }); var deps = umd(ast, { es6: true, amd: true, cjs: true, }); return Array.from(new Set(deps)).map(function (dep) { var source = dep.source; return { source: { value: String(source && 'value' in source ? source.value : ''), start: source ? source.start : 0, end: source ? source.end : 0, }, }; }); } /** * @param {string} code * @param {string} _prepend * @param {Package | false} pkg * @param {ParseOptions} [parseOpts] */ function alterAssignedModule(code, _prepend, pkg, parseOpts) { if (!pkg) { return code; } var deps = getDeps(code, parseOpts); if (!deps.length) { return code; } var name = pkg.name; var chars = 0; name = regExpEscape(name); var pattern = new RegExp("^".concat(name, "($|/.*)")); deps.forEach(function (dep) { var match = dep.source.value.match(pattern); if (match) { var start = chars + dep.source.start + 1; var end = chars + dep.source.end - 1; var absModule = path.dirname(path.resolve(pkg.path)); var replacement = toRequirePath(match[1] ? path.join(absModule, match[1]) : absModule); code = replacePosition(code, start, end, replacement); chars += replacement.length - dep.source.value.length; } }); return code; } /** * @param {string} code * @param {readonly MdNode[]} nodes * @param {ParseOptions} [parseOpts] */ function alterSelfModules(code, nodes, parseOpts) { var deps = getDeps(code, parseOpts); if (!deps.length) { return code; } var chars = 0; deps.forEach(function (dep) { if (dep.source.value) { var node = nodes.find(function (node) { return node.fileEval === dep.source.value; }); if (node && node.fileCreated) { var start = chars + dep.source.start + 1; var end = chars + dep.source.end - 1; var replacement = toRequirePath(node.fileEvalHashPath); code = replacePosition(code, start, end, replacement); chars += replacement.length - dep.source.value.length; } } }); return code; } /** * @param {string} code * @param {readonly MdNode[]} nodes * @param {string} prepend * @param {ParseOptions} [parseOpts] */ function alterPrependModules(code, nodes, prepend, parseOpts) { var deps = getDeps(code, parseOpts); if (!deps.length) { return code; } prepend = (prepend) ? prepend : './'; var localRegex = /^.\.\/|^.\//; var chars = 0; deps.forEach(function (dep) { if (dep.source.value && dep.source.value.match(localRegex)) { var node = nodes.find(function (node) { return node.fileEval === dep.source.value; }); if (!node) { var start = chars + dep.source.start + 1; var end = chars + dep.source.end - 1; var replacement = toRequirePath(path.resolve(path.join(prepend, dep.source.value))); code = replacePosition(code, start, end, replacement); chars += replacement.length - dep.source.value.length; } } }); return code; } /** * @param {string} code * @param {readonly MdNode[]} _nodes * @param {string} prepend * @param {ParseOptions} [parseOpts] */ function alterNpmModules(code, _nodes, prepend, parseOpts) { var deps = getDeps(code, parseOpts); if (!deps.length) { return code; } prepend = (prepend) ? prepend : './'; var nonNpm = /^.\.\/|^.\/|^\//; var chars = 0; deps.forEach(function (dep) { if (dep.source.value && !dep.source.value.match(nonNpm) && !isCore(dep.source.value) && !path.isAbsolute(dep.source.value)) { var start = chars + dep.source.start + 1; var end = chars + dep.source.end - 1; var replacement = toRequirePath(path.resolve(path.join(prepend, 'node_modules', dep.source.value))); code = replacePosition(code, start, end, replacement); chars += replacement.length - dep.source.value.length; } }); return code; } /** * @param {string} code * @param {readonly MdNode[]} nodes * @param {Package | false} pkg * @param {string} prepend * @param {ParseOptions} [parseOpts] */ function alterModules(code, nodes, pkg, prepend, parseOpts) { /* * syntax errors will come through to here and * get thrown by the acorn parser */ code = alterAssignedModule(code, prepend, pkg, parseOpts); code = alterSelfModules(code, nodes, parseOpts); code = alterPrependModules(code, nodes, prepend, parseOpts); code = alterNpmModules(code, nodes, prepend, parseOpts); return code; } /** * @param {MdNode | readonly MdNode[]} node * @param {readonly MdNode[]} nodes * @param {number} markdownLinesLength * @param {Package | false} pkg * @param {string} prepend * @param {ParseOptions} [parseOpts] * @returns {EvalBuild} */ function buildEvalable(node, nodes, markdownLinesLength, pkg, prepend, parseOpts) { var preserve = buildPreserveLines(node, markdownLinesLength); var concat = buildConcat(node); // if there is an error have preserve run first to return line number var preserveAlter = alterModules(preserve, nodes, pkg, prepend, parseOpts); var concatAlter = alterModules(concat, nodes, pkg, prepend, parseOpts); return { preserve: preserve, concat: concat, preserveAlter: preserveAlter, concatAlter: concatAlter, }; } module.exports = { replacePosition: replacePosition, toRequirePath: toRequirePath, regExpEscape: regExpEscape, getDeps: getDeps, alterAssignedModule: alterAssignedModule, alterSelfModules: alterSelfModules, alterPrependModules: alterPrependModules, alterNpmModules: alterNpmModules, alterModules: alterModules, buildEvalable: buildEvalable, };