<commit_before>
/*!
 * Jade - Compiler
 * Copyright(c) 2010 <NAME> <<EMAIL>>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var filters = require('./filters'),
    doctypes = require('./doctypes'),
    selfClosing = require('./self-closing');

/**
 * Initialize `Compiler` with the given `node`.
 *
 * @param {Node} node
 * @api private
 */

var Compiler = module.exports = function Compiler(node) {
    this.node = node;
};

/**
 * Compiler prototype.
 */

Compiler.prototype = {
    compile: function(){
        this.buf = ['var buf = [];'];
        this.visit(this.node);
        this.buf.push("return buf.join('');")
        return this.buf.join('\n')
    },
    
    buffer: function(str, esc){
        if (esc) str = escape(str);
        return this.buf.push("buf.push('" + str + "');");
    },
    
    visit: function(node){
        return this['visit' + node.constructor.name](node);
    },
    
    visitRoot: function(root){
        this.visitBlock(root.block);
    },

    visitBlock: function(block){
        for (var i = 0, len = block.nodes.length; i < len; ++i) {
            this.visit(block.nodes[i]);
        }
    },
    
    visitDoctype: function(doctype){
        var name = doctype.val;
        if ('5' == name) this.terse = true;
        doctype = doctypes[name || 'default'];
        this.buffer(doctype);
    },
    
    visitTag: function(tag){
        var name = tag.name
        if (~selfClosing.indexOf(name)) {
            this.buffer('<' + name);
            this.visitAttributes(tag.attrs);
            this.terse
                ? this.buffer('>')
                : this.buffer('/>');
        } else {
            this.buffer('<' + name);
            this.visitAttributes(tag.attrs);
            this.buffer('>');
            if (tag.code) this.visitCode(tag.code);
            this.visitBlock(tag.block);
            this.buffer('</' + name + '>');
        }
    },
    
    visitFilter: function(filter){
        var fn = filters[filter.name];
        if (!fn) throw new Error('unknown filter ":' + filter.name + '"');
        var text = filter.text.lines.join('\\n').trimLeft();
        text = interpolate(escape(text));
        this.buffer(fn(text));
    },
    
    visitText: function(node){
        this.buffer(escape(text(node)));
    },
    
    visitComment: function(comment){
        if (comment.buffer) {
            this.buffer('<!--' + escape(comment.val) + '-->');
        }
    },
    
    visitCode: function(code){
        if (code.buffer) {
            this.buffer(code.val.trimLeft(), code.escape);
        } else {
            this.buf.push(code.val);
        }
        if (code.block) {
            this.buf.push('(function(){');
            this.visitBlock(code.block);
            this.buf.push('}).call(this);');
        }
    },
    
    visitEach: function(each){
        this.buf.push(''
            + '// iterate ' + each.obj + '\n'
            + '(function(){\n'
            + '  for (var ' + each.key + ' in ' + each.obj + ') {\n'
            + '    var ' + each.val + ' = ' + each.obj + '[' + each.key + '];\n');
        this.visitBlock(each.block);
        this.buf.push('  }\n}).call(this);\n');
    },
    
    visitAttributes: function(attrs){
        var buf = [],
            classes = [];
        if (this.terse) buf.push('terse: true');
        attrs.forEach(function(attr){
            if (attr.name == 'class') {
                classes.push(attr.val);
            } else {
                var pair = "'" + attr.name + "':" + attr.val;
                buf.push(pair);
            }
        });
        if (classes.length) {
            classes = classes.join(" + ' ' + ");
            buf.push("class:" + classes);
        }
        this.buf.push("buf.push(attrs({ " + buf.join(', ') + " }));");
    }
};

/**
 * Convert interpolation in the given string to JavaScript.
 *
 * @param {String} str
 * @return {String}
 * @api private
 */

function interpolate(str){
    return str.replace(/(\\)?[#$]{(.*?)}/g, function(str, escape, code){
        return escape
            ? str
            : "' + (" + code.replace(/\\'/g, "'") + ") + '";
    });
}

function text(node){
    return interpolate(node.lines.join('\\n').trimLeft());
}

