Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 71 additions & 13 deletions lib/haml.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ var Haml;

var matchers, self_close_tags, embedder, forceXML, escaperName, escapeHtmlByDefault;

if (process && process.platform) {
var NEW_LINE_STR = process.platform.match(/^win/i) ? "\\r\\n" : "\\n";
var NEW_LINE = process.platform.match(/^win/i) ? "\r\n" : "\n";
}
else {
var NEW_LINE_STR = "\\n";
var NEW_LINE = "\n";
}

function html_escape(text) {
return (text + "").
replace(/&/g, "&").
Expand Down Expand Up @@ -299,8 +308,8 @@ var Haml;
'var ' + rvar + ' = [], ' + ivar + ', ' + vvar + '; ' +
'for (' + ivar + ' in ' + avar + ') { ' +
'if (' + avar + '.hasOwnProperty(' + ivar + ')) { ' +
vvar + ' = ' + avar + '[' + ivar + ']; ' +
rvar + '.push(\n' + (this.render_contents() || "''") + '\n); ' +
vvar + ' = ' + avar + '[' + ivar + ']; _$output = ' + (this.render_contents() || "''") + ";" +
rvar + '.push(_$output); ' +
'} } return ' + rvar + '.join(""); }).call(this)';
}
},
Expand Down Expand Up @@ -334,7 +343,7 @@ var Haml;
process: function () {
this.contents.unshift(this.matches[2]);

return '"<!--'+this.contents.join('\\n')+'-->"';
return '"<!--'+this.contents.join(NEW_LINE_STR)+'-->"';
}
},

Expand All @@ -343,7 +352,54 @@ var Haml;
name: "rawjs",
regexp: /^(\s*)-\s*(.*)\s*$/i,
process: function () {
function removeComments(js) {
var inString = null,
chars = js.length,
i, chr, chrNext,
result = [];

COMMENT_SEARCH:
for (i = 0; i < chars; i++) {
chr = js.charAt(i);
if (inString) {
// Check if it is the end of a string
if (chr === inString) {
inString = null;
}
}
else {
switch (chr) {
// Check if it is a beginning of a string
case "'":
case '"':
inString = chr;
break;

// Check a comment
case "/":
if (i < chars - 1) {
chrNext = js.charAt(i + 1);
if (chrNext == "/") {
break COMMENT_SEARCH;
}
}

break;
}
}

result.push(chr);
}

js = result.join("");
return js;
}

this.contents.unshift(this.matches[2]);
for (var i in this.contents) {
this.contents[i] = removeComments(this.contents[i]);
}

return '"";' + this.contents.join("\n")+"; _$output = _$output ";
}
},
Expand Down Expand Up @@ -403,7 +459,7 @@ var Haml;
line = "<?xml version='1.0' encoding='iso-8859-1' ?>";
break;
}
return JSON.stringify(line + "\n");
return JSON.stringify(line + NEW_LINE);
}
},

Expand All @@ -421,10 +477,10 @@ var Haml;
name: "script",
regexp: /^(\s*):(?:java)?script\s*$/,
process: function () {
return parse_interpol('\n<script type="text/javascript">\n' +
'//<![CDATA[\n' +
this.contents.join("\n") +
"\n//]]>\n</script>\n");
return parse_interpol(NEW_LINE + '<script type="text/javascript">' + NEW_LINE +
'//<![CDATA[' + NEW_LINE +
this.contents.join(NEW_LINE) +
NEW_LINE + "//]]>" + NEW_LINE + "</script>" + NEW_LINE);
}
},

Expand All @@ -433,9 +489,9 @@ var Haml;
name: "css",
regexp: /^(\s*):css\s*$/,
process: function () {
return JSON.stringify('<style type="text/css">\n' +
this.contents.join("\n") +
"\n</style>");
return JSON.stringify('<style type="text/css">' + NEW_LINE +
this.contents.join(NEW_LINE) +
NEW_LINE + "</style>");
}
}

Expand All @@ -447,7 +503,7 @@ var Haml;

