UNPKG

worksheets-cli

Version:
673 lines (652 loc) 26.6 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var axios = require('axios'); var sqlDataApi$1 = require('sql-data-api'); var fs = require('fs/promises'); var readline = require('readline-sync'); var path = require('path'); require('rimraf'); var jspythonInterpreter = require('jspython-interpreter'); var dataPipe = require('datapipe-js'); var dpString = require('datapipe-js/string'); var dpUtils = require('datapipe-js/utils'); var dpArray = require('datapipe-js/array'); var rxjs = require('rxjs'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } function _interopNamespace(e) { if (e && e.__esModule) return e; var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n["default"] = e; return Object.freeze(n); } var axios__default = /*#__PURE__*/_interopDefaultLegacy(axios); var axios__namespace = /*#__PURE__*/_interopNamespace(axios); var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs); var readline__default = /*#__PURE__*/_interopDefaultLegacy(readline); var path__default = /*#__PURE__*/_interopDefaultLegacy(path); var dataPipe__namespace = /*#__PURE__*/_interopNamespace(dataPipe); var dpString__namespace = /*#__PURE__*/_interopNamespace(dpString); var dpUtils__namespace = /*#__PURE__*/_interopNamespace(dpUtils); var dpArray__namespace = /*#__PURE__*/_interopNamespace(dpArray); var rxjs__namespace = /*#__PURE__*/_interopNamespace(rxjs); /*! ***************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ function __awaiter(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()); }); } function __classPrivateFieldGet(receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); } function __classPrivateFieldSet(receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; } function createDirectory(filePath) { return __awaiter(this, void 0, void 0, function* () { var dirname = path__default["default"].dirname(filePath); try { yield fs__default["default"].access(dirname); return dirname; } catch (e) { return fs__default["default"].mkdir(dirname, { recursive: true }); } }); } const CONFIG_DIRNAME = '.ws'; const DEFAULT_BASE_URL = "https://api.worksheet.systems"; class ConfigService { constructor() { this.CONFIG_FILE_PATH = path__default["default"].resolve(process.cwd(), `${CONFIG_DIRNAME}/config.json`); } save(config) { return __awaiter(this, void 0, void 0, function* () { const prev = yield this.get(); const c = Object.assign(Object.assign({}, prev), config); try { yield fs.writeFile(this.CONFIG_FILE_PATH, JSON.stringify(c, null, '\t')); this._config = c; return c; } catch (e) { console.error(e); } }); } get(prop) { return __awaiter(this, void 0, void 0, function* () { if (!this._config) { try { yield createDirectory(this.CONFIG_FILE_PATH); const f = yield fs.readFile(this.CONFIG_FILE_PATH); const config = JSON.parse(f.toString()); this._config = config; } catch (e) { this._config = {}; } } if (typeof prop === 'string') { let value = this._config[prop]; if (prop === 'baseUrl' && !value) { value = DEFAULT_BASE_URL; } return value; } return this._config; }); } } const configService = new ConfigService(); class AuthService { constructor() { this.SECURITY_URL = `/authentication`; this.TOKEN_PATH = path__default["default"].resolve(`./${CONFIG_DIRNAME}/token.txt`); } authenticate() { return __awaiter(this, void 0, void 0, function* () { const isAuth = yield this.isAuth(); if (isAuth) { return true; } return this.login(); }); } getAuthHeaders() { return { Authorization: `Bearer ${this.token}`, }; } getCurrentToken() { return this.token; } isAuth() { return __awaiter(this, void 0, void 0, function* () { const token = yield this.getToken(); if (token) { try { return this.isTokenValid(); } catch (e) { return false; } } else { return false; } }); } getToken() { return __awaiter(this, void 0, void 0, function* () { try { const token = yield fs.readFile(this.TOKEN_PATH); this.token = token.toString(); return this.token; } catch (e) { console.log("Local token token does not exist. Please login."); } }); } getCredentials(username, password) { username = username !== null && username !== void 0 ? username : readline__default["default"].question("Enter Username:"); password = password !== null && password !== void 0 ? password : readline__default["default"].question("Enter Password:", { hideEchoBack: true, }); return { username, password }; } login(username, password) { return __awaiter(this, void 0, void 0, function* () { try { const baseUrl = yield configService.get("baseUrl"); if (!baseUrl) { throw new Error("Set baseUrl to work with worksheets-cli!"); } const cred = this.getCredentials(username, password); const res = yield axios__default["default"].post(`${baseUrl}${this.SECURITY_URL}/authenticate`, cred); if (res.data.token) { this.printUser(res.data.user); yield createDirectory(this.TOKEN_PATH); yield fs.writeFile(this.TOKEN_PATH, res.data.token); this.token = res.data.token; return true; } return false; } catch (e) { console.warn(e.message); return false; } }); } simpleLogin(username, password) { return __awaiter(this, void 0, void 0, function* () { try { const baseUrl = DEFAULT_BASE_URL; const res = yield axios__default["default"].post(`${baseUrl}${this.SECURITY_URL}/authenticate`, { username, password }); if (res.data.token) { this.token = res.data.token; return res.data.token; } return null; } catch (e) { console.warn(e.message); return null; } }); } isTokenValid() { return __awaiter(this, void 0, void 0, function* () { try { const baseUrl = yield configService.get("baseUrl"); const res = yield axios__default["default"].get(`${baseUrl}${this.SECURITY_URL}/user`, { headers: this.getAuthHeaders(), }); this.printUser(res.data); return true; } catch (e) { console.log("Local token token is invalid. Please login"); return false; } }); } printUser(user) { const { firstName, lastName, email } = user; console.log(`You authorized as ${firstName} ${lastName} (${email})`); } } const authService = new AuthService(); var _Assert_chainedCheckCount, _Assert_logFn; class Assert { constructor(assert, dataContext, logFn) { this.assert = assert; this.dataContext = dataContext; _Assert_chainedCheckCount.set(this, 1); this.status = true; _Assert_logFn.set(this, void 0); __classPrivateFieldSet(this, _Assert_logFn, logFn, "f"); } equal(expected, received) { return this.assertFunction(expected, received, (e, r) => { if (typeof e === 'object') { // deepClone return JSON.stringify(e) !== JSON.stringify(r); } return e === r; }, (e, r) => `Expected '${e}', received '${r}'`); } notEqual(expected, received) { return this.assertFunction(expected, received, (e, r) => { if (typeof e === 'object') { // deepClone return JSON.stringify(e) !== JSON.stringify(r); } return e !== r; }, (e, r) => `Expected '${e}' is the same as received '${r}'`); } isTruthy(value) { return this.assertFunction(value, null, (e, r) => !!e, (e, r) => `Value '${e}' is not Truthy - https://developer.mozilla.org/en-US/docs/Glossary/Truthy`); } isFalsy(value) { return this.assertFunction(value, null, (e, r) => !e, (e, r) => `Value '${e}' is not Falsy - https://developer.mozilla.org/en-US/docs/Glossary/Falsy`); } isTrue(value) { return this.assertFunction(value, null, (e, r) => e === true, (e, r) => `Value '${e}' is not true`); } isFalse(value) { return this.assertFunction(value, null, (e, r) => e === false, (e, r) => `Value '${e}' is not false`); } greaterThan(value1, value2) { return this.assertFunction(value1, value2, (e, r) => e > r, (e, r) => `${e}' is not greater than ${r}`); } greaterOrEqualThan(value1, value2) { return this.assertFunction(value1, value2, (e, r) => e >= r, (e, r) => `${e}' is not greater (or equal) than ${r}`); } inRange(value, min, max) { return this.between(value, min, max); } between(value, min, max) { return this.assertFunction(value, { min, max }, (v, r) => v >= r.min && v <= r.max, (v, r) => `${v}' is NOT in range of ${r.min} and ${r.max}`); } lessThan(value1, value2) { return this.assertFunction(value1, value2, (e, r) => e < r, (e, r) => `${e}' is not lesser than ${r}`); } lessOrEqualThan(value1, value2) { return this.assertFunction(value1, value2, (e, r) => e <= r, (e, r) => `${e}' is not lesser (or equal) than ${r}`); } assertFunction(expected, received, assertExpressionFn, errorMessageFn) { var _a; // resolve function, if any if (typeof expected === 'function') { expected = expected(this.dataContext); } if (typeof received === 'function') { received = received(this.dataContext); } if (!assertExpressionFn(expected, received)) { this.status = false; this.message = `[${__classPrivateFieldGet(this, _Assert_chainedCheckCount, "f")}] - ${errorMessageFn(expected, received)}`; __classPrivateFieldGet(this, _Assert_logFn, "f").call(this, false, this.message); return this; } __classPrivateFieldGet(this, _Assert_logFn, "f").call(this, true, ''); __classPrivateFieldSet(this, _Assert_chainedCheckCount, (_a = __classPrivateFieldGet(this, _Assert_chainedCheckCount, "f"), _a++, _a), "f"); return this; } } _Assert_chainedCheckCount = new WeakMap(), _Assert_logFn = new WeakMap(); // import * as sqlDataApi from 'sql-data-api'; const sqlDataApi = require("sql-data-api"); sqlDataApi.setBaseUrl(DEFAULT_BASE_URL); const AVAILABLE_PACKAGES = { "datapipe-js": dataPipe__namespace, "datapipe-js/utils": dpUtils__namespace, "datapipe-js/array": dpArray__namespace, "datapipe-js/string": dpString__namespace, "sql-data-api": sqlDataApi, rxjs: rxjs__namespace, axios: axios__namespace, "rxjs/factory": { createSubject: () => new rxjs__namespace.Subject(), createAsyncSubject: () => new rxjs__namespace.AsyncSubject(), createBehaviorSubject: (v) => new rxjs__namespace.BehaviorSubject(v), createReplaySubject: (v) => new rxjs__namespace.ReplaySubject(v), }, }; const mapFunction = new Map([ ["typeof", (val) => typeof val], [ "httpGet", (url, headers) => sqlDataApi.httpGet(url, Object.assign({}, headers)), ], [ "httpGetText", (url, headers) => sqlDataApi.httpGetText(url, headers), ], [ "httpRequest", (method, url, body, headers) => sqlDataApi.httpRequest(method, url, body, headers), ], [ "httpPost", (url, body, headers) => sqlDataApi.httpPost(url, body, Object.assign({}, headers)), ], [ "httpPut", (url, body, headers) => sqlDataApi.httpPut(url, body, Object.assign({}, headers)), ], [ "httpDelete", (url, headers) => sqlDataApi.httpDelete(url, undefined, Object.assign({}, headers)), ], ["httpGet$", (url, c) => rxjs.from(sqlDataApi.httpGet(url, c))], ["httpRequest$", (url, p, c) => rxjs.from(sqlDataApi.httpRequest(url, p, c))], ["parseInt", parseInt], ["parseFloat", parseFloat], [ "dateTime", (value, format) => dpUtils.parseDatetimeOrNull(value, format) || new Date(), ], [ "setQueryParameters", (search) => { const url = location.pathname + (search.startsWith("?") ? search : `?${search}`); window.history.pushState({}, "", url); }, ], ]); function getInterpreter(jspyModuleLoader = (_) => Promise.resolve("")) { const interpreter = jspythonInterpreter.jsPython() .registerPackagesLoader(packageLoader) .registerModuleLoader(jspyModuleLoader) .assignGlobalContext({}); addFunctions(interpreter); return interpreter; } function addFunctions(interpreter) { mapFunction.forEach((func, name) => { func["interpreter"] = interpreter; interpreter.addFunction(name, func); }); } function packageLoader(packageName) { if (!AVAILABLE_PACKAGES.hasOwnProperty(packageName)) { throw Error(`Package '${packageName}' is not available.`); } return AVAILABLE_PACKAGES[packageName]; } function toContentPath(path) { let lastSlash = Math.max(path.lastIndexOf('/'), 0); const folder = lastSlash > 0 ? path.substring(0, lastSlash) : ''; let name = path.substring(lastSlash); if (name[0] === '/') { name = name.replace('/', ''); } let contentType = ''; if (path.endsWith('app.xml')) { contentType = 'app.xml'; name = ''; } else if (path.endsWith('component.xml')) { contentType = 'component.xml'; name = name.replace('.component.xml', ''); } else if (path.endsWith('page.xml')) { contentType = 'page.xml'; name = name.replace('.page.xml', ''); } else { const lastDot = name.lastIndexOf('.'); if (lastDot < 0) { throw new Error('Incorrect path' + path); } contentType = name.substring(lastDot + 1); name = name.substring(0, lastDot); } return { folder, name, contentType }; } sqlDataApi$1.setBaseUrl(DEFAULT_BASE_URL); class WorksheetsRunner { constructor(config) { this.config = config; this.asserts = []; this.logLines = []; this.previousLogMessage = ""; } login() { return __awaiter(this, void 0, void 0, function* () { this.auth = yield authService .simpleLogin(this.config.userName, this.config.password) .then((token) => { if (!token) { throw new Error("Failed to login"); } sqlDataApi$1.setBearerToken(token); return token; }) .catch((e) => { console.log(`AUTH ERROR: ${e.message}`); return e; }); }); } assert(name, dataContext) { // an original case when if (typeof dataContext === "boolean") { this.logFn({ level: dataContext ? "success" : "fail", message: name || "", time: new Date(), }); this.asserts.push({ success: !!dataContext, name }); return; } const assertCallback = (success, message) => { var _a; this.logFn({ logId: name, level: success ? "success" : "fail", message: `${name} ${message ? ":" : ""} ${message || ""}`, time: new Date(), }); const existingAssert = (_a = this.asserts) === null || _a === void 0 ? void 0 : _a.find((a) => a.name === name); if (existingAssert) { // only if condition it is not fail yet if (!!existingAssert.success) { existingAssert.success = !!success; existingAssert.description = message; } } else { this.asserts.push({ success: !!success, name: name, description: message, }); } }; return new Assert(name, dataContext, assertCallback); } logFn(msg) { const level = msg.level === "success" ? msg.level : msg.level + " "; const message = `${level} | ${msg.message}`; if (message !== this.previousLogMessage) { this.logLines.push(`| ${msg.time.toTimeString().slice(0, 8)} | ${message}`); this.previousLogMessage = message; } } assignFunctions(interpreter) { interpreter.addFunction("print", (...args) => { console.log(...args); const message = args .map((v) => (typeof v === "object" ? JSON.stringify(v) : String(v))) .join(", "); this.logFn({ level: "info", message, time: new Date(), }); return args.length > 0 ? args[0] : null; }); interpreter.addFunction("assert", (name, dataContext) => this.assert(name, dataContext)); interpreter.addFunction("showAsserts", () => this.asserts.forEach((r) => this.logFn({ time: new Date(), level: "info", message: `${r.success ? "success" : "fail "} | ${r.name}${!!r.description ? ": " : ""}${r.description || ""}`.trim(), }))); } run(appPath, filePath, functionName) { var _a; return __awaiter(this, void 0, void 0, function* () { this.logLines = []; this.setAppPath(appPath); const file = (yield this.loadFileContent(filePath)).data.content; const interpreter = getInterpreter((link) => __awaiter(this, void 0, void 0, function* () { return this.moduleLoader(link); })); this.assignFunctions(interpreter); const context = { __env: { args: {}, entryModule: filePath, entryFunction: functionName || "", runsAt: "task-scheduller", }, }; try { this.logLines.push(interpreter.jsPythonInfo()); this.logLines.push(`> ${filePath}`); const result = yield interpreter.evaluate(file, context, functionName, filePath); if ((_a = this.asserts) === null || _a === void 0 ? void 0 : _a.length) { this.logLines.push(` > assert success : ${this.asserts.filter((a) => a.success).length}`); this.logLines.push(` > assert failed : ${this.asserts.filter((a) => !a.success).length}`); } return { log: this.logLines.join("\n"), result, }; } catch (ex) { return { error: ex.message, log: this.logLines.join("\n") }; } }); } getScheduledTasks(days, time) { var _a; return __awaiter(this, void 0, void 0, function* () { const isAuth = yield this.auth; if (!isAuth) { console.log("Not authorized"); return; } let url = `${DEFAULT_BASE_URL}/api/scheduled-tasks`; const qp = []; if ((days === null || days === void 0 ? void 0 : days.length) > 0) { qp.push("$days=" + days); } if ((time === null || time === void 0 ? void 0 : time.length) > 0) { qp.push("$time=" + time); } if (qp.length > 0) { url = url + "?" + qp.join("&"); } return (_a = (yield axios__default["default"] .get(url, { headers: authService.getAuthHeaders(), }) .catch((e) => { console.log(e.message); return null; }))) === null || _a === void 0 ? void 0 : _a.data; }); } startScheduledTask(taskId, agentName = "agent1") { return __awaiter(this, void 0, void 0, function* () { const url = `${DEFAULT_BASE_URL}/api/scheduled-tasks/start/${taskId}/${agentName}`; return (yield axios__default["default"].post(url, null, { headers: authService.getAuthHeaders(), })).data; }); } endScheduledTask(taskStatusId, status, result) { return __awaiter(this, void 0, void 0, function* () { const url = `${DEFAULT_BASE_URL}/api/scheduled-tasks/end`; return (yield axios__default["default"].put(url, { taskStatusId, status, result }, { headers: authService.getAuthHeaders(), })).data; }); } moduleLoader(link) { return __awaiter(this, void 0, void 0, function* () { if (link.startsWith("./")) { link = link.substring(2); } if (link.startsWith("/")) { link = link.substring(1); } const res = yield this.loadFileContent(link); return res.data.content || ""; }); } setAppPath(appPath) { const [appOwner, appName] = appPath.split("/"); if (!appOwner) { throw new Error("App owner is not initialized"); } this.appOwner = appOwner; if (!appName) { throw new Error("App name is not initialized"); } this.appName = appName; } loadFileContent(link) { return __awaiter(this, void 0, void 0, function* () { const c = toContentPath(link); const data = { contentType: c.contentType, folder: c.folder, name: c.name, appName: this.appName, appOwnerName: this.appOwner, }; const url = `${DEFAULT_BASE_URL}/api/app-definitions/get-app-content`; return yield axios__default["default"].post(url, data, { headers: authService.getAuthHeaders(), }); }); } } exports.WorksheetsRunner = WorksheetsRunner; //# sourceMappingURL=public-api.js.map