<commit_before>"use strict";

var fs   = require("fs"),
    path = require("path"),

    through = require("through2"),
    sink    = require("sink-transform"),
    mkdirp  = require("mkdirp"),

    each    = require("lodash.foreach"),
    
    Processor = require("modular-css-core"),
    relative  = require("modular-css-core/lib/relative.js"),
    output    = require("modular-css-core/lib/output.js");

module.exports = function(browserify, opts) {
    var options = Object.assign(Object.create(null), {
            ext : ".css",
            map : browserify._options.debug,
            cwd : browserify._options.basedir || process.cwd()
        }, opts),
        
        processor = new Processor(options),
        
        bundler, bundles, handled;
    
    if(!options.ext || options.ext.charAt(0) !== ".") {
        return browserify.emit("error", "Missing or invalid \"ext\" option: " + options.ext);
    }
    
    function depReducer(curr, next) {
        curr[relative.prefixed(options.cwd, next)] = next;
        
        return curr;
    }

    browserify.transform(function(file) {
        if(path.extname(file) !== options.ext) {
            return through();
        }
        
        return sink.str(function(buffer, done) {
            var push = this.push.bind(this),
                real = fs.realpathSync(file);
            
            processor.string(real, buffer).then(
                function(result) {
                    // Tell watchers about dependencies by emitting "file" events
                    // AFAIK this is only useful to watchify, to ensure that it watches
                    // everyone in the dependency graph
                    processor.dependencies(result.id).forEach(function(id) {
                        browserify.emit("file", path.resolve(process.cwd(), id), id);
                    });
                    
                    push("module.exports = " + JSON.stringify(output.join(result.exports), null, 4) + ";");
                    
                    done();
                },

                function(error) {
                    // Thrown from the current bundler instance, NOT the main browserify
                    // instance. This is so that watchify won't explode.
                    bundler.emit("error", error);
                    
                    push(buffer);
                    
                    done();
                }
            );
        });
    });
    
    // Splice ourselves as early as possible into the deps pipeline
    browserify.pipeline.get("deps").splice(1, 0, through.obj(function(row, enc, done) {
        if(path.extname(row.file) !== options.ext) {
            return done(null, row);
        }
        
        handled[row.id] = true;
        
        // Ensure that browserify knows about the CSS dependency tree by updating
        // any referenced entries w/ their dependencies
        row.deps = processor.dependencies(row.file).reduce(depReducer, {});
        
        return done(null, row);
    }, function(done) {
        // Ensure that any CSS dependencies not directly referenced are
        // injected into the stream of files being managed
        var push = this.push.bind(this);
        
        processor.dependencies().forEach(function(dep) {
            if(dep in handled) {
                return;
            }
            
            push({
                id     : dep,
                file   : dep,
                source : "module.exports = " + JSON.stringify(output.join(processor.files[dep].exports), null, 4) + ";",
                deps   : processor.dependencies(dep).reduce(depReducer, {})
            });
        });
        
        done();
    }));
    
    // Keep tabs on factor-bundle organization
    browserify.on("factor.pipeline", function(file, pipeline) {
        bundles[file] = [];

        // Track the files in each bundle so we can determine commonalities
        // Doesn't actually modify the file, just records it
        pipeline.unshift(through.obj(function(obj, enc, done) {
            if(path.extname(obj.file) === options.ext) {
                bundles[file].unshift(obj.file);
            }

            done(null, obj);
        }));
    });

    // Watchify fires update events when files change, this tells the processor
    // to remove the changed files from its cache so they will be re-processed
    browserify.on("update", function(files) {
        processor.remove(files);
    });
    
    return browserify.on("bundle", function(current) {
        // Calls to .bundle() means we should recreate anything tracking bundling progress
        // in case things have changed out from under us, like when using watchify
        bundles = {};
        handled = {};
        
        bundler = current;
        
        // Listen for bundling to finish
        bundler.on("end", function() {<commit_msg>feat: add ability to disable file caching in browserify<commit_after>"use strict";

var fs   = require("fs"),
    path = require("path"),

    through = require("through2"),
    sink    = require("sink-transform"),
    mkdirp  = require("mkdirp"),

    each    = require("lodash.foreach"),
    
    Processor = require("modular-css-core"),
    relative  = require("modular-css-core/lib/relative.js"),
    output    = require("modular-css-core/lib/output.js");

module.exports = function(browserify, opts) {
    var options = Object.assign(Object.create(null), {
            ext   : ".css",
            map   : browserify._options.debug,
            cwd   : browserify._options.basedir || process.cwd(),
            cache : true
        }, opts),
        
        processor = opts.cache && new Processor(options),
        
        bundler, bundles, handled;
    
    if(!options.ext || options.ext.charAt(0) !== ".") {
        return browserify.emit("error", "Missing or invalid \"ext\" option: " + options.ext);
    }
    
    function depReducer(curr, next) {
        curr[relative.prefixed(options.cwd, next)] = next;
        
        return curr;
    }

    browserify.transform(function(file) {
        if(path.extname(file) !== options.ext) {
            return through();
        }
        
        return sink.str(function(buffer, done) {
            var push = this.push.bind(this),
                real = fs.realpathSync(file);
            
            processor.string(real, buffer).then(
                function(result) {
                    // Tell watchers about dependencies by emitting "file" events
                    // AFAIK this is only useful to watchify, to ensure that it watches
                    // everyone in the dependency graph
                    processor.dependencies(result.id).forEach(function(id) {
                        browserify.emit("file", path.resolve(process.cwd(), id), id);
                    });
                    
                    push("module.exports = " + JSON.stringify(output.join(result.exports), null, 4) + ";");
                    
                    done();
                },

                function(error) {
                    // Thrown from the current bundler instance, NOT the main browserify
                    // instance. This is so that watchify won't explode.
                    bundler.emit("error", error);
                    
                    push(buffer);
                    
                    done();
                }
            );
        });
    });
    
    // Splice ourselves as early as possible into the deps pipeline
    browserify.pipeline.get("deps").splice(1, 0, through.obj(function(row, enc, done) {
        if(path.extname(row.file) !== options.ext) {
            return done(null, row);
        }
        
        handled[row.id] = true;
        
        // Ensure that browserify knows about the CSS dependency tree by updating
        // any referenced entries w/ their dependencies
        row.deps = processor.dependencies(row.file).reduce(depReducer, {});
        
        return done(null, row);
    }, function(done) {
        // Ensure that any CSS dependencies not directly referenced are
        // injected into the stream of files being managed
        var push = this.push.bind(this);
        
        processor.dependencies().forEach(function(dep) {
            if(dep in handled) {
                return;
            }
            
            push({
                id     : dep,
                file   : dep,
                source : "module.exports = " + JSON.stringify(output.join(processor.files[dep].exports), null, 4) + ";",
                deps   : processor.dependencies(dep).reduce(depReducer, {})
            });
        });
        
        done();
    }));
    
    // Keep tabs on factor-bundle organization
    browserify.on("factor.pipeline", function(file, pipeline) {
        bundles[file] = [];

        // Track the files in each bundle so we can determine commonalities
        // Doesn't actually modify the file, just records it
        pipeline.unshift(through.obj(function(obj, enc, done) {
            if(path.extname(obj.file) === options.ext) {
                bundles[file].unshift(obj.file);
            }

            done(null, obj);
        }));
    });

    // Watchify fires update events when files change, this tells the processor
    // to remove the changed files from its cache so they will be re-processed
    browserify.on("update", function(files) {
        processor.remove(files);
    });
    
    return browserify.on("bundle", function(current) {
        // Calls to .bundle() means we should recreate anything tracking bundling progress
        // in case things have changed out from under us, like when using watchify
        bundles = {};
        handled = {};
        
        // cache set to false means we need to create a new Processor each run-through
        if(!opts.cache) {
            processor = new Processor(options);
        }

        bundler = current;
        
        // Listen for bundling to finish
        bundler.on("end", function() {
{'fraction_non_alphanumeric': 0.11538461538461539, 'fraction_numerical': 0.0011988011988011988, 'mean_word_length': 1.64561310782241, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2866550', 'n_tokens_mistral': 2639, 'n_tokens_neox': 2534, 'n_words': 663}