isbn-bisac-tools
Version:
A toolkit for working with BISAC subject headings and ISBN lookups
139 lines • 5.64 kB
JavaScript
import { promises as fs } from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import { spawn } from 'child_process';
import inquirer from 'inquirer';
import { glob } from 'glob';
import chalk from 'chalk';
// Get the current directory
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const outputDir = path.join(__dirname, '..', 'output');
/**
* Browse JSON files in the output directory
* @param customOutputDir Optional custom output directory path
* @returns Promise resolving to true if successful, false otherwise
*/
async function browseJsonFiles(customOutputDir) {
const targetDir = customOutputDir || outputDir;
try {
// Ensure the output directory exists
await fs.mkdir(targetDir, { recursive: true });
// Find all JSON files, prioritizing bisac-data.json if it exists
const bisacDataPath = path.join(targetDir, 'bisac-data.json');
let bisacDataExists = false;
try {
await fs.access(bisacDataPath);
bisacDataExists = true;
}
catch {
// File doesn't exist, will search for other JSON files
}
// If bisac-data.json exists, use only that, otherwise find all JSON files
const files = bisacDataExists ? [bisacDataPath] : await glob(`${targetDir}/*.json`);
if (files.length === 0) {
console.error(chalk.red('❌ No JSON files found in the output directory'));
return false;
}
// Get file stats for modification time sorting
const fileStats = await Promise.all(files.map(async (filePath) => {
const stats = await fs.stat(filePath);
return {
path: filePath,
mtime: stats.mtime,
};
}));
// Sort files by modification time (newest first)
const sortedFiles = fileStats.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
// Format choices for display
const fileChoices = await Promise.all(sortedFiles.map(async (file) => {
// Try to read the file to check if it's the new format with timestamp
try {
const content = await fs.readFile(file.path, 'utf8');
const data = JSON.parse(content);
// If it's the new format with metadata
if (data.timestamp && data.date) {
const date = new Date(data.timestamp);
return {
name: `${path.basename(file.path)} (From: ${data.date}, Generated: ${date.toLocaleTimeString()})`,
value: file.path,
};
}
}
catch {
// If parsing fails, fall back to using file stats
}
// Default to using file stats for display
return {
name: `${path.basename(file.path)} (${file.mtime.toLocaleDateString()} ${file.mtime.toLocaleTimeString()})`,
value: file.path,
};
}));
// Prompt for file selection
const { selectedFile } = await inquirer.prompt([
{
type: 'list',
name: 'selectedFile',
message: 'Select a JSON file to browse:',
choices: fileChoices,
pageSize: 15,
},
]);
console.log(chalk.green(`📂 Opening ${path.basename(selectedFile)} with fx...`));
// Read the file content
const fileContent = await fs.readFile(selectedFile, 'utf8');
const jsonData = JSON.parse(fileContent);
// For new format with categories, use the categories array for display
// Otherwise use the original content
const displayContent = jsonData.categories
? JSON.stringify({
...jsonData,
// Display first 3 categories in preview, with count of total
categories: jsonData.categories.length > 3
? [
...jsonData.categories.slice(0, 3),
`... ${jsonData.categories.length - 3} more categories`,
]
: jsonData.categories,
}, null, 2)
: fileContent;
// Use spawn to open fx with the selected file
const fx = spawn('npx', ['fx'], {
stdio: ['pipe', 'inherit', 'inherit'],
cwd: process.cwd(),
});
// Write the processed content to fx's stdin
fx.stdin?.write(displayContent);
fx.stdin?.end();
// Handle process completion
return new Promise(resolve => {
fx.on('close', code => {
if (code === 0) {
resolve(true);
}
else {
console.error(chalk.red(`❌ fx exited with code ${code}`));
resolve(false);
}
});
});
}
catch (error) {
console.error(chalk.red(`❌ Error browsing JSON files: ${error.message}`));
return false;
}
}
// Execute the function when this module is run directly
// This handles ESM modules where require.main is not available
const isMainModule = import.meta.url.endsWith(process.argv[1].replace(/^file:\/\//, ''));
if (isMainModule) {
browseJsonFiles()
.then(success => {
process.exit(success ? 0 : 1);
})
.catch((error) => {
console.error(chalk.red(`Error: ${error.message}`));
process.exit(1);
});
}
export { browseJsonFiles };
//# sourceMappingURL=browse-json.js.map