UNPKG

@tableau/taco-toolkit

Version:
255 lines 20.5 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.getPackedTacoFilename = exports.getTemplateVarValues = exports.getTemplateAndDestPath = exports.writeTacoFile = exports.createFiles = void 0; var fs_1 = __importDefault(require("fs")); var path_1 = __importDefault(require("path")); var logging_1 = require("../utils/logging"); var status_code_1 = require("../../../shared/errors/status-code"); var error_codes_1 = require("../../../shared/errors/error-codes"); var error_source_1 = require("../../../shared/errors/error-source"); var connector_json_1 = require("../utils/connector-json"); var toolkit_paths_1 = require("../utils/toolkit-paths"); var COMMON_TEMPLATES = ['connection-fields.xml', 'connection-metadata.xml']; var OAUTH_CONNECTOR_TEMPLATES = ['manifest-oauth.xml', 'oauth-config.xml']; var BASIC_CONNECTOR_TEMPLATES = ['manifest.xml']; /** * Create taco xml files according to the information in the connector.json. * It does not check file existence. It overwrites if any file exists. */ function createFiles(connectorJson, templateAndDests) { return __awaiter(this, void 0, void 0, function () { var variableValues, result, failures; return __generator(this, function (_a) { switch (_a.label) { case 0: variableValues = getTemplateVarValues(connectorJson); return [4 /*yield*/, Promise.allSettled(templateAndDests.map(function (_a) { var templatePath = _a.templatePath, destFilePath = _a.destFilePath; return writeTacoFile(templatePath, destFilePath, variableValues); }))]; case 1: result = _a.sent(); failures = []; result.forEach(function (result, index) { var destFilePath = templateAndDests[index].destFilePath; if (result.status === 'rejected') { failures.push({ path: destFilePath, reason: result.reason, }); } }); if (failures.length > 0) { return [2 /*return*/, { state: 'error', error: { statusCode: status_code_1.StatusCode.Cancelled, errorSource: error_source_1.ErrorSources.Client, errorCode: error_codes_1.ErrorCodes.EJB55C4V, message: "Error occurred when creating files: ".concat(failures), }, }]; } return [2 /*return*/, { state: 'success' }]; } }); }); } exports.createFiles = createFiles; function writeTacoFile(templatePath, destFilePath, variableValues) { return __awaiter(this, void 0, void 0, function () { var templateContent, content; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, fs_1.default.promises.readFile(templatePath, { encoding: 'utf8', flag: 'r', })]; case 1: templateContent = _a.sent(); content = templateContent.replace(/{{([^}]+)}}/g, function (matched, variable) { var value = variableValues[variable]; if (value === undefined) { // Only log error here to let the file generation complete. The validation phase will stop the pack. logging_1.logger.error("Missing required variable '".concat(variable, "'. Please check if the corresponding config is set in the connection.json")); return matched; } return value; }); return [2 /*return*/, fs_1.default.promises.writeFile(destFilePath, content, { encoding: 'utf8', flag: 'w', })]; } }); }); } exports.writeTacoFile = writeTacoFile; function getTacoFileTemplates(connectorJson) { if ((0, connector_json_1.isOauthConnector)(connectorJson)) { return __spreadArray(__spreadArray([], __read(COMMON_TEMPLATES), false), __read(OAUTH_CONNECTOR_TEMPLATES), false); } return __spreadArray(__spreadArray([], __read(COMMON_TEMPLATES), false), __read(BASIC_CONNECTOR_TEMPLATES), false); } function getTemplateAndDestPath(tacoRootPath, connectorJson) { return getTacoFileTemplates(connectorJson).map(function (template) { return { templatePath: path_1.default.join(toolkit_paths_1.TEMPLATE_ROOT_PATH, template), destFilePath: path_1.default.resolve(tacoRootPath, getDestXmlFilename(template)), }; }); } exports.getTemplateAndDestPath = getTemplateAndDestPath; function getDestXmlFilename(templateName) { if (templateName === 'manifest-oauth.xml') { return 'manifest.xml'; } return templateName; } function createXmlTag(tagName, value) { if (!value) { return ''; } return "<".concat(tagName, ">").concat(value, "</").concat(tagName, ">"); } function createXmlTagList(tagName, values, indent) { if (!values) { return ''; } return values.map(function (value) { return "".concat(' '.repeat(indent), "<").concat(tagName, ">").concat(value, "</").concat(tagName, ">\n"); }).join(''); } function createXmlTagKeyValue(values, indent) { if (!values) { return ''; } return Object.entries(values) .map(function (_a) { var _b = __read(_a, 2), key = _b[0], value = _b[1]; return "".concat(' '.repeat(indent * 2), "<entry>\n") + // prettier "".concat(' '.repeat(indent * 3), "<key>").concat(key, "</key>\n") + "".concat(' '.repeat(indent * 3), "<value>").concat(value, "</value>\n") + "".concat(' '.repeat(indent * 2), "</entry>\n"); }) .join(''); } function getTemplateVarValues(connectorJson) { var _a; var isOauth = (0, connector_json_1.isOauthConnector)(connectorJson); var values = { // class name is derived from connectorJson.name CLASS: (0, connector_json_1.getConnectorClassName)(connectorJson), // By default, connectorJson.name will be used for connector display name, // while the connector may use displayName property to overwrites it. NAME: (_a = connectorJson.displayName) !== null && _a !== void 0 ? _a : connectorJson.name, 'PLUGIN-VERSION': connectorJson.version, 'MIN-TAB-VERSION': connectorJson['tableau-version'].min, // The version is hardcoded to 18.1 as referring to https://tableau.github.io/connector-plugin-sdk/docs/design 'MANEFIEST-VERSION': '18.1', // The version needs to be hardcoded to 10.0 // refer to https://github.com/tableau/connector-plugin-sdk/blob/master/samples/plugins/postgres_jdbc/manifest.xml 'CONNECTION-CUSTOM-VERSION': '10.0', 'COMP-NAME': connectorJson.vendor.name, 'COMP-URL': connectorJson.vendor['support-link'], AUTH: isOauth ? 'oauth' : 'auth-none', }; if (isOauth) { // At this point, connectorJson should be already validated. // The type casting should be safe. var oauthConfig = connectorJson.auth.oauth; Object.assign(values, { // values with tag OAUTH_CONFIG_ID: createXmlTag('oauthConfigId', oauthConfig.oauthConfigId), CONFIG_LABEL: createXmlTag('configLabel', oauthConfig.configLabel), AUTH_URI: createXmlTag('authUri', oauthConfig.authUri), TOKEN_URI: createXmlTag('tokenUri', oauthConfig.tokenUri), USERINFO_URI: createXmlTag('userInfoUri', oauthConfig.userInfoUri), CLIENT_ID: createXmlTag('clientIdDesktop', oauthConfig.clientIdDesktop), CLIENT_SECRET: createXmlTag('clientSecretDesktop', oauthConfig.clientSecretDesktop), INSTANCEURL_SUFFIX: createXmlTag('instanceUrlSuffix', oauthConfig.instanceUrlSuffix), INSTANCEURL_VALIDATION_REGEX: createXmlTag('instanceUrlValidationRegex', oauthConfig.instanceUrlValidationRegex), DEFAULT_INSTANCEURL: createXmlTag('defaultInstanceUrl', oauthConfig.defaultInstanceUrl), // list values REDIRECT_URI: createXmlTagList('redirectUrisDesktop', oauthConfig.redirectUrisDesktop, 4), SCOPES: createXmlTagList('scopes', oauthConfig.scopes, 4), // key-value values CAPABILITIES: createXmlTagKeyValue(oauthConfig.capabilities, 4), ACCESS_MAPS: createXmlTagKeyValue(oauthConfig.accessTokenResponseMaps, 4), }); } return values; } exports.getTemplateVarValues = getTemplateVarValues; function getPackedTacoFilename(connectorJson, nameOnly, tacoName) { var connectorClassName = tacoName ? tacoName : (0, connector_json_1.getConnectorClassName)(connectorJson); if (nameOnly) { return "".concat(connectorClassName, ".taco"); } var version = connectorJson.version.toLowerCase(); return "".concat(connectorClassName, "-").concat(version, ".taco"); } exports.getPackedTacoFilename = getPackedTacoFilename; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFjby1maWxlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9jbGkvdGFjby1jb21tYW5kcy9wYWNrL3RhY28tZmlsZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLDBDQUFtQjtBQUNuQiw4Q0FBdUI7QUFFdkIsNENBQXFEO0FBRXJELGtFQUErRDtBQUUvRCxrRUFBK0Q7QUFDL0Qsb0VBQWtFO0FBRWxFLDBEQUFpRjtBQUNqRix3REFBMkQ7QUFZM0QsSUFBTSxnQkFBZ0IsR0FBRyxDQUFDLHVCQUF1QixFQUFFLHlCQUF5QixDQUFDLENBQUE7QUFFN0UsSUFBTSx5QkFBeUIsR0FBRyxDQUFDLG9CQUFvQixFQUFFLGtCQUFrQixDQUFDLENBQUE7QUFDNUUsSUFBTSx5QkFBeUIsR0FBRyxDQUFDLGNBQWMsQ0FBQyxDQUFBO0FBRWxEOzs7R0FHRztBQUNILFNBQXNCLFdBQVcsQ0FDL0IsYUFBNEIsRUFDNUIsZ0JBQW1DOzs7Ozs7b0JBRTdCLGNBQWMsR0FBRyxvQkFBb0IsQ0FBQyxhQUFhLENBQUMsQ0FBQTtvQkFFM0MscUJBQU0sT0FBTyxDQUFDLFVBQVUsQ0FDckMsZ0JBQWdCLENBQUMsR0FBRyxDQUFDLFVBQUMsRUFBOEI7Z0NBQTVCLFlBQVksa0JBQUEsRUFBRSxZQUFZLGtCQUFBOzRCQUNoRCxPQUFPLGFBQWEsQ0FBQyxZQUFZLEVBQUUsWUFBWSxFQUFFLGNBQWMsQ0FBQyxDQUFBO3dCQUNsRSxDQUFDLENBQUMsQ0FDSCxFQUFBOztvQkFKSyxNQUFNLEdBQUcsU0FJZDtvQkFFSyxRQUFRLEdBQTBCLEVBQUUsQ0FBQTtvQkFDMUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxVQUFDLE1BQU0sRUFBRSxLQUFLO3dCQUNuQixJQUFBLFlBQVksR0FBSyxnQkFBZ0IsQ0FBQyxLQUFLLENBQUMsYUFB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