UNPKG

@constructor-io/constructorio-connect-cli

Version:

CLI tool to enable users to interface with the Constructor Connect Ecosystem

232 lines (231 loc) 9.69 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.getRepositoryConfigFile = getRepositoryConfigFile; exports.getRepositoryConnectionsAndConfig = getRepositoryConnectionsAndConfig; const fs = __importStar(require("fs/promises")); const core_1 = require("@oclif/core"); const errors_1 = require("@oclif/core/errors"); const print_warnings_1 = require("../helpers/print-warnings"); const path_1 = require("./path"); /** * @returns The exported config from the connectrc.js file . * @throws CLIError if the connectrc.js file is not found or contains a syntax error. * @description This function attempts to load the connectrc.js file from the root directory of the repository. * If the file is not found, it throws a CLIError with a message indicating the expected path. */ async function getRepositoryConfigFile() { const configPath = (0, path_1.getCustomerOSSpecificPath)("connectrc.js"); try { return require(configPath); } catch (error) { // To get ux.warn to render properly, we need to stop the action first core_1.ux.action.stop("💥"); if (error.code === "MODULE_NOT_FOUND") { throw new errors_1.CLIError(`💥 Could not find a connectrc.js file in the root directory!\nExpected to be at: ${configPath}`, { code: error.code, suggestions: [ "Make sure you have a connectrc.js file in the root directory of your repository.", `If your root directory is not the same as your current working directory, you can set the \`REPOSITORY_ROOT_DIRECTORY\` environment variable as a relative path pointing to the correct connectrc.js directory.`, ], }); } core_1.ux.warn(error.stack); if (error.name?.includes("SyntaxError")) { throw new errors_1.CLIError("💥 Syntax error found in your connectrc.js file!", { code: "SYNTAX_ERROR", }); } throw new errors_1.CLIError("💥 Could not load your connectrc.js file! \nTake a look at the original error printed above.", { code: error.code, }); } } /** * Reads the content of the connectrc.js file and returns the connections object and the content of the file * @returns The connections object and the content of the connectrc.js file in {@link RawConfigContent} */ async function getRepositoryConnectionsAndConfig() { const configPath = (0, path_1.getCustomerOSSpecificPath)("connectrc.js"); const fileContent = await readRawConfigFile(configPath); // Get the connections object from the content of the connectrc.js file const configMatch = fileContent.match(/const\s+connections\s*=\s*({[\s\S]*?});/); if (isEmptyFileContent(fileContent, configPath) || !hasConfigMatch(configMatch) || !configMatch // just for configMatch[1] below since hasConfigMatch already checks for !configMatch ) { return { fileContent: "", existingConnections: {} }; } // Remove trailing commas from the connections object const connectionsStr = configMatch[1].replace(/,(\s*[}\]])/g, "$1"); try { return { fileContent, existingConnections: JSON.parse(connectionsStr), }; } catch (error) { if (hasUnexpectedToken(error)) { return handleUnexpectedTokenError(error, connectionsStr, fileContent); } else { (0, print_warnings_1.printExecutionWarnings)({ warnings: [ { type: "Config", critical: true, message: `Failed to parse the connections object in connectrc.js. Are you running a custom setup?`, }, ], showDocsLink: false, }); return { fileContent, existingConnections: {} }; } } } /** * Reads the content of the connectrc.js file * @param configPath The path to the connectrc.js file * @returns The content of the connectrc.js file */ async function readRawConfigFile(configPath) { try { return await fs.readFile(configPath, "utf-8"); } catch { // If this function is called and "" is returned, it means that the file does not exist since // connectrc.js is not supposed to be a blank file anyway return ""; } } /** * Checks if the content of the connectrc.js file is empty * @param fileContent The content of the connectrc.js file * @param configPath The path to the connectrc.js file * @returns true if the content of the connectrc.js file is empty */ function isEmptyFileContent(fileContent, configPath) { if (!fileContent) { (0, print_warnings_1.printExecutionWarnings)({ warnings: [ { type: "Config", critical: true, message: `Could not find a connectrc.js file in the root directory!\nExpected to be at: ${configPath}`, }, ], showDocsLink: false, }); return true; } return false; } /** * Checks if the connections object is found in the connectrc.js file * @param configMatch The result of matching the connections object in the connectrc.js file * @returns true if the connections object is found in the connectrc.js file */ function hasConfigMatch(configMatch) { if (!configMatch) { (0, print_warnings_1.printExecutionWarnings)({ warnings: [ { type: "Config", critical: true, message: "Could not find the `connections` variable in connectrc.js to keep your connections up to date. Are you running a custom setup?", }, ], showDocsLink: false, }); return false; } return true; } /** * Checks if the error is an unexpected token error * @param error The error that is thrown when getting connections from connectrc.js * @returns true if the error is an unexpected token error */ function hasUnexpectedToken(error) { return (error instanceof SyntaxError && error.message.includes("Unexpected token") && error.message.includes("in JSON at position")); } /** * Checks if the connections object has properties without quotation marks, try to parse it with the properties in quotation marks * and if it's the same, it means that there's something wrong with the connection name (perhaps a quotation mark in the name) * @param _error The error that is thrown when getting connections from connectrc.js * @param connectionsStr The connections object in connectrc.js * @param fileContent The content of connectrc.js * @returns The connections object and the content of connectrc.js */ function handleUnexpectedTokenError(_error, connectionsStr, fileContent) { const QuotedConnectionStr = addQuotationMarksToProperties(connectionsStr); if (connectionsStr !== QuotedConnectionStr) { return { fileContent, existingConnections: JSON.parse(QuotedConnectionStr), }; } else { (0, print_warnings_1.printExecutionWarnings)({ warnings: [ { type: "Config", critical: true, message: `Unable to parse the connections object. Please make sure that the config file is defined as it was previously generated in the repo, as running custom setups to map your connections isn't supported when automatically updating those.`, }, ], showDocsLink: false, }); return { fileContent, existingConnections: {} }; } } /** * Adds quotation marks to all properties in the {@link PartialConnection} make it JSON parsable * @param connectionsStr The connections object in connectrc.js * @returns The connections object with the specified properties in quotation marks */ function addQuotationMarksToProperties(connectionsStr) { return connectionsStr.replace(/({\s*)([^{}]*)(\s*})/g, (_match, p1, p2, p3) => { const updatedProperties = p2.replace(/(\w+):/g, '"$1":'); return `${p1}${updatedProperties}${p3}`; }); }