Search code examples
javascriptnode.jschokidar

How to detect changes in the contents of a file, using Regex and Chokidar


I would like to run a JS function when a specific section of a file changes. The contents that are being watched should be selected by Regex.

As far as I have seen, libraries like Chokidar can only detect changes to a file directly and do not provide information about the contents of the file before and after the changes.


Solution

  • I ended up creating a slightly adjusted version of Prashant Pokhriyal's answer.

    const fs = require('fs');
    const chokidar = require('chokidar');
    
    const watchForFileContentChanges = (path, regex, callback) => {
        const regexFileContents = new Map();
    
        const registerFileContentMatches = (filePath) => {
            const currentFileContent = fs.readFileSync(filePath, 'utf8');
            const currentFileMatches = currentFileContent.match(regex);
            if (currentFileMatches === null) return;
            regexFileContents.set(filePath, currentFileMatches);
        }
    
        const handleContentChanges = (filePath) => {
            const previousFileMatches = regexFileContents.get(filePath);
            const hasFileBeenReadBefore = previousFileMatches !== undefined;
    
            const currentFileContent = fs.readFileSync(filePath, 'utf8');
            const currentFileMatches = currentFileContent.match(regex);
    
            if (hasFileBeenReadBefore === false) {
                regexFileContents.set(filePath, currentFileMatches);
                if (currentFileMatches === null) return;
                callback();
                return;
            }
    
            const haveFileMatchesChanged = JSON.stringify(previousFileMatches) !== JSON.stringify(currentFileMatches);
    
            if (haveFileMatchesChanged === false) return;
    
            regexFileContents.set(filePath, currentFileMatches);
            callback();
        }
    
        const handleFileRemoval = (filePath) => {
            regexFileContents.delete(filePath);
        }
    
        chokidar.watch(path)
            .on('add', registerFileContentMatches)
            .on('change', handleContentChanges)
            .on('unlink', handleFileRemoval);
    }
    
    watchForFileContentChanges('output/*.txt', /foo/g, () => {
        console.log('foo changed');
    });