Files
shopApiNg/src/utils/file-sync-utils.js

135 lines
3.8 KiB
JavaScript

import fs from 'fs/promises';
import path from 'path';
/**
* File synchronization utility functions
*/
/**
* Get existing IDs from files in a directory
* @param {string} dir - Directory path
* @param {Object} options - Configuration options
* @param {string} options.prefix - File prefix to filter (e.g., 'category_')
* @param {string} options.suffix - File suffix to filter (e.g., '.json')
* @param {RegExp} options.pattern - Custom regex pattern to extract ID
* @returns {Promise<number[]>} - Array of numeric IDs
*/
export async function getExistingIds(dir, options = {}) {
const { prefix = '', suffix = '', pattern = null } = options;
let existingFiles = [];
try {
existingFiles = await fs.readdir(dir);
} catch (err) {
// Directory might be empty or new
return [];
}
if (pattern) {
return existingFiles
.map(f => {
const match = f.match(pattern);
return match ? parseInt(match[1]) : null;
})
.filter(id => id !== null && !isNaN(id));
}
return existingFiles
.filter(f => {
if (prefix && !f.startsWith(prefix)) return false;
if (suffix && !f.endsWith(suffix)) return false;
return true;
})
.map(f => {
let id = f;
if (prefix) id = id.replace(prefix, '');
if (suffix) id = id.replace(suffix, '');
return parseInt(id);
})
.filter(id => !isNaN(id));
}
/**
* Delete obsolete files based on valid IDs
* @param {string} dir - Directory path
* @param {number[]} existingIds - IDs of existing files
* @param {Set<number>} validIds - Set of valid IDs to keep
* @param {Function} filenameFn - Function to generate filename from ID
* @returns {Promise<number>} - Number of files deleted
*/
export async function deleteObsoleteFiles(dir, existingIds, validIds, filenameFn) {
const toDelete = existingIds.filter(id => !validIds.has(id));
for (const id of toDelete) {
const filePath = path.join(dir, filenameFn(id));
await fs.unlink(filePath);
}
if (toDelete.length > 0) {
console.log(`🗑️ Deleted ${toDelete.length} obsolete files.`);
}
return toDelete.length;
}
/**
* Write JSON to file only if content has changed
* @param {string} filePath - Full path to file
* @param {*} data - Data to write (will be JSON.stringify'd)
* @param {number} indent - JSON indentation (default: 2)
* @returns {Promise<boolean>} - True if file was written, false if unchanged
*/
export async function writeJsonIfChanged(filePath, data, indent = 2) {
const newContent = JSON.stringify(data, null, indent);
let oldContent = '';
try {
oldContent = await fs.readFile(filePath, 'utf-8');
} catch (e) {
// File doesn't exist yet
}
if (oldContent !== newContent) {
await fs.writeFile(filePath, newContent);
return true;
}
return false;
}
/**
* Ensure directory exists, create if it doesn't
* @param {string} dir - Directory path
* @returns {Promise<void>}
*/
export async function ensureDir(dir) {
await fs.mkdir(dir, { recursive: true });
}
/**
* Read JSON file safely
* @param {string} filePath - Full path to file
* @returns {Promise<*|null>} - Parsed JSON or null if file doesn't exist
*/
export async function readJsonFile(filePath) {
try {
const content = await fs.readFile(filePath, 'utf-8');
return JSON.parse(content);
} catch (err) {
return null;
}
}
/**
* Read text file safely
* @param {string} filePath - Full path to file
* @returns {Promise<string|null>} - File content or null if file doesn't exist
*/
export async function readTextFile(filePath) {
try {
return await fs.readFile(filePath, 'utf-8');
} catch (err) {
return null;
}
}