// If lines is a string, turn it into an array
if (typeof lines === 'string') {
lines = lines.trim().replace(/\n\r|\r/g, '\n').split('\n');
lines = lines.trim().replace(/\r\n|\r/g, '\n').split('\n');
}

lines.forEach(function(line) {
Expand Down Expand Up @@ -557,7 +613,7 @@ var Haml;
buffer = [];
}
}
js.replace(/\n\r|\r/g, '\n').split('\n').forEach(function (line) {
js.replace(/\r\n|\r/g, '\n').split('\n').forEach(function (line) {
part = line.match(/^(\".*\")(\s*\+\s*)?$/);
if (!part) {
flush();
Expand All @@ -579,6 +635,8 @@ var Haml;

function render(text, options) {
options = options || {};
escaperName = options.customEscape || "html_escape"

text = text || "";
var js = compile(text, options);
if (options.optimize) {
Expand Down
4 changes: 4 additions & 0 deletions test/js_after_each.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
:each question in questions
- var temp = 'hello'
%div&= question
%div&= temp
1 change: 1 addition & 0 deletions test/js_after_each.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div>question 1<div>hello</div></div><div>question 2<div>hello</div></div><div>question 3<div>hello</div></div>
5 changes: 5 additions & 0 deletions test/js_after_each.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
locals: {
questions: ["question 1", "question 2", "question 3"]
}
}
31 changes: 31 additions & 0 deletions test/js_eol_comment.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
:each user in users
- var testComment = "hello " + user // sample eol-comment
%div&= testComment

:each user in users
- var testComment = 'hello ' + user // sample eol-comment
%div&= testComment

:each user in users
- var testComment = "hello // ok " + user
%div&= testComment

:each user in users
- var testComment = "hello // ok " + user // sample eol-comment
%div&= testComment

:each user in users
- var testComment = 'hello // ok ' + user
%div&= testComment

:each user in users
- var testComment = 'hello // ok ' + user // sample eol-comment
%div&= testComment

:each user in users
- var testComment = "hel'lo " + user // sample eol-comment
%div&= testComment

:each user in users
- var testComment = 'hel"lo ' + user // sample eol-comment
%div&= testComment
1 change: 1 addition & 0 deletions test/js_eol_comment.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div>hello Alex</div><div>hello Alex</div><div>hello // ok Alex</div><div>hello // ok Alex</div><div>hello // ok Alex</div><div>hello // ok Alex</div><div>hel'lo Alex</div><div>hel&quot;lo Alex</div>
5 changes: 5 additions & 0 deletions test/js_eol_comment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
locals: {
users: ["Alex"]
}
}
74 changes: 49 additions & 25 deletions test/test.js
Original file line number Diff line number Diff line change
@@ -1,49 +1,59 @@
var fs = require('fs');
var assert = require('assert');
var sys = require('sys');
var util = require('util');

var Haml = require("../lib/haml");



function compare(haml_file, haml, expected, scope, options){
options || (options = {});
try {
sys.puts(haml_file + " Begun")
util.puts(haml_file + " Begun")
var js = Haml.compile(haml);
var js_opt = Haml.optimize(js);
var jsFn = Haml(haml, options);
var actual = jsFn.call(scope.context, scope.locals);

assert.equal(actual, expected);
sys.puts(haml_file + " Passed")
util.puts(haml_file + " Passed")

actual = Haml.render(haml, {context:scope.context, locals:scope.locals})

assert.equal(actual, expected);
sys.puts(haml_file + " Haml.render Passed")
util.puts(haml_file + " Haml.render Passed")

} catch (e) {
var message = e.name;
if (e.message) { message += ": " + e.message; }
sys.error(haml_file + " FAILED")
sys.error(message);
sys.error("\nJS:\n\n" + js);
sys.error("\nOptimized JS:\n\n" + js_opt);
sys.error("\nJS fn:\n\n"+jsFn.toString());
sys.error("\nStack:\n\n"+e.stack);
util.error(haml_file + " FAILED")
util.error(message);
util.error("\nJS:\n\n" + js);
util.error("\nOptimized JS:\n\n" + js_opt);
util.error("\nJS fn:\n\n"+jsFn.toString());
util.error("\nStack:\n\n"+e.stack);
try{
sys.error("\nActual["+actual.length+"]:\n\n" + actual);
sys.error("\nExpected["+expected.length+"]:\n\n" + expected);
util.error("\nActual["+actual.length+"]:\n\n" + actual);
util.error("\nExpected["+expected.length+"]:\n\n" + expected);
}catch(e2){}

process.exit();
}
}

// Load command line arguments to run a specific test
var test_param = [];

if (process.argv.length > 2) {
for (var i = 2; i < process.argv.length; ++i) {
test_param.push(process.argv[i].toLowerCase());
}
}

fs.readdir('.', function (err, files) {
files.forEach(function (haml_file) {
if (test_param.length != 0 && test_param.indexOf(haml_file.toLowerCase()) === -1) {
return;
}

var m = haml_file.match(/^(.*)\.haml/),
base;
if (!m) {
Expand Down Expand Up @@ -71,25 +81,35 @@ fs.readdir('.', function (err, files) {
});

(function(){
var hamlSrc = fs.readFileSync("alt_attribs.haml", "utf8");
var haml_file = "alt_attribs.haml";

if (test_param.length != 0 && test_param.indexOf(haml_file) === -1) {
return;
}

var hamlSrc = fs.readFileSync(haml_file, "utf8");
var includeEscape = Haml(hamlSrc).toString();
var customEscape = Haml(hamlSrc, {customEscape:"$esc"}).toString();
try{
assert.ok(customEscape.length < includeEscape.length);
}catch(e){
sys.error(e.stack);
sys.error(customEscape);
util.error(e.stack);
util.error(customEscape);
process.exit();
}
})();


(function(){
if (test_param.length != 0 && test_param.indexOf("custom_escape.haml") === -1) {
return;
}

var hamlSrc = fs.readFileSync("./other/custom_escape.haml", "utf8");
var expected = fs.readFileSync("./other/custom_escape.html", "utf8");
var scope = eval("(" + fs.readFileSync("escaping.js") + ")");

sys.puts("custom_escape" + " Begun")
util.puts("custom_escape" + " Begun")
var jsFn = Haml(hamlSrc, {customEscape:"$esc"});

this.$esc = function(){
Expand All @@ -100,21 +120,25 @@ fs.readdir('.', function (err, files) {
try{
assert.equal(actual, expected);
}catch(e){
sys.error("\nActual["+actual.length+"]:\n\n" + actual);
sys.error("\nExpected["+expected.length+"]:\n\n" + expected);
util.error("\nActual["+actual.length+"]:\n\n" + actual);
util.error("\nExpected["+expected.length+"]:\n\n" + expected);
process.exit();
}
sys.puts("custom_escape" + " Passed")
util.puts("custom_escape" + " Passed")

})();


(function(){
if (test_param.length != 0 && test_param.indexOf("escape_by_default.haml") === -1) {
return;
}

var hamlSrc = fs.readFileSync("./other/escape_by_default.haml", "utf8");
var expected = fs.readFileSync("./other/escape_by_default.html", "utf8");
var scope = {};

sys.puts("escape_by_default" + " Begun")
util.puts("escape_by_default" + " Begun")
var js = Haml.compile(hamlSrc);

var jsFn = Haml(hamlSrc, {escapeHtmlByDefault:true});
Expand All @@ -127,11 +151,11 @@ fs.readdir('.', function (err, files) {
try{
assert.equal(actual, expected);
}catch(e){
sys.error("\nActual["+actual.length+"]:\n\n" + actual);
sys.error("\nExpected["+expected.length+"]:\n\n" + expected);
util.error("\nActual["+actual.length+"]:\n\n" + actual);
util.error("\nExpected["+expected.length+"]:\n\n" + expected);
process.exit();
}
sys.puts("escape_by_default" + " Passed")
util.puts("escape_by_default" + " Passed")

})();