UNPKG

@shopify/cli-kit

Version:

A set of utilities, interfaces, and models that are common across all the platform features

104 lines 4.07 kB
/* eslint-disable @typescript-eslint/no-non-null-assertion */ import { AbortError } from './error.js'; import { fileExists, readFile, writeFile } from './fs.js'; import { outputDebug, outputContent, outputToken } from '../../public/node/output.js'; import { parse } from 'dotenv'; /** * Reads and parses a .env file. * @param path - Path to the .env file * @returns An in-memory representation of the .env file. */ export async function readAndParseDotEnv(path) { outputDebug(outputContent `Reading the .env file at ${outputToken.path(path)}`); if (!(await fileExists(path))) { throw new AbortError(`The environment file at ${path} does not exist.`); } const content = await readFile(path); return { path, variables: parse(content), }; } /** * Writes a .env file to disk. * @param file - .env file to be written. */ export async function writeDotEnv(file) { const fileContent = Object.entries(file.variables) .map(([key, value]) => createDotEnvFileLine(key, value)) .join('\n'); await writeFile(file.path, fileContent); } /** * Given an .env file content, generates a new one with new values * without removing already existing lines. * @param envFileContent - .env file contents. * @param updatedValues - object containing new env variables values. */ export function patchEnvFile(envFileContent, updatedValues) { const outputLines = []; const envFileLines = envFileContent === null ? [] : envFileContent.split('\n'); const alreadyPresentKeys = []; let multilineVariable; for (const line of envFileLines) { if (multilineVariable) { if (line.endsWith(multilineVariable.quote)) { let lineToWrite = createDotEnvFileLine(multilineVariable.key, multilineVariable.value + line.slice(0, -1), multilineVariable.quote); const newValue = updatedValues[multilineVariable.key]; if (newValue) { alreadyPresentKeys.push(multilineVariable.key); lineToWrite = createDotEnvFileLine(multilineVariable.key, newValue); } outputLines.push(lineToWrite); multilineVariable = undefined; } else { multilineVariable.value += `${line}\n`; } continue; } const match = line.match(/^([^=:#]+?)[=:](.*)/); let lineToWrite = line; if (match) { const key = match[1].trim(); const value = (match[2] || '').trim(); if (/^["'`]/.test(value) && !value.endsWith(value[0])) { multilineVariable = { key, value: `${value.slice(1)}\n`, quote: value[0], }; continue; } const newValue = updatedValues[key]; if (newValue) { alreadyPresentKeys.push(key); lineToWrite = createDotEnvFileLine(key, newValue); } } outputLines.push(lineToWrite); } if (multilineVariable) { throw new AbortError(`Multi-line environment variable '${multilineVariable.key}' is not properly enclosed.`); } for (const [patchKey, updatedValue] of Object.entries(updatedValues)) { if (!alreadyPresentKeys.includes(patchKey)) { outputLines.push(createDotEnvFileLine(patchKey, updatedValue)); } } return outputLines.join('\n'); } export function createDotEnvFileLine(key, value, quote) { if (quote) { return `${key}=${quote}${value}${quote}`; } if (value?.includes('\n')) { const quoteCharacter = ['"', "'", '`'].find((char) => !value.includes(char)); if (!quoteCharacter) { throw new AbortError(`The environment file patch has an env value that can't be surrounded by quotes: ${value}`); } return `${key}=${quoteCharacter}${value}${quoteCharacter}`; } return `${key}=${value}`; } //# sourceMappingURL=dot-env.js.map