tools/file/src/path.js

/**
* @module @svizzle/file/path
*/

import path from 'node:path';

import * as _ from 'lamb';

/**
 * Return the extension of the provided file path
 * [node environment]
 *
 * @function
 * @arg {string} filepath
 * @return {string} - the extension of the file path
 *
 * @example
> getPathExt('foo/bar.txt')
'txt'
> getPathExt('foo/bar.todo.md')
'md'
 *
 * @since 0.11.0
 */
export const getPathExt =
	filepath => path.parse(filepath).ext.slice(1);

/**
 * Detect if a file name has one of the provided extensions.
 * [node environment]
 *
 * @function
 * @arg {array} extensions - An array of extensions
 * @return {boolean}
 *
 * @example
> isJsonOrGeojson = hasAnyExtensionOf(['.json', '.geojson'])
> isJsonOrGeojson('file.json')
true
> isJsonOrGeojson('file.geojson')
true
> isJsonOrGeojson('file.csv')
false
 *
 * @since 0.4.0
 */
export const hasAnyExtensionOf = extensions =>
	fileName => extensions.includes(path.extname(fileName));

/**
 * Filter an array of file names to contain only those with extension .json or .geojson.
 * [node environment]
 *
 * @function
 * @arg {array} extensions - Array of file names
 * @return {array}
 *
 * @example
> filterJsonExtensions(['file.json', 'file.geojson', 'file.csv'])
['file.json', 'file.geojson']
 *
 * @since 0.4.0
 */
export const filterJsonExtensions =
	_.filterWith(hasAnyExtensionOf(['.json', '.geojson']));

/**
 * Return a function that returns true if the input file name has the provided extension
 * [node environment]
 *
 * @function
 * @arg {string} extension
 * @return {boolean}
 *
 * @example
> isJson = isFileWithExt('json')
> isJson('file.json')
true
> isJson('file.txt')
false
 *
 * @since 0.11.0
 */
export const isFileWithExt = ext => _.pipe([getPathExt, _.is(ext)]);

/**
 * Return a function expecting a filepath and returning it renamed to the provided extension.
 * Note that if the original provided filepath has multiple extensions only the last one gets changed.
 * [node environment]
 *
 * @function
 * @arg {string} extension - file extension, including the dot (`.txt`, `.csv`, etc)
 * @return {function} - String -> String
 *
 * @example
> renameToJson = renameToExtension('.json')
> renameToJson('file.txt')
'file.json'
> renameToJson('file.min.js')
'file.txt'
 *
 * @since 0.4.0
 */
export const renameToExtension = ext => _.pipe([
	path.parse,
	_.skip(['base']), // [1]
	obj => ({...obj, ext}),
	path.format
]);

// [1]
// 'pathObject.ext and pathObject.name are ignored if pathObject.base exists'
// https://nodejs.org/api/path.html#path_path_format_pathobject

/*
// version not using node's path
const renameToExtension = ext => filepath => {
	const split = filepath.split('.');
	const oldExt = `.${split[split.length - 1]}`;
	// const oldExt = `.${_.last(split)}`;
	// not usable in dev utils to avoid depending on lamb for now

	return filepath.replace(oldExt, ext);
}
*/


/**
 * Return a function expecting a filename and returning it resolved to
 * the provided directory path
 * [node environment]
 *
 * @function
 * @arg {string} dirPath - path of the dir to resolve to
 * @return {function} - String -> String
 *
 * @example
> resolve = resolveToDir('/output/dir/');

> resolve('file1.txt')
'/output/dir/file1.txt'

> resolve('file2.txt')
'/output/dir/file2.txt'
 *
 * @since 0.10.0
 */
export const resolveToDir =
	dirPath => filename => path.resolve(dirPath, filename);


// no need to test the utils below

export const isCsvFile = isFileWithExt('csv');
export const isJsonFile = isFileWithExt('json');
export const isTsvFile = isFileWithExt('tsv');
export const isYamlFile = hasAnyExtensionOf(['.yaml', '.yml']);