grunt-ps-sass
Version:
GruntJS plugin to compile Sass files
185 lines (163 loc) • 5.65 kB
JavaScript
const fs = require('fs');
/**
* Service for detecting file changes based on timestamps
* This service is focused solely on change detection - no dependency resolution
*/
class FileChangeDetector {
constructor(options = {}) {
this.verbose = options.verbose || false;
}
/**
* Check if any files in the array have been modified after the given timestamp
* @param {Array<string>} filePaths - Array of file paths to check
* @param {number|Date} baseTimestamp - Timestamp to compare against (can be number or Date)
* @param {Object} options - Optional configuration
* @returns {Object} Result object with change information
*/
checkForChanges(filePaths, baseTimestamp, options = {}) {
const result = {
hasChanges: false,
changedFiles: [],
errors: [],
stats: {
totalFiles: filePaths.length,
checkedFiles: 0,
errorFiles: 0
}
};
// Convert timestamp to number if it's a Date
const timestamp = baseTimestamp instanceof Date ? baseTimestamp.getTime() : baseTimestamp;
if (this.verbose) {
console.log(`Checking ${filePaths.length} files for changes since ${new Date(timestamp).toISOString()}`);
}
for (const filePath of filePaths) {
try {
const stats = fs.statSync(filePath);
result.stats.checkedFiles++;
if (stats.mtime.getTime() > timestamp) {
result.hasChanges = true;
result.changedFiles.push({
path: filePath,
modifiedTime: stats.mtime,
size: stats.size
});
if (this.verbose) {
console.log(` Changed: ${filePath} (${stats.mtime.toISOString()})`);
}
}
} catch (err) {
result.stats.errorFiles++;
result.errors.push({
path: filePath,
error: err.message
});
if (this.verbose) {
console.warn(` Error checking ${filePath}: ${err.message}`);
}
}
}
if (this.verbose) {
console.log(`Change detection complete: ${result.changedFiles.length} changed files found`);
}
return result;
}
/**
* Check if a single file has been modified after the given timestamp
* @param {string} filePath - Path to the file to check
* @param {number|Date} baseTimestamp - Timestamp to compare against
* @returns {boolean} True if the file has been modified after the timestamp
*/
hasFileChanged(filePath, baseTimestamp) {
try {
const stats = fs.statSync(filePath);
const timestamp = baseTimestamp instanceof Date ? baseTimestamp.getTime() : baseTimestamp;
return stats.mtime.getTime() > timestamp;
} catch (err) {
if (this.verbose) {
console.warn(`Error checking file ${filePath}: ${err.message}`);
}
return false;
}
}
/**
* Get the modification time of a file
* @param {string} filePath - Path to the file
* @returns {Date|null} Modification time or null if error
*/
getModificationTime(filePath) {
try {
const stats = fs.statSync(filePath);
return stats.mtime;
} catch (err) {
if (this.verbose) {
console.warn(`Error getting modification time for ${filePath}: ${err.message}`);
}
return null;
}
}
/**
* Get the latest modification time from an array of files
* @param {Array<string>} filePaths - Array of file paths
* @returns {Date|null} Latest modification time or null if no valid files
*/
getLatestModificationTime(filePaths) {
let latestTime = null;
for (const filePath of filePaths) {
try {
const stats = fs.statSync(filePath);
if (!latestTime || stats.mtime > latestTime) {
latestTime = stats.mtime;
}
} catch (err) {
if (this.verbose) {
console.warn(`Error checking ${filePath}: ${err.message}`);
}
}
}
return latestTime;
}
/**
* Compare modification times of two files
* @param {string} file1Path - Path to first file
* @param {string} file2Path - Path to second file
* @returns {number} -1 if file1 is older, 1 if file1 is newer, 0 if equal, null if error
*/
compareFiles(file1Path, file2Path) {
try {
const stats1 = fs.statSync(file1Path);
const stats2 = fs.statSync(file2Path);
if (stats1.mtime < stats2.mtime) return -1;
if (stats1.mtime > stats2.mtime) return 1;
return 0;
} catch (err) {
if (this.verbose) {
console.warn(`Error comparing files: ${err.message}`);
}
return null;
}
}
/**
* Filter files that have been modified after a given timestamp
* @param {Array<string>} filePaths - Array of file paths to filter
* @param {number|Date} baseTimestamp - Timestamp to compare against
* @returns {Array<string>} Array of file paths that have been modified
*/
filterChangedFiles(filePaths, baseTimestamp) {
const timestamp = baseTimestamp instanceof Date ? baseTimestamp.getTime() : baseTimestamp;
const changedFiles = [];
for (const filePath of filePaths) {
try {
const stats = fs.statSync(filePath);
if (stats.mtime.getTime() > timestamp) {
changedFiles.push(filePath);
}
} catch (err) {
if (this.verbose) {
console.warn(`Error checking ${filePath}: ${err.message}`);
}
}
}
return changedFiles;
}
}
module.exports = FileChangeDetector;