193 lines
4.9 KiB
TypeScript
193 lines
4.9 KiB
TypeScript
import fs from 'fs-extra';
|
|
import path from 'path';
|
|
// import { prompt, Question} from 'inquirer';
|
|
import inquirer from 'inquirer';
|
|
import chalk from 'chalk';
|
|
|
|
|
|
const COMPLETED = 'SELECTION_COMPLETED';
|
|
const CANCELLED = 'SELECTION_CANCELLED';
|
|
const CHECKMARK = '\u2713';
|
|
|
|
class FilesSystemService {
|
|
directories(directoryPath, directoryFilter ?: (joinedPath) => true) {
|
|
return fs.readdirSync(directoryPath).filter((name) => {
|
|
const joinedPath = path.join(directoryPath, name);
|
|
return this.isDirectory(joinedPath) && directoryFilter(joinedPath);
|
|
});
|
|
}
|
|
|
|
files(directoryPath, fileFilter = (joinedPath) => true) {
|
|
return fs.readdirSync(directoryPath).filter((name) => {
|
|
const joinedPath = path.join(directoryPath, name);
|
|
return this.isFile(joinedPath) && fileFilter(joinedPath);
|
|
});
|
|
}
|
|
|
|
isDirectory(directoryPath) {
|
|
return fs.statSync(directoryPath).isDirectory();
|
|
}
|
|
|
|
isFile(filePath) {
|
|
return fs.statSync(filePath).isFile();
|
|
}
|
|
}
|
|
|
|
class FilesSelectionService extends Set {
|
|
lastFileSelected = null;
|
|
constructor(selectedFiles) {
|
|
super(selectedFiles);
|
|
}
|
|
|
|
get selectedFiles() {
|
|
return Array.from(this);
|
|
}
|
|
|
|
isSelected(file) {
|
|
return this.has(file);
|
|
}
|
|
|
|
selectFile(file) {
|
|
this.add(file);
|
|
this.lastFileSelected = file;
|
|
}
|
|
|
|
removeFile(file) {
|
|
this.delete(file);
|
|
}
|
|
}
|
|
|
|
class LocationService {
|
|
constructor(public currentPath) {
|
|
this.currentPath = currentPath;
|
|
}
|
|
}
|
|
|
|
class OptionsService {
|
|
constructor(public options) {
|
|
this.options = { ...this.defaultOptions, ...options };
|
|
}
|
|
|
|
get defaultOptions() {
|
|
return {
|
|
directoryFilter: () => true,
|
|
fileFilter: () => true,
|
|
root: process.cwd(),
|
|
startingPath: process.cwd(),
|
|
multi: true,
|
|
pageSize: 10,
|
|
selectedFiles: [],
|
|
clearConsole: true,
|
|
};
|
|
}
|
|
}
|
|
|
|
export const selectFiles = function (options = {}) {
|
|
const optionsService = new OptionsService(options);
|
|
const locationService = new LocationService(
|
|
optionsService.options.startingPath
|
|
);
|
|
const fileSystemService = new FilesSystemService();
|
|
const filesSelectionService = new FilesSelectionService(
|
|
optionsService.options.selectedFiles
|
|
);
|
|
|
|
return new Promise((resolve):FCResult|void => {
|
|
(async function promptUserToSelectFiles() {
|
|
const directories = fileSystemService.directories(
|
|
locationService.currentPath,
|
|
optionsService.options.directoryFilter
|
|
);
|
|
|
|
if (locationService.currentPath !== optionsService.options.root) {
|
|
directories.unshift('..');
|
|
}
|
|
|
|
const files = fileSystemService.files(
|
|
locationService.currentPath,
|
|
optionsService.options.fileFilter
|
|
);
|
|
|
|
const choices = [
|
|
...directories.map((directoryName) => {
|
|
const value = path.join(locationService.currentPath, directoryName);
|
|
const name = chalk.yellow(directoryName);
|
|
return { value, name };
|
|
}),
|
|
...files.map((fileName) => {
|
|
const value = path.join(locationService.currentPath, fileName);
|
|
const name = `${fileName} ${
|
|
filesSelectionService.isSelected(value)
|
|
? chalk.green(CHECKMARK)
|
|
: ''
|
|
}`;
|
|
return { value, name };
|
|
}),
|
|
];
|
|
|
|
if (filesSelectionService.selectedFiles.length) {
|
|
choices.push({
|
|
name: chalk.green('-- File Selection Complete --'),
|
|
value: COMPLETED,
|
|
});
|
|
}
|
|
|
|
choices.push({
|
|
name: chalk.red('-- Cancel File Selection --'),
|
|
value: CANCELLED,
|
|
});
|
|
|
|
if (optionsService.options.clearConsole) {
|
|
console.clear();
|
|
}
|
|
|
|
const { selection } = await inquirer.prompt([
|
|
{
|
|
type: 'list',
|
|
message: `Select file(s) in ${locationService.currentPath}`,
|
|
name: 'selection',
|
|
pageSize: optionsService.options.pageSize,
|
|
choices,
|
|
default: () => filesSelectionService.lastFileSelected,
|
|
},
|
|
]);
|
|
|
|
if (optionsService.options.clearConsole) {
|
|
console.clear();
|
|
}
|
|
|
|
if (selection === COMPLETED || selection === CANCELLED) {
|
|
return resolve({
|
|
selectedFiles: filesSelectionService.selectedFiles,
|
|
status: selection,
|
|
});
|
|
} else if (!optionsService.options.multi) {
|
|
return resolve({
|
|
selectedFiles: [selection],
|
|
status: COMPLETED,
|
|
});
|
|
}
|
|
|
|
if (fileSystemService.isDirectory(selection)) {
|
|
locationService.currentPath = selection;
|
|
} else {
|
|
if (filesSelectionService.isSelected(selection)) {
|
|
filesSelectionService.removeFile(selection);
|
|
} else {
|
|
filesSelectionService.selectFile(selection);
|
|
}
|
|
}
|
|
|
|
promptUserToSelectFiles();
|
|
})();
|
|
});
|
|
};
|
|
export type FCResult = {
|
|
selectedFiles:Array<string>
|
|
status:'SELECTION_COMPLETED'|'SELECTION_CANCELLED'
|
|
}
|
|
// const exports = {
|
|
// COMPLETED,
|
|
// CANCELLED,
|
|
// selectFiles,
|
|
// };
|