@catladder/cli
Version:
Panter cli tool for cloud CI/CD and DevOps
137 lines • 6.04 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.escapeForDotEnv = exports.escapeNewlines = exports.escapeBackTicks = exports.escapeSingleQuotes = exports.escapeDoubleQuotes = exports.escapeBashExpression = exports.escapeString = exports.bashEscape = void 0;
const globalScriptFunctions_1 = require("../globalScriptFunctions");
const VariableValueContainingReferences_1 = require("../variables/VariableValueContainingReferences");
const BashExpression_1 = require("./BashExpression");
/**
* escapes a string or bash expression for bash
* it either can escape single or double quotes (double is default)
*/
const bashEscape = (value, options = {
quotes: "double",
}) => {
if (value instanceof BashExpression_1.BashExpression) {
// no need to escape
return (0, exports.escapeBashExpression)(value, options);
}
if (value instanceof VariableValueContainingReferences_1.VariableValueContainingReferences) {
return value.toString(options);
}
return (0, exports.escapeString)(value, options);
};
exports.bashEscape = bashEscape;
const escapeString = (value, { quotes } = {
quotes: "double",
}) => {
const quoteEscaped = quotes
? quotes === "single"
? (0, exports.escapeSingleQuotes)(value)
: (0, exports.escapeDoubleQuotes)(value)
: value;
return quoteEscaped;
};
exports.escapeString = escapeString;
const escapeBashExpression = (value, options) => {
// no need to escape, we just return the string
return value;
};
exports.escapeBashExpression = escapeBashExpression;
const escapeDoubleQuotes = (value) => value === null || value === void 0 ? void 0 : value.toString().replace(/"/g, '\\"');
exports.escapeDoubleQuotes = escapeDoubleQuotes;
const escapeSingleQuotes = (value) => value === null || value === void 0 ? void 0 : value.toString().replace(/'/g, "\\'");
exports.escapeSingleQuotes = escapeSingleQuotes;
const escapeBackTicks = (value) => value === null || value === void 0 ? void 0 : value.toString().replace(/`/g, "\\`");
exports.escapeBackTicks = escapeBackTicks;
const escapeNewlines = (value) => value === null || value === void 0 ? void 0 : value.toString().replace(/\n/g, "\\n");
exports.escapeNewlines = escapeNewlines;
/**
*
* escape env vars for .env files.
* unfortunatly, the format has many limitations. In order to be very forgiving, we need to do some magic here:
*
* - when the value contains no newlines, we are fine
* - if the value contains newlines, we need to wrap it in quotes. And thats where the problem begins:
* - you can't escape quotes. this is a limitation of dotenv and node
* - you can have inner quotes, but they break in node.js (not in dotenv though), see https://github.com/nodejs/node/issues/54134
* - so we need to quote cleverly
* - to make things worse, we need to check whether we have a simple stirng or a bash expression, that needs to be evalulated first...
*
* what an absolute nightmare.
*
* - other languages are currently only partially supported, since most .env implementations are slightly different
*/
const escapeForDotEnv = (value, options = {
quoteMode: "auto",
}) => {
if (value === undefined || value === null) {
return "";
}
if (typeof value === "string") {
// if string contains newlines, we need to wrap it in quotes
// we additionaly escape newlines, that give best compatibility
if (options.quoteMode === "always" || value.includes("\n")) {
const newlinesReplaces = value.replace(/\n/g, "\\n");
// default to ", but if this is not possible, we try to use ' or `
const quote = value.includes(`"`)
? value.includes(`'`)
? value.includes("`")
? // If all quote types are present, default to double quotes. This works in dotenv, but not in node.js because of the bug mentioned abouve
'"'
: "`"
: "'"
: '"';
// if we found a quote, we can wrap the string in it
return `${quote}${newlinesReplaces}${quote}`;
}
else {
// otherwise we can return as is
return value;
}
}
else if (value instanceof BashExpression_1.BashExpression) {
return escapeBashExpressionForDotEnv(value);
}
else if (value instanceof VariableValueContainingReferences_1.VariableValueContainingReferences) {
// instead of doing it part-wise, we just do it all at once
const containsAnyBashExpression = value.parts.some((part) => part instanceof BashExpression_1.BashExpression);
if (!containsAnyBashExpression) {
return (0, exports.escapeForDotEnv)(value.toString({
quotes: "double",
}));
}
else {
const result = escapeBashExpressionForDotEnv(new BashExpression_1.BashExpression(value.toString({
quotes: "double",
})));
return result;
}
}
else {
return value;
}
};
exports.escapeForDotEnv = escapeForDotEnv;
// basically the same thing as above for bash
// thx chatgpt for this
const escapeForDotEnvScript = (0, globalScriptFunctions_1.registerGlobalScriptFunction)("escapeForDotEnv", `
input="\${1:-$(cat)}"
input="\${input//$'\\n'/\\\\n}"
if [[ "$input" == *\\\\n* ]]; then
if [[ "$input" == *\\"* && "$input" == *\\'* && "$input" == *\\\`* ]]; then
printf "\\"%s\\"\\n" "$input" ${ /* fallback to double quotes */""}
elif [[ "$input" == *\\"* && "$input" == *\\'* ]]; then
printf "\`%s\`\\n" "$input"
elif [[ "$input" == *\\"* ]]; then
printf "'%s'\\n" "$input"
else
printf "\\"%s\\"\\n" "$input"
fi
else
printf "%s\\n" "$input"
fi
`);
const escapeBashExpressionForDotEnv = (value) => {
return value.transformWithCommand(escapeForDotEnvScript.name).toString();
};
//# sourceMappingURL=bashEscape.js.map