@ghii/yaml-loader
Version:
A Funny yaml loader for ghii configuration manager
113 lines • 4.43 kB
JavaScript
import { existsSync } from 'node:fs';
import { readFile, stat } from 'node:fs/promises';
import path from 'node:path';
import yaml from 'js-yaml';
/**
* Creates a YAML file loader function for use with GHII configuration manager.
*
* This function generates a loader that reads and parses a YAML file from the filesystem.
* The loader supports customizable error handling and logging, making it suitable for
* various deployment scenarios where configuration files may or may not be present.
*
* @template T - The expected shape of the configuration object. Must extend `Record<string, unknown>`.
* Defaults to `Record<string, unknown>` if not specified.
*
* @param options - Configuration options for the loader.
* @param options.throwOnError - If `true`, throws errors when file operations fail.
* If `false` (default), returns an empty object `{}` on errors.
* @param options.logger - Custom logging function called when errors occur.
* Receives the error object and a message string.
* Defaults to `console.log(message, err)`.
* @param filePathToken - Variable number of path segments that will be joined together
* to form the absolute file path using `path.join()`.
* Example: `yamlLoader(options, '/path/to', 'config.yaml')`
*
* @returns A `Loader` function that returns a Promise resolving to the parsed YAML content.
* The loader will:
* - Return the parsed YAML as a typed object `T` on success
* - Throw an error if `throwOnError: true` and an error occurs
* - Return `{}` (typed as `T`) if `throwOnError: false` and an error occurs
*
* @example
* ```typescript
* // Basic usage with error throwing
* const loader = yamlLoader(
* { throwOnError: true },
* __dirname,
* 'config.yaml'
* );
* const config = await loader();
*
* // Usage with custom logger
* const loader = yamlLoader(
* {
* throwOnError: false,
* logger: (err, msg) => console.error(msg, err),
* },
* __dirname,
* 'config.yaml'
* );
*
* // Type-safe usage
* interface AppConfig {
* database: { host: string; port: number };
* }
* const loader = yamlLoader<AppConfig>(
* { throwOnError: true },
* __dirname,
* 'config.yaml'
* );
* const config = await loader(); // typed as AppConfig
* ```
*/
export default function yamlLoader({ throwOnError, logger = (err, message) => console.log(message, err), }, ...filePathToken) {
const sourcePath = path.join(...filePathToken);
/**
* Internal loader function that performs the actual file reading and YAML parsing.
*
* @returns Promise that resolves to the parsed YAML content as type T
* @throws Error if `throwOnError` is true and file operations fail
*/
return async function yamlFileLoader() {
// Check if file exists synchronously before attempting to read
if (!existsSync(sourcePath)) {
logger({
msg: 'not exist',
}, `${sourcePath} 404`);
if (throwOnError)
throw new Error(`${sourcePath} 404`);
// Return empty object if throwOnError is false
return {};
}
try {
// Verify that the path points to a file, not a directory
const fstat = await stat(sourcePath);
if (fstat.isFile()) {
// Read and parse the YAML file
const yamlContent = await readFile(sourcePath, {
encoding: 'utf8',
});
return yaml.load(yamlContent);
}
// Path exists but is not a file (likely a directory)
const msg = `Source ${sourcePath} is not a file`;
logger({
msg,
}, msg);
if (throwOnError) {
throw new Error(msg);
}
return {};
}
catch (err) {
// Handle cases where file is deleted after loader creation or other I/O errors
const msg = `FILE DELETED OR A DIRECTORY-> ${sourcePath} 404: ${err instanceof Error ? err.message : ''}`;
logger(err, msg);
if (throwOnError)
throw new Error(msg);
return {};
}
};
}
export { yamlLoader };
//# sourceMappingURL=yaml-loader.js.map