Add key mutation commands (add, set, unset, delete) for v0.0.4
- Add CLI commands: add, set, unset, delete for modifying .env files - Add value auto-quoting for special characters (spaces, #, quotes, newlines) - Add example file detection with warning for .env.example/.sample/.template - Add library API: addEnvFileKey, setEnvFileKey, unsetEnvFileKey, deleteEnvFileKeys - Export isExampleEnvFile utility - Add tests for new mutation operations - Update README and CHANGELOG
This commit is contained in:
+152
-1
@@ -1,6 +1,17 @@
|
||||
import { readFile } from 'node:fs/promises';
|
||||
|
||||
import { annotateDotenvKey, copyDotenvKeys, formatDotenv, validateDotenv } from './dotenv/edit.js';
|
||||
import {
|
||||
addDotenvKey,
|
||||
annotateDotenvKey,
|
||||
copyDotenvKeys,
|
||||
deleteDotenvKeys,
|
||||
formatDotenv,
|
||||
setDotenvKey,
|
||||
unsetDotenvKey,
|
||||
validateDotenv,
|
||||
type KeyMutationAction,
|
||||
type KeyMutationPlanItem
|
||||
} from './dotenv/edit.js';
|
||||
import { readTextFileOrEmpty, writeTextFileAtomic } from './dotenv/io.js';
|
||||
|
||||
export type DotenvIssue = {
|
||||
@@ -172,3 +183,143 @@ export async function validateEnvFile(file: string): Promise<ValidateEnvFileResu
|
||||
const result = validateDotenv(contents);
|
||||
return { file, ok: result.ok, issues: result.issues };
|
||||
}
|
||||
|
||||
export type { KeyMutationAction, KeyMutationPlanItem };
|
||||
|
||||
export type AddEnvFileKeyResult = {
|
||||
file: string;
|
||||
key: string;
|
||||
willWrite: boolean;
|
||||
wrote: boolean;
|
||||
hasChanges: boolean;
|
||||
issues: DotenvIssue[];
|
||||
plan: KeyMutationPlanItem;
|
||||
};
|
||||
|
||||
export async function addEnvFileKey(options: {
|
||||
file: string;
|
||||
key: string;
|
||||
value: string;
|
||||
write?: boolean;
|
||||
}): Promise<AddEnvFileKeyResult> {
|
||||
const contents = await readTextFileOrEmpty(options.file);
|
||||
const result = addDotenvKey({ contents, key: options.key, value: options.value });
|
||||
|
||||
const willWrite = options.write === true;
|
||||
if (willWrite && result.hasChanges) {
|
||||
await writeTextFileAtomic(options.file, result.output);
|
||||
}
|
||||
|
||||
return {
|
||||
file: options.file,
|
||||
key: options.key,
|
||||
willWrite,
|
||||
wrote: willWrite && result.hasChanges,
|
||||
hasChanges: result.hasChanges,
|
||||
issues: result.issues,
|
||||
plan: result.plan
|
||||
};
|
||||
}
|
||||
|
||||
export type SetEnvFileKeyResult = {
|
||||
file: string;
|
||||
key: string;
|
||||
willWrite: boolean;
|
||||
wrote: boolean;
|
||||
hasChanges: boolean;
|
||||
issues: DotenvIssue[];
|
||||
plan: KeyMutationPlanItem;
|
||||
};
|
||||
|
||||
export async function setEnvFileKey(options: {
|
||||
file: string;
|
||||
key: string;
|
||||
value: string;
|
||||
write?: boolean;
|
||||
}): Promise<SetEnvFileKeyResult> {
|
||||
const contents = await readTextFileOrEmpty(options.file);
|
||||
const result = setDotenvKey({ contents, key: options.key, value: options.value });
|
||||
|
||||
const willWrite = options.write === true;
|
||||
if (willWrite && result.hasChanges) {
|
||||
await writeTextFileAtomic(options.file, result.output);
|
||||
}
|
||||
|
||||
return {
|
||||
file: options.file,
|
||||
key: options.key,
|
||||
willWrite,
|
||||
wrote: willWrite && result.hasChanges,
|
||||
hasChanges: result.hasChanges,
|
||||
issues: result.issues,
|
||||
plan: result.plan
|
||||
};
|
||||
}
|
||||
|
||||
export type UnsetEnvFileKeyResult = {
|
||||
file: string;
|
||||
key: string;
|
||||
willWrite: boolean;
|
||||
wrote: boolean;
|
||||
hasChanges: boolean;
|
||||
issues: DotenvIssue[];
|
||||
plan: KeyMutationPlanItem;
|
||||
};
|
||||
|
||||
export async function unsetEnvFileKey(options: {
|
||||
file: string;
|
||||
key: string;
|
||||
write?: boolean;
|
||||
}): Promise<UnsetEnvFileKeyResult> {
|
||||
const contents = await readFile(options.file, 'utf8');
|
||||
const result = unsetDotenvKey({ contents, key: options.key });
|
||||
|
||||
const willWrite = options.write === true;
|
||||
if (willWrite && result.hasChanges) {
|
||||
await writeTextFileAtomic(options.file, result.output);
|
||||
}
|
||||
|
||||
return {
|
||||
file: options.file,
|
||||
key: options.key,
|
||||
willWrite,
|
||||
wrote: willWrite && result.hasChanges,
|
||||
hasChanges: result.hasChanges,
|
||||
issues: result.issues,
|
||||
plan: result.plan
|
||||
};
|
||||
}
|
||||
|
||||
export type DeleteEnvFileKeysResult = {
|
||||
file: string;
|
||||
keys: string[];
|
||||
willWrite: boolean;
|
||||
wrote: boolean;
|
||||
hasChanges: boolean;
|
||||
issues: DotenvIssue[];
|
||||
plan: KeyMutationPlanItem[];
|
||||
};
|
||||
|
||||
export async function deleteEnvFileKeys(options: {
|
||||
file: string;
|
||||
keys: readonly string[];
|
||||
write?: boolean;
|
||||
}): Promise<DeleteEnvFileKeysResult> {
|
||||
const contents = await readFile(options.file, 'utf8');
|
||||
const result = deleteDotenvKeys({ contents, keys: options.keys });
|
||||
|
||||
const willWrite = options.write === true;
|
||||
if (willWrite && result.hasChanges) {
|
||||
await writeTextFileAtomic(options.file, result.output);
|
||||
}
|
||||
|
||||
return {
|
||||
file: options.file,
|
||||
keys: [...options.keys],
|
||||
willWrite,
|
||||
wrote: willWrite && result.hasChanges,
|
||||
hasChanges: result.hasChanges,
|
||||
issues: result.issues,
|
||||
plan: result.plan
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user