UNPKG

template-tango

Version:

Tool for merging HTML templates between front and back end, making use of Beyond Compare folder comparison.

399 lines (398 loc) 18.3 kB
"use strict"; var fs = require("fs-extra"); var chalk = require("chalk"); var globby = require("globby"); var _ = require("lodash"); var replaceExt = require('replace-ext'); var Bombom = require("../deps/bombom/dist/BomBom.js"); var es6_promise_1 = require("es6-promise"); var child_process_1 = require('child_process'); var NS = "TemplateTango"; var bcLaunchedAtLeastOnce = false; var bombom = new Bombom.default(), suppressWarnings = false; // checks a value, logs a warning and returns if successful function checkVal(val, msg) { if (val === null || val === undefined) { if (!suppressWarnings) console.warn(chalk.cyan(NS + " - checkVal"), chalk.red(msg), chalk.red("Returning early.")); return false; } return true; } // replaces back slashes with forward slashes function normalizePaths(filePath) { return filePath.split("\\").join("/"); } // gets the current working directory function getCWD() { return normalizePaths(process.cwd() + "/"); } // Ensures the path given ends in a "/" character. function ensureTrainlingSlash(path) { if (path.substr(path.length - 1) !== "/") path += "/"; return path; } // add bang to exclusions function bangUpExclusions(exclusions, rootDir) { exclusions = exclusions.map(function (filePath) { return "!" + rootDir + filePath.replace("!", ""); }); return exclusions; } function prepareCopyOpts(opts) { // makes sure all paths use forward slashes opts.rootDir = normalizePaths(opts.rootDir); // makes sure paths all have trailing slashes if (opts.pagesDir) opts.pagesDir = ensureTrainlingSlash(opts.pagesDir); if (opts.modulesDir) opts.modulesDir = ensureTrainlingSlash(opts.modulesDir); return opts; } // creates page or module paths (minus exclusions) function getOptsFullPaths(opts, type, log) { //if(log) console.log(opts.rootDir + (type === "page" ? opts.pagesDir : opts.modulesDir) + "**/*" + opts.extension) if (log === void 0) { log = false; } if (!opts.pageExclusions) opts.pageExclusions = []; if (!opts.moduleExclusions) opts.moduleExclusions = []; // add bang to exclusions opts.pageExclusions = bangUpExclusions(opts.pageExclusions, opts.rootDir); opts.moduleExclusions = bangUpExclusions(opts.moduleExclusions, opts.rootDir); var query = [ opts.rootDir + (type === "page" ? opts.pagesDir : opts.modulesDir) + "**/*" + opts.extension ]; if (type === "page" && opts.pageExclusions) query = query.concat(opts.pageExclusions); else if (type === "module" && opts.moduleExclusions) query = query.concat(opts.moduleExclusions); return globby.sync(query); } /** * @description Copies a file to a new destination, changing the extension and folder structure and adding original file paths to either a success or error array * @param originalFilePath - File to copy from. * @param originalMainDir - Part of the file path to swap out with 'newMainDir'. * @param newMainDir - New directory path to replace 'originalMainDir'. * @param ext - New extention for the copied file. * @param originalSubDir - Sub-directory from original target template. * @param newSubDir - Sub-directory for target template. * @param cb - Callback on complete, passing boolean for success/fail. * @param sucList (optional) - Array of successful file paths (uses originalFilePath). * @param errList (optional) - Array of failed file paths (uses originalFilePath). * @param nameMap (optional) - Maps page and module names that differ between front and back end * @param justFile (optional) - Pass true if you just want the file copied without any folder hierarchy */ function copyToNewFolderStructure(originalFilePath, originalMainDir, newMainDir, ext, originalSubDir, newSubDir, cb, sucList, errList, nameMap, justFile) { if (sucList === void 0) { sucList = null; } if (errList === void 0) { errList = null; } if (nameMap === void 0) { nameMap = null; } if (justFile === void 0) { justFile = false; } // fail it if original file doesn't exist if (!fs.existsSync(originalFilePath)) { if (errList) errList.push(originalFilePath); cb(false); return; } if (originalSubDir) originalSubDir = ensureTrainlingSlash(originalSubDir); if (newSubDir) newSubDir = ensureTrainlingSlash(newSubDir); fs.readFile(originalFilePath, function (err, buf) { // we add a BOM to each file to avoid differences with Visual Studio created files buf = bombom.enforce(buf, "utf8"); var fileName = replaceExt(originalFilePath .replace(originalMainDir, "") // removes original main directory so it can be replaced with new one , ext); fileName = normalizePaths(fileName); // if(nameMap) console.log("--", nameMap.from + ext, fileName) if (nameMap && nameMap.from + ext === fileName) { fileName = nameMap.to + ext; if (!suppressWarnings) console.log(chalk.cyan(NS + " - copyToNewFolderStructure"), chalk.red("'nameMap' used"), nameMap); } // The destination filePath removes the original directory (eg back end) and extension, because they've been replaced (eg. to match the front end ones), which makes them easily comparable var dest = newMainDir + fileName; dest = normalizePaths(dest); // needs to be called before replacing subDir in path because of slash inconsistency on Windows if (originalSubDir) dest = dest.replace("/" + originalSubDir, "/"); // removes original subdirectory so it can be replaced with new one // adds new subdirectory, but if nameMap is used, this subdirectory will already exist, so gets skipped fileName = getFileName(dest); if (dest.indexOf(newSubDir + fileName) === -1) dest = dest.replace(fileName, newSubDir + fileName); if (justFile) { dest = newMainDir + fileName; console.log("dest", dest); } fs.outputFile(dest, buf, function (err) { if (err) { if (errList) errList.push(err.message); cb(false); } else { if (sucList) sucList.push(originalFilePath); cb(true); } }); }); } function copyBackToFront(cloneDest, beOpts, // will write using front end values feExt, feSubDir, fePagesDir, feModulesDir, nameMapGroup) { if (feExt === void 0) { feExt = ".vash"; } if (feSubDir === void 0) { feSubDir = "tmpl/"; } if (fePagesDir === void 0) { fePagesDir = "Pages/"; } if (feModulesDir === void 0) { feModulesDir = "Widgets/"; } if (nameMapGroup === void 0) { nameMapGroup = null; } var noPages = !fePagesDir || !beOpts.pagesDir; var noModules = !feModulesDir || !beOpts.modulesDir; beOpts = prepareCopyOpts(beOpts); var bePages; if (!noPages) { fs.ensureDirSync(cloneDest + fePagesDir); bePages = getOptsFullPaths(beOpts, "page"); fePagesDir = ensureTrainlingSlash(fePagesDir); } var beModules; if (!noModules) { feModulesDir = ensureTrainlingSlash(feModulesDir); fs.ensureDirSync(cloneDest + feModulesDir); beModules = getOptsFullPaths(beOpts, "module"); } return new es6_promise_1.Promise(function (resolve, reject) { var count = 0, total = (noPages ? 0 : bePages.length) + (noModules ? 0 : beModules.length), errList = [], sucList = []; // when all files are copied, resolve the promise var checkCount = function () { count++; if (count >= total) { var result = { sucList: sucList, errList: errList }; if (beOpts.completeCB) beOpts.completeCB(result); resolve(result); } }; if (!noPages) { if (!bePages.length) { if (!suppressWarnings) console.warn(NS, "copyBackToFront", "No back end 'pages' found. Check that 'extension', 'pagesDir' and 'rootDir' resolve to files that exist."); checkCount(); } else { bePages.forEach(function (filePath) { var pagesDir = fePagesDir; var originalMainDir = beOpts.rootDir + beOpts.pagesDir; var nameMap = getNameMap(filePath, nameMapGroup, originalMainDir, true, true); var justFile = pagesDir === "/"; // normalizes trailing double slash from `fePagesDir` when there is no parent folder var noParentFolder = beOpts.pagesDir === "/"; if (noParentFolder) { originalMainDir = originalMainDir.replace("//", "/"); pagesDir += getFileName(filePath, false) + "/"; // generates the folder from the file name } copyToNewFolderStructure(filePath, originalMainDir, cloneDest + pagesDir, feExt, beOpts.subDir, feSubDir, checkCount, sucList, errList, nameMap, justFile); }); } } if (!noModules) { if (!beModules.length) { if (!suppressWarnings) console.warn(NS, "copyBackToFront", "No back end 'modules' found. Check that 'extension', 'modulesDir' and 'rootDir' resolve to files that exist."); checkCount(); } else { beModules.forEach(function (filePath) { var modulesDir = feModulesDir; var originalMainDir = beOpts.rootDir + beOpts.modulesDir; var nameMap = getNameMap(filePath, nameMapGroup, originalMainDir, true, false); var justFile = modulesDir === "/"; // normalizes trailing double slash from `feModulesDir` when there is no parent folder var noParentFolder = beOpts.modulesDir === "/"; if (noParentFolder) { originalMainDir = originalMainDir.replace("//", "/"); modulesDir += getFileName(filePath, false) + "/"; // generates the folder from the file name } copyToNewFolderStructure(filePath, originalMainDir, cloneDest + modulesDir, feExt, beOpts.subDir, feSubDir, checkCount, sucList, errList, nameMap, justFile); }); } } }); } function copyFrontToBack(cloneDest, feOpts, // will write using front end values beExt, beSubDir, bePagesDir, beModulesDir, nameMapGroup) { if (beExt === void 0) { beExt = ".vash"; } if (beSubDir === void 0) { beSubDir = ""; } if (bePagesDir === void 0) { bePagesDir = "Views/"; } if (beModulesDir === void 0) { beModulesDir = "Components/"; } if (nameMapGroup === void 0) { nameMapGroup = null; } var noPages = !bePagesDir || !feOpts.pagesDir; var noModules = !beModulesDir || !feOpts.modulesDir; feOpts = prepareCopyOpts(feOpts); var fePages; if (!noPages) { bePagesDir = ensureTrainlingSlash(bePagesDir); fs.ensureDirSync(cloneDest + bePagesDir); fePages = getOptsFullPaths(feOpts, "page"); } var feModules; if (!noModules) { beModulesDir = ensureTrainlingSlash(beModulesDir); fs.ensureDirSync(cloneDest + beModulesDir); feModules = getOptsFullPaths(feOpts, "module"); } return new es6_promise_1.Promise(function (resolve, reject) { var count = 0, total = (noPages ? 0 : fePages.length) + (noModules ? 0 : feModules.length), errList = [], sucList = []; // when all files are copied, resolve the promise var checkCount = function () { count++; if (count >= total) { var result = { sucList: sucList, errList: errList }; if (feOpts.completeCB) feOpts.completeCB(result); resolve(result); } }; if (!noPages) { if (!fePages.length) { if (!suppressWarnings) console.warn(NS, "copyFrontToBack", "No front end 'pages' found. Check that 'extension', 'pagesDir' and 'rootDir' resolve to files that exist."); checkCount(); } else { fePages.forEach(function (filePath) { var pagesDir = bePagesDir; var originalMainDir = feOpts.rootDir + feOpts.pagesDir; var nameMap = getNameMap(filePath, nameMapGroup, originalMainDir, false, true); var justFile = pagesDir === "/"; // normalizes trailing double slash from `bePagesDir` when there is no parent folder var noParentFolder = feOpts.pagesDir === "/"; if (noParentFolder) { originalMainDir = originalMainDir.replace("//", "/"); pagesDir += getFileName(filePath, false) + "/"; // generates the folder from the file name } copyToNewFolderStructure(filePath, originalMainDir, cloneDest + pagesDir, beExt, feOpts.subDir, beSubDir, checkCount, sucList, errList, nameMap, justFile); }); } } if (!noModules) { if (!feModules.length) { if (!suppressWarnings) console.warn(NS, "copyFrontToBack", "No front end 'modules' found. Check that 'extension', 'modulesDir' and 'rootDir' resolve to files that exist."); checkCount(); } else { feModules.forEach(function (filePath) { var modulesDir = beModulesDir; var originalMainDir = feOpts.rootDir + feOpts.modulesDir; var nameMap = getNameMap(filePath, nameMapGroup, originalMainDir, false, false); var justFile = modulesDir === "/"; // normalizes trailing double slash from `beModulesDir` when there is no parent folder var noParentFolder = feOpts.modulesDir === "/"; if (noParentFolder) { originalMainDir = originalMainDir.replace("//", "/"); modulesDir += getFileName(filePath, false) + "/"; // generates the folder from the file name } copyToNewFolderStructure(filePath, originalMainDir, cloneDest + modulesDir, beExt, feOpts.subDir, beSubDir, checkCount, sucList, errList, nameMap, justFile); }); } } }); } function getNameMap(filePath, nameMapGroup, originalMainDir, isBackEnd, isPages) { var nameMap = null; if (nameMapGroup) { var fileName = normalizePaths(replaceExt(filePath.replace(originalMainDir, ""), "")); var filterObj = isBackEnd ? { backEnd: fileName } : { frontEnd: fileName }; var matches = _.filter(isPages ? nameMapGroup.pages : nameMapGroup.modules, filterObj); if (matches.length === 1) { var nameMapSpecific = matches[0]; nameMap = { from: isBackEnd ? nameMapSpecific.backEnd : nameMapSpecific.frontEnd, to: isBackEnd ? nameMapSpecific.frontEnd : nameMapSpecific.backEnd }; } } return nameMap; } function expectFiles(fileList, cb) { fileList.forEach(function (filePath, i) { //console.log(filePath, fs.existsSync(filePath)) expect(fs.existsSync(filePath)).toBe(true); if (i === fileList.length - 1) cb(); }); } function launchBC(bcPath, cloneDest, targetDir, cb, delay) { if (cb === void 0) { cb = null; } if (delay === void 0) { delay = 1000; } var cmd = '"' + bcPath + '" "' + cloneDest + '" "' + targetDir + '"'; // timeout is just so you have a chance to read the message above setTimeout(function () { child_process_1.exec(cmd, function (err, stdout, stderr) { if (err) { console.error(err); if (cb) cb(false, err); return; } if (cb) cb(true); }); }, delay); } function getBeyondCompareMessage(type, col, bgCol) { var colFn = chalk[col]; var bgColFn = chalk[bgCol]; var msg = bgColFn.white('\n"' + type + '" clone complete.') + colFn('\n\n Launching beyond compare...'); if (!bcLaunchedAtLeastOnce) { msg += colFn('\n\n In Beyond Compare, go to ') + bgColFn.white('"Tools -> Import Settings"') + colFn(' and choose the file ') + bgColFn.white('"deps/BCSettings.bcpkg"') + colFn(' and check all the options. ') + colFn.bold('You only need to set this once.') + colFn('\n\n When you\'re finished hit enter.'); } bcLaunchedAtLeastOnce = true; return msg; } function getFileName(filePath, inclExt) { if (inclExt === void 0) { inclExt = true; } filePath = normalizePaths(filePath); var lastSlashIndex = filePath.lastIndexOf("/"); if (inclExt) return filePath.slice(lastSlashIndex + 1); var lastDotIndex = filePath.lastIndexOf("."); return filePath.slice(lastSlashIndex + 1, lastDotIndex); } Object.defineProperty(exports, "__esModule", { value: true }); exports.default = { checkVal: checkVal, normalizePaths: normalizePaths, copyBackToFront: copyBackToFront, copyFrontToBack: copyFrontToBack, getCWD: getCWD, expectFiles: expectFiles, getBeyondCompareMessage: getBeyondCompareMessage, ensureTrainlingSlash: ensureTrainlingSlash, launchBC: launchBC, testable: { suppressWarnings: function (val) { suppressWarnings = val; }, getOptsFullPaths: getOptsFullPaths, bangUpExclusions: bangUpExclusions, copyToNewFolderStructure: copyToNewFolderStructure } };