function escape(str) {
    return str.replace(/'/g, "\\'");
}<commit_msg>Always interpolate and escape text<commit_after>
/*!
 * Jade - Compiler
 * Copyright(c) 2010 <NAME> <<EMAIL>>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var filters = require('./filters'),
    doctypes = require('./doctypes'),
    selfClosing = require('./self-closing');

/**
 * Initialize `Compiler` with the given `node`.
 *
 * @param {Node} node
 * @api private
 */

var Compiler = module.exports = function Compiler(node) {
    this.node = node;
};

/**
 * Compiler prototype.
 */

Compiler.prototype = {
    compile: function(){
        this.buf = ['var buf = [];'];
        this.visit(this.node);
        this.buf.push("return buf.join('');")
        return this.buf.join('\n')
    },
    
    buffer: function(str, esc){
        if (esc) str = escape(str);
        return this.buf.push("buf.push('" + str + "');");
    },
    
    visit: function(node){
        return this['visit' + node.constructor.name](node);
    },
    
    visitRoot: function(root){
        this.visitBlock(root.block);
    },

    visitBlock: function(block){
        for (var i = 0, len = block.nodes.length; i < len; ++i) {
            this.visit(block.nodes[i]);
        }
    },
    
    visitDoctype: function(doctype){
        var name = doctype.val;
        if ('5' == name) this.terse = true;
        doctype = doctypes[name || 'default'];
        this.buffer(doctype);
    },
    
    visitTag: function(tag){
        var name = tag.name
        if (~selfClosing.indexOf(name)) {
            this.buffer('<' + name);
            this.visitAttributes(tag.attrs);
            this.terse
                ? this.buffer('>')
                : this.buffer('/>');
        } else {
            this.buffer('<' + name);
            this.visitAttributes(tag.attrs);
            this.buffer('>');
            if (tag.code) this.visitCode(tag.code);
            this.visitBlock(tag.block);
            this.buffer('</' + name + '>');
        }
    },
    
    visitFilter: function(filter){
        var fn = filters[filter.name];
        if (!fn) throw new Error('unknown filter ":' + filter.name + '"');
        this.buffer(fn(text(filter.text)));
    },
    
    visitText: function(node){
        this.buffer(text(node));
    },
    
    visitComment: function(comment){
        if (comment.buffer) {
            this.buffer('<!--' + escape(comment.val) + '-->');
        }
    },
    
    visitCode: function(code){
        if (code.buffer) {
            this.buffer(code.val.trimLeft(), code.escape);
        } else {
            this.buf.push(code.val);
        }
        if (code.block) {
            this.buf.push('(function(){');
            this.visitBlock(code.block);
            this.buf.push('}).call(this);');
        }
    },
    
    visitEach: function(each){
        this.buf.push(''
            + '// iterate ' + each.obj + '\n'
            + '(function(){\n'
            + '  for (var ' + each.key + ' in ' + each.obj + ') {\n'
            + '    var ' + each.val + ' = ' + each.obj + '[' + each.key + '];\n');
        this.visitBlock(each.block);
        this.buf.push('  }\n}).call(this);\n');
    },
    
    visitAttributes: function(attrs){
        var buf = [],
            classes = [];
        if (this.terse) buf.push('terse: true');
        attrs.forEach(function(attr){
            if (attr.name == 'class') {
                classes.push(attr.val);
            } else {
                var pair = "'" + attr.name + "':" + attr.val;
                buf.push(pair);
            }
        });
        if (classes.length) {
            classes = classes.join(" + ' ' + ");
            buf.push("class:" + classes);
        }
        this.buf.push("buf.push(attrs({ " + buf.join(', ') + " }));");
    }
};

/**
 * Convert interpolation in the given string to JavaScript.
 *
 * @param {String} str
 * @return {String}
 * @api private
 */

function interpolate(str){
    return str.replace(/(\\)?[#$]{(.*?)}/g, function(str, escape, code){
        return escape
            ? str
            : "' + (" + code.replace(/\\'/g, "'") + ") + '";
    });
}

function text(node){
    return interpolate(escape(node.lines.join('\\n').trimLeft()));
}

function escape(str) {
    return str.replace(/'/g, "\\'");
}
{'fraction_non_alphanumeric': 0.1913993655269651, 'fraction_numerical': 0.0014099400775467042, 'mean_word_length': 1.773541870316064, 'pattern_counts': {'":': 2, '<': 19, '<?xml version=': 0, '>': 19, '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': '6470580', 'n_tokens_mistral': 2695, 'n_tokens_neox': 2646, 'n_words': 479}