UNPKG

clever-tools

Version:

Command Line Interface for Clever Cloud.

117 lines (98 loc) 3.71 kB
import { ERROR_TYPES, parseRaw, toNameValueObject, validateName } from '@clevercloud/client/esm/utils/env-vars.js'; import _countBy from 'lodash/countBy.js'; import readline from 'node:readline'; function readStdin() { return new Promise((resolve, reject) => { const rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: false, }); const lines = []; rl.on('line', (line) => { lines.push(line); }); rl.on('close', () => { const text = lines.join('\n'); resolve(text); }); rl.on('error', reject); }); } // The JSON input format for variables is: // an array of objects, each having: // a "name" property with a string and value // a "value" property with a string and value // TODO: This should be moved and unit tested in the clever-client repo function parseFromJson(rawStdin) { let variables; try { variables = JSON.parse(rawStdin); } catch (e) { throw new Error(`Error when parsing JSON input: ${e.message}`); } if (!Array.isArray(variables) || variables.some((entry) => typeof entry !== 'object')) { throw new Error( 'The input was valid JSON but it does not follow the correct format. It must be an array of objects.', ); } const someEntriesDontHaveNameAndValueAsString = variables.some(({ name, value }) => { return typeof name !== 'string' || typeof value !== 'string'; }); if (someEntriesDontHaveNameAndValueAsString) { throw new Error( 'The input was a valid JSON array of objects but all entries must have properties "name" and "value" of type string. Ex: { "name": "THE_NAME", "value": "the value" }', ); } const namesOccurences = _countBy(variables, 'name'); const duplicatedNames = Object.entries(namesOccurences) .filter(([_name, count]) => count > 1) .map(([name]) => `"${name}"`) .join(', '); if (duplicatedNames.length !== 0) { throw new Error(`Some variable names defined multiple times: ${duplicatedNames}`); } const invalidNames = variables .filter(({ name }) => !validateName(name)) .map(({ name }) => `"${name}"`) .join(', '); if (invalidNames.length !== 0) { throw new Error(`Some variable names are invalid: ${invalidNames}`); } return toNameValueObject(variables); } function parseFromNameEqualsValue(rawStdin) { const { variables, errors } = parseRaw(rawStdin); if (errors.length !== 0) { const formattedErrors = errors .map(({ type, name, pos }) => { if (type === ERROR_TYPES.INVALID_NAME) { return `line ${pos.line}: ${name} is not a valid variable name`; } if (type === ERROR_TYPES.DUPLICATED_NAME) { return `line ${pos.line}: be careful, the name ${name} is already defined`; } if (type === ERROR_TYPES.INVALID_LINE) { return `line ${pos.line}: this line is not valid, the correct pattern is: NAME="VALUE"`; } if (type === ERROR_TYPES.INVALID_VALUE) { return `line ${pos.line}: the value is not valid, if you use quotes, you need to escape them like this: \\" or quote the whole value.`; } return 'Unknown error in your input'; }) .join('\n'); throw new Error(formattedErrors); } return toNameValueObject(variables); } export async function readVariablesFromStdin(format) { const rawStdin = await readStdin(); switch (format) { case 'name-equals-value': return parseFromNameEqualsValue(rawStdin); case 'json': return parseFromJson(rawStdin); default: throw new Error("Unrecognized environment input format. Available formats are 'name-equals-value' and 'json'"); } }