UNPKG

@sasjs/cli

Version:

Command line interface for SASjs

379 lines (378 loc) 22.7 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.compileTestFlow = exports.copyTestMacroFiles = exports.compileTestFile = void 0; var utils_1 = require("@sasjs/utils"); var chalk_1 = __importDefault(require("chalk")); var path_1 = __importDefault(require("path")); var types_1 = require("../../../types"); var config_1 = require("../../../utils/config"); var file_1 = require("../../../utils/file"); var _1 = require("./"); var getFileName = function (filePath) { return path_1.default.parse(filePath).base; }; function compileTestFile(target, filePath, testVar, saveToRoot, removeOriginalFile, compileTree, destinationPath) { if (testVar === void 0) { testVar = ''; } if (saveToRoot === void 0) { saveToRoot = true; } if (removeOriginalFile === void 0) { removeOriginalFile = true; } return __awaiter(this, void 0, void 0, function () { var dependencies, _a, _b, _c, buildDestinationFolder, buildDestinationTestFolder, buildDestinationFolderName; return __generator(this, function (_d) { switch (_d.label) { case 0: _a = _1.loadDependencies; _b = [target, (0, utils_1.getAbsolutePath)(filePath, process.projectDir)]; return [4 /*yield*/, (0, config_1.getMacroFolders)(target)]; case 1: _b = _b.concat([_d.sent()]); return [4 /*yield*/, (0, config_1.getProgramFolders)(target)]; case 2: return [4 /*yield*/, _a.apply(void 0, _b.concat([_d.sent(), utils_1.SASJsFileType.test, compileTree]))]; case 3: dependencies = _d.sent(); dependencies = "".concat(testVar ? testVar + '\n' : '', "\n").concat(dependencies); _c = process.sasjsConstants, buildDestinationFolder = _c.buildDestinationFolder, buildDestinationTestFolder = _c.buildDestinationTestFolder; buildDestinationFolderName = buildDestinationFolder .split(path_1.default.sep) .pop(); destinationPath = destinationPath || path_1.default.join(buildDestinationTestFolder, saveToRoot ? filePath.split(path_1.default.sep).pop() || '' : filePath .split(path_1.default.sep) .reduce(function (acc, item, i, arr) { return acc.length ? __spreadArray(__spreadArray([], __read(acc), false), [item], false) : arr[i - 1] === buildDestinationFolderName ? __spreadArray(__spreadArray([], __read(acc), false), [item], false) : acc; }, []) .join(path_1.default.sep)); return [4 /*yield*/, (0, utils_1.createFile)(destinationPath, dependencies)]; case 4: _d.sent(); if (!removeOriginalFile) return [3 /*break*/, 6]; return [4 /*yield*/, (0, utils_1.deleteFile)(filePath)]; case 5: _d.sent(); _d.label = 6; case 6: return [2 /*return*/]; } }); }); } exports.compileTestFile = compileTestFile; function copyTestMacroFiles(folderAbsolutePath) { return __awaiter(this, void 0, void 0, function () { var macroFiles, macroTestFiles, buildDestinationTestFolder; var _this = this; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, (0, utils_1.listFilesAndSubFoldersInFolder)(folderAbsolutePath)]; case 1: macroFiles = _a.sent(); macroTestFiles = macroFiles.filter(function (item) { return utils_1.testFileRegExp.test(item); }); buildDestinationTestFolder = process.sasjsConstants.buildDestinationTestFolder; return [4 /*yield*/, (0, utils_1.asyncForEach)(macroTestFiles, function (file) { return __awaiter(_this, void 0, void 0, function () { var destinationFile; return __generator(this, function (_a) { switch (_a.label) { case 0: destinationFile = path_1.default.join(buildDestinationTestFolder, 'macros', file); return [4 /*yield*/, (0, utils_1.fileExists)(destinationFile)]; case 1: if (!!(_a.sent())) return [3 /*break*/, 3]; return [4 /*yield*/, (0, utils_1.copy)(path_1.default.join(folderAbsolutePath, file), destinationFile)]; case 2: _a.sent(); _a.label = 3; case 3: return [2 /*return*/]; } }); }); })]; case 2: _a.sent(); return [2 /*return*/]; } }); }); } exports.copyTestMacroFiles = copyTestMacroFiles; var compileTestFlow = function (target) { return __awaiter(void 0, void 0, void 0, function () { var _a, buildDestinationFolder, buildDestinationTestFolder, testFiles, config, testFlow, testSetUp, testTearDown, testSetUpFileName_1, testTearDownFileName_1; var _b, _c, _d, _e; return __generator(this, function (_f) { switch (_f.label) { case 0: if (target.testConfig && Object.keys(target.testConfig).includes('testFolders')) { process.logger.warn("'testFolders' is not supported 'testConfig' entry, please use 'serviceFolders' entry in 'serviceConfig' or 'jobFolders' entry in 'jobConfig'."); } _a = process.sasjsConstants, buildDestinationFolder = _a.buildDestinationFolder, buildDestinationTestFolder = _a.buildDestinationTestFolder; return [4 /*yield*/, (0, utils_1.folderExists)(buildDestinationTestFolder)]; case 1: if (!_f.sent()) return [3 /*break*/, 4]; return [4 /*yield*/, (0, utils_1.listFilesAndSubFoldersInFolder)(buildDestinationTestFolder)]; case 2: testFiles = (_f.sent()).map(function (file) { return path_1.default.join('tests', file); }); config = process.sasjsConfig; testFlow = { tests: [] }; testSetUp = ((_b = target.testConfig) === null || _b === void 0 ? void 0 : _b.testSetUp) || ((_c = config.testConfig) === null || _c === void 0 ? void 0 : _c.testSetUp); testTearDown = ((_d = target.testConfig) === null || _d === void 0 ? void 0 : _d.testTearDown) || ((_e = config.testConfig) === null || _e === void 0 ? void 0 : _e.testTearDown); if (testFiles.length) { if (testSetUp) { testSetUpFileName_1 = getFileName(testSetUp); if (testFiles.find(function (file) { return getFileName(file) === testSetUpFileName_1; })) { testFiles = testFiles.filter(function (file) { return getFileName(file) !== testSetUpFileName_1; }); testFlow.testSetUp = ['tests', testSetUpFileName_1].join('/'); } } if (testTearDown) { testTearDownFileName_1 = getFileName(testTearDown); if (testFiles.find(function (file) { return getFileName(file) === testTearDownFileName_1; })) { testFiles = testFiles.filter(function (file) { return getFileName(file) !== testTearDownFileName_1; }); testFlow.testTearDown = ['tests', testTearDownFileName_1].join('/'); } } } testFlow.tests = testFiles.map(function (file) { return file.split(path_1.default.sep).join('/'); }); return [4 /*yield*/, printTestCoverage(testFlow, buildDestinationFolder, target)]; case 3: _f.sent(); return [2 /*return*/, Promise.resolve(testFlow)]; case 4: return [2 /*return*/]; } }); }); }; exports.compileTestFlow = compileTestFlow; var printTestCoverage = function (testFlow, buildDestinationFolder, target) { return __awaiter(void 0, void 0, void 0, function () { var toCover, covered, extraTests, serviceFolder, collectCoverage, jobFolder, macroFolders, filter, coverage, notCovered, coveredServices, servicesToCover, notCoveredServices, coveredJobs, jobsToCover, notCoveredJobs, coveredMacros, macrosToCover, notCoveredMacros, calculateCoverage, formatCoverage; var _a, _b, _c; return __generator(this, function (_d) { switch (_d.label) { case 0: toCover = []; covered = []; extraTests = testFlow.tests; serviceFolder = path_1.default.join(buildDestinationFolder, 'services'); collectCoverage = function (folder, type, filter) { if (filter === void 0) { filter = function (s) { return true; }; } return __awaiter(void 0, void 0, void 0, function () { var files; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, (0, utils_1.folderExists)(folder)]; case 1: if (!_a.sent()) return [3 /*break*/, 3]; return [4 /*yield*/, (0, utils_1.listFilesAndSubFoldersInFolder)(folder)]; case 2: files = (_a.sent()) .filter(function (file) { return file_1.sasFileRegExp.test(file); }) .filter(filter) .map(function (file) { return [type, file.split(path_1.default.sep).join('/')].join('/'); }); toCover = __spreadArray(__spreadArray([], __read(toCover), false), __read(files), false); files.forEach(function (file) { var shouldBeCovered = ['tests', file.split(path_1.default.sep).join('/')] .join('/') .replace(file_1.sasFileRegExp, ''); if (type === 'macros') { shouldBeCovered = shouldBeCovered.split(path_1.default.sep).pop() || ''; } if (testFlow.tests.find(function (testFile) { var testCovering = testFile.replace(utils_1.testFileRegExp, ''); if (type === 'macros') { testCovering = testCovering.split(path_1.default.sep).pop() || ''; } if (testCovering === shouldBeCovered) { extraTests = extraTests.filter(function (test) { return test.replace(utils_1.testFileRegExp, '') !== testFile.replace(utils_1.testFileRegExp, ''); }); } return testCovering === shouldBeCovered; })) { covered.push(file); } }); _a.label = 3; case 3: return [2 /*return*/]; } }); }); }; return [4 /*yield*/, collectCoverage(serviceFolder, 'services')]; case 1: _d.sent(); jobFolder = path_1.default.join(buildDestinationFolder, 'jobs'); return [4 /*yield*/, collectCoverage(jobFolder, 'jobs')]; case 2: _d.sent(); return [4 /*yield*/, (0, config_1.getMacroFolders)(target)]; case 3: macroFolders = _d.sent(); return [4 /*yield*/, (0, utils_1.asyncForEach)(macroFolders, function (macroFolder) { return __awaiter(void 0, void 0, void 0, function () { return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, collectCoverage(macroFolder, 'macros', function (file) { return !utils_1.testFileRegExp.test(file); })]; case 1: _a.sent(); return [2 /*return*/]; } }); }); })]; case 4: _d.sent(); filter = function (files, type) { return files.filter(function (file) { return new RegExp("^".concat(type)).test(file); }); }; coverage = {}; notCovered = toCover.filter(function (tc) { return !covered.includes(tc); }); coveredServices = filter(covered, types_1.CoverageType.service); servicesToCover = filter(toCover, types_1.CoverageType.service); notCoveredServices = filter(notCovered, types_1.CoverageType.service); notCoveredServices.forEach(function (file, i) { coverage[file] = { Type: types_1.CoverageType.service, Coverage: types_1.CoverageState.notCovered }; }); coveredJobs = filter(covered, types_1.CoverageType.job); jobsToCover = filter(toCover, types_1.CoverageType.job); notCoveredJobs = filter(notCovered, types_1.CoverageType.job); notCoveredJobs.forEach(function (file, i) { coverage[file] = { Type: types_1.CoverageType.job, Coverage: types_1.CoverageState.notCovered }; }); coveredMacros = filter(covered, types_1.CoverageType.macro); macrosToCover = filter(toCover, types_1.CoverageType.macro); notCoveredMacros = filter(notCovered, types_1.CoverageType.macro); if (!notCoveredMacros.length) return [3 /*break*/, 6]; return [4 /*yield*/, (0, utils_1.asyncForEach)(macroFolders, function (macroFolder) { return __awaiter(void 0, void 0, void 0, function () { var macros, macroTypeRegExp; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, (0, utils_1.listFilesAndSubFoldersInFolder)(macroFolder)]; case 1: return [4 /*yield*/, (_a.sent()).filter(function (file) { return !(0, utils_1.isTestFile)(file); })]; case 2: macros = _a.sent(); macroTypeRegExp = new RegExp("^macros".concat(utils_1.pathSepEscaped)); notCoveredMacros = notCoveredMacros.map(function (macro) { return macros.includes(macro.replace(macroTypeRegExp, '')) ? macro.replace(macroTypeRegExp, macroFolder + path_1.default.sep) : macro; }); return [2 /*return*/]; } }); }); })]; case 5: _d.sent(); _d.label = 6; case 6: notCoveredMacros.forEach(function (file, i) { coverage[file] = { Type: types_1.CoverageType.macro, Coverage: types_1.CoverageState.notCovered }; }); extraTests.forEach(function (file) { coverage[file] = { Type: types_1.CoverageType.test, Coverage: types_1.CoverageState.standalone }; }); calculateCoverage = function (covered, from) { return (Math.round((covered / from) * 100) || 0) + '%'; }; formatCoverage = function (type, covered, toCover) { var _a; return toCover.length ? (_a = process.logger) === null || _a === void 0 ? void 0 : _a.info("".concat(type, " coverage: ").concat(covered.length, "/").concat(toCover.length, " (").concat(chalk_1.default.greenBright(calculateCoverage(covered.length, toCover.length)), ")")) : null; }; (_a = process.logger) === null || _a === void 0 ? void 0 : _a.info('Test coverage:'); (_b = process.logger) === null || _b === void 0 ? void 0 : _b.table(Object.keys(coverage).map(function (key) { return [ key, coverage[key].Type, coverage[key].Coverage ]; }), { head: ['File', 'Type', 'Coverage'] }); formatCoverage('Services', coveredServices, servicesToCover); formatCoverage('Jobs', coveredJobs, jobsToCover); formatCoverage('Macros', coveredMacros, macrosToCover); formatCoverage('Overall', covered, toCover); (_c = process.logger) === null || _c === void 0 ? void 0 : _c.log(''); return [4 /*yield*/, (0, utils_1.createFile)(path_1.default.join(buildDestinationFolder, 'testFlow.json'), JSON.stringify(testFlow, null, 2))]; case 7: _d.sent(); return [2 /*return*/]; } }); }); };