legal-markdown-js
Version:
Node.js implementation of LegalMarkdown for processing legal documents with markdown and YAML - Complete feature parity with Ruby version
191 lines ⢠7.46 kB
JavaScript
/**
* File selection prompt for Interactive CLI
*
* This module handles the file selection process, providing users with
* options to select from discovered files, browse directories, or
* manually enter file paths.
*
* @module
*/
import { select } from '@inquirer/prompts';
import chalk from 'chalk';
import * as fs from 'fs';
import * as path from 'path';
import { RESOLVED_PATHS } from '../../../constants/index.js';
import { scanDirectory } from '../utils/file-scanner.js';
import { formatWarningMessage } from '../utils/format-helpers.js';
import { handleFirstTimeUserExperience } from './ftux-handler.js';
import { handleBrowseFolder, handleManualInput } from '../utils/file-input-helpers.js';
import { getEnvFilePath } from '../utils/installation-detector.js';
/** Option for browsing alternative directories */
const BROWSE_OPTION = 'š Browse other folder...';
/** Option for manual path entry */
const MANUAL_OPTION = 'š Enter path manually...';
/** Option for exiting the application */
const EXIT_OPTION = 'ā Exit';
/**
* Check if a directory exists and is accessible
*
* @param dirPath - Path to check
* @returns True if directory exists and is accessible
*/
function isDirectoryAccessible(dirPath) {
try {
return fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory();
}
catch {
return false;
}
}
/**
* Check if configuration is properly set up
*
* @returns True if .env exists in the correct location and input directory is configured and accessible
*/
function isConfigurationValid() {
// Check if .env exists in the expected installation-specific location
const expectedEnvPath = getEnvFilePath();
const hasCorrectEnvFile = fs.existsSync(expectedEnvPath);
if (!hasCorrectEnvFile) {
// Fallback: check if there's a .env in the current working directory
const localEnvPath = path.join(process.cwd(), '.env');
const hasLocalEnvFile = fs.existsSync(localEnvPath);
if (!hasLocalEnvFile) {
return false;
}
// If local .env exists, reload environment variables from it
try {
const envContent = fs.readFileSync(localEnvPath, 'utf8');
const envVars = envContent
.split('\n')
.filter(line => line.trim() && !line.startsWith('#'))
.reduce((vars, line) => {
const [key, ...valueParts] = line.split('=');
if (key && valueParts.length > 0) {
// Remove quotes if present
let value = valueParts.join('=').trim();
if ((value.startsWith('"') && value.endsWith('"')) ||
(value.startsWith("'") && value.endsWith("'"))) {
value = value.slice(1, -1);
}
vars[key.trim()] = value;
}
return vars;
}, {});
// Check if DEFAULT_INPUT_DIR is configured and accessible in local .env
const localInputDir = envVars.DEFAULT_INPUT_DIR;
if (!localInputDir) {
return false;
}
return isDirectoryAccessible(path.resolve(localInputDir));
}
catch {
return false;
}
}
// Check if the configured input directory is accessible
return isDirectoryAccessible(RESOLVED_PATHS.DEFAULT_INPUT_DIR);
}
/**
* Prompt user for initial setup choice when configuration is missing/invalid
*/
async function promptInitialSetup() {
console.log(chalk.yellow('\nā ļø Configuration Setup Needed'));
console.log(chalk.gray('No valid configuration detected or input directory is not accessible.\n'));
const choice = await select({
message: 'How would you like to proceed?',
choices: [
{
name: 'š ļø Run First-Time User Experience (recommended)',
value: 'ftux',
description: 'Set up directories, try examples, and get guided help',
},
{
name: 'ā” Continue with defaults (current directory)',
value: 'defaults',
description: 'Use current directory as input, no configuration saved',
},
],
});
return choice;
}
/**
* Handle file selection logic
*/
async function handleFileSelection(selectedFile) {
switch (selectedFile) {
case BROWSE_OPTION:
return await handleBrowseFolder();
case MANUAL_OPTION:
return await handleManualInput();
case EXIT_OPTION:
console.log(chalk.yellow('š Goodbye!'));
process.exit(0);
break;
default:
return selectedFile;
}
}
/**
* Prompt user to select an input file
*
* Initiates the file selection process by first checking if configuration is valid.
* If not, offers FTUX or defaults. Then scans the input directory and presents
* available files to the user, with fallback options for manual input.
*
* @returns Promise resolving to the absolute path of the selected input file
* @throws Error when user cancels or no valid file is selected
*/
export async function selectInputFile() {
// Check if configuration is valid first
if (!isConfigurationValid()) {
const setupChoice = await promptInitialSetup();
if (setupChoice === 'ftux') {
return await handleFirstTimeUserExperience();
}
// Continue with defaults - scan current directory instead
console.log(chalk.cyan('\nš Using current directory as input...\n'));
const currentDirFiles = scanDirectory(process.cwd(), process.cwd());
if (currentDirFiles.length === 0) {
console.log(formatWarningMessage('No supported files found in current directory.'));
return await handleFirstTimeUserExperience();
}
// Show files from current directory
const choices = [
...currentDirFiles.map(file => ({
name: file.name,
value: file.path,
})),
{ name: BROWSE_OPTION, value: BROWSE_OPTION },
{ name: MANUAL_OPTION, value: MANUAL_OPTION },
{ name: EXIT_OPTION, value: EXIT_OPTION },
];
const selectedFile = await select({
message: 'Select a file from current directory:',
choices,
});
return await handleFileSelection(selectedFile);
}
// Configuration is valid - use configured directory
console.log(chalk.cyan(`š Searching for files in: ${RESOLVED_PATHS.DEFAULT_INPUT_DIR}\n`));
const files = scanDirectory(RESOLVED_PATHS.DEFAULT_INPUT_DIR, RESOLVED_PATHS.DEFAULT_INPUT_DIR);
if (files.length === 0) {
console.log(formatWarningMessage('No supported files found in the configured directory.'));
return await handleFirstTimeUserExperience();
}
const choices = [
...files.map(file => ({
name: file.name,
value: file.path,
})),
{ name: BROWSE_OPTION, value: BROWSE_OPTION },
{ name: MANUAL_OPTION, value: MANUAL_OPTION },
{ name: EXIT_OPTION, value: EXIT_OPTION },
];
const selectedFile = await select({
message: 'Select an input file:',
choices,
});
return await handleFileSelection(selectedFile);
}
//# sourceMappingURL=file-selector.js.map