// Pattern for valid uppercase env var names: starts with letter or underscore, // followed by letters, numbers, or underscores (all uppercase) import { isPlainObject } from "../utils.js";
// Escaped: $${VAR} -> ${VAR} if (next === "$" && afterNext === "{") { const start = index + 3; const end = value.indexOf("}", start); if (end !== -1) { const name = value.slice(start, end); if (ENV_VAR_NAME_PATTERN.test(name)) { return { kind: "escaped", name, end };
}
}
}
// Substitution: ${VAR} -> value if (next === "{") { const start = index + 2; const end = value.indexOf("}", start); if (end !== -1) { const name = value.slice(start, end); if (ENV_VAR_NAME_PATTERN.test(name)) { return { kind: "substitution", name, end };
}
}
}
returnnull;
}
export type EnvSubstitutionWarning = {
varName: string;
configPath: string;
};
export type SubstituteOptions = { /** When set, missing vars call this instead of throwing and the original placeholder is preserved. */
onMissing?: (warning: EnvSubstitutionWarning) => void;
};
function substituteString(
value: string,
env: NodeJS.ProcessEnv,
configPath: string,
opts?: SubstituteOptions,
): string { if (!value.includes("$")) { return value;
}
const chunks: string[] = [];
for (let i = 0; i < value.length; i += 1) { constchar = value[i]; if (char !== "$") {
chunks.push(char); continue;
}
const token = parseEnvTokenAt(value, i); if (token?.kind === "escaped") {
chunks.push(`\${${token.name}}`);
i = token.end; continue;
} if (token?.kind === "substitution") { const envValue = env[token.name]; if (envValue === undefined || envValue === "") { if (opts?.onMissing) {
opts.onMissing({ varName: token.name, configPath }); // Preserve the original placeholder so the value is visibly unresolved.
chunks.push(`\${${token.name}}`);
i = token.end; continue;
} thrownew MissingEnvVarError(token.name, configPath);
}
chunks.push(envValue);
i = token.end; continue;
}
// Leave untouched if not a recognized pattern
chunks.push(char);
}
return chunks.join("");
}
export function containsEnvVarReference(value: string): boolean { if (!value.includes("$")) { returnfalse;
}
for (let i = 0; i < value.length; i += 1) { constchar = value[i]; if (char !== "$") { continue;
}
const token = parseEnvTokenAt(value, i); if (token?.kind === "escaped") {
i = token.end; continue;
} if (token?.kind === "substitution") { returntrue;
}
}
returnfalse;
}
function substituteAny(
value: unknown,
env: NodeJS.ProcessEnv,
path: string,
opts?: SubstituteOptions,
): unknown { if (typeof value === "string") { return substituteString(value, env, path, opts);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.