bizmatch-project/crawler/filechooser.ts

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,
// };