@creditkarma/dynamic-config
Version:
Dynamic Config for Node.js backed by Consul and Vault
115 lines • 3.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.envTranslator = void 0;
/**
* Plugin that replaces ${<variable-name>} with an environment placeholder.
*
* http://${HOSTNAME}:9000
*/
const errors_1 = require("../errors");
function isValidChar(char) {
return ((char >= 'A' && char <= 'Z') ||
(char >= '0' && char <= '9') ||
char === '_' ||
char === '|');
}
class Interpolater {
constructor() {
this.source = '';
this.len = 0;
this.index = 0;
this.match = '';
}
run(source) {
this.source = source;
this.len = source.length;
this.index = 0;
this.match = '';
let result = '';
let defaultVal = '';
while (this.index < this.len) {
const char = this.current();
if (char === '$' && this.peek() === '{') {
this.advance(); // advance past $
this.advance(); // advance path {
while (!this.isAtEnd() &&
this.current() !== '}' &&
isValidChar(this.current())) {
// Check if we are handling a default value
if (this.current() === '|' && this.peek() === '|') {
this.advance(); // advance past first |
this.advance(); // advance past second |
defaultVal = this.parseDefault();
// Don't allow random pipe characters
}
else if (this.current() === '|') {
// pipe is invalid unless defining default value
throw new errors_1.InvalidCharacter(this.current());
// Otherwise we're still parsing the name match
}
else {
this.match += this.current();
this.advance();
}
// These handle the end of our parse
if (this.current() === '}' &&
process.env[this.match.trim()] !== undefined) {
// Match found
this.advance(); // advance past }
result += process.env[this.match.trim()];
this.match = '';
}
else if (this.current() === '}' && defaultVal !== '') {
result += defaultVal;
this.advance(); // advance past }
}
else if (this.current() === '}') {
throw new errors_1.MissingEnvironmentVariable(this.match);
}
else if (this.isAtEnd()) {
result += this.match;
this.match = '';
}
}
}
else {
result += char;
this.advance();
}
}
return result;
}
parseDefault() {
let result = '';
while (!this.isAtEnd() && this.current() !== '}') {
result += this.current();
this.advance();
}
return result.trim();
}
current() {
return this.source.charAt(this.index);
}
isAtEnd() {
return this.index >= this.len;
}
peek() {
return this.source.charAt(this.index + 1);
}
advance() {
this.index += 1;
}
}
const interpolater = new Interpolater();
exports.envTranslator = {
translate(configValue) {
if (typeof configValue === 'string') {
const envVar = interpolater.run(configValue);
if (envVar !== undefined) {
return envVar;
}
}
return configValue;
},
};
//# sourceMappingURL=env.js.map