Skip to content

Commit 63118d2

Browse files
committed
Merge pull request #21 from jenseng/jsx-attribute-fix
Fix loc.end in multi-line jsx attribute values, basic test runner.
2 parents bb00491 + a8f5c1e commit 63118d2

File tree

4 files changed

+205
-11
lines changed

4 files changed

+205
-11
lines changed

inject.js

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -61,17 +61,7 @@ module.exports = function(acorn) {
6161
default:
6262
if (acorn.isNewLine(ch)) {
6363
out += this.input.slice(chunkStart, this.pos);
64-
++this.pos;
65-
if (ch === 13 && this.input.charCodeAt(this.pos) === 10) {
66-
++this.pos;
67-
out += '\n';
68-
} else {
69-
out += String.fromCharCode(ch);
70-
}
71-
if (this.options.locations) {
72-
++this.curLine;
73-
this.lineStart = this.pos;
74-
}
64+
out += this.jsx_readNewLine(true);
7565
chunkStart = this.pos;
7666
} else {
7767
++this.pos;
@@ -80,6 +70,24 @@ module.exports = function(acorn) {
8070
}
8171
};
8272

73+
pp.jsx_readNewLine = function(normalizeCRLF) {
74+
var ch = this.input.charCodeAt(this.pos);
75+
var out;
76+
++this.pos;
77+
if (ch === 13 && this.input.charCodeAt(this.pos) === 10) {
78+
++this.pos;
79+
out = normalizeCRLF ? '\n' : '\r\n';
80+
} else {
81+
out = String.fromCharCode(ch);
82+
}
83+
if (this.options.locations) {
84+
++this.curLine;
85+
this.lineStart = this.pos;
86+
}
87+
88+
return out;
89+
};
90+
8391
pp.jsx_readString = function(quote) {
8492
var out = '', chunkStart = ++this.pos;
8593
for (;;) {
@@ -91,6 +99,10 @@ module.exports = function(acorn) {
9199
out += this.input.slice(chunkStart, this.pos);
92100
out += this.jsx_readEntity();
93101
chunkStart = this.pos;
102+
} else if (acorn.isNewLine(ch)) {
103+
out += this.input.slice(chunkStart, this.pos);
104+
out += this.jsx_readNewLine(false);
105+
chunkStart = this.pos;
94106
} else {
95107
++this.pos;
96108
}

test/driver.js

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
var tests = [];
2+
3+
exports.test = function(code, ast, options) {
4+
tests.push({code: code, ast: ast, options: options});
5+
};
6+
exports.testFail = function(code, message, options) {
7+
tests.push({code: code, error: message, options: options});
8+
};
9+
exports.testAssert = function(code, assert, options) {
10+
tests.push({code: code, assert: assert, options: options});
11+
};
12+
13+
exports.runTests = function(config, callback) {
14+
var parse = config.parse;
15+
16+
for (var i = 0; i < tests.length; ++i) {
17+
var test = tests[i];
18+
if (config.filter && !config.filter(test)) continue;
19+
try {
20+
var testOpts = test.options || {locations: true};
21+
var expected = {};
22+
if (expected.onComment = testOpts.onComment) {
23+
testOpts.onComment = []
24+
}
25+
if (expected.onToken = testOpts.onToken) {
26+
testOpts.onToken = [];
27+
}
28+
testOpts.plugins = { jsx: true };
29+
var ast = parse(test.code, testOpts);
30+
if (test.error) {
31+
if (config.loose) {
32+
callback("ok", test.code);
33+
} else {
34+
callback("fail", test.code, "Expected error message: " + test.error + "\nBut parsing succeeded.");
35+
}
36+
}
37+
else if (test.assert) {
38+
var error = test.assert(ast);
39+
if (error) callback("fail", test.code,
40+
"\n Assertion failed:\n " + error);
41+
else callback("ok", test.code);
42+
} else {
43+
var mis = misMatch(test.ast, ast);
44+
for (var name in expected) {
45+
if (mis) break;
46+
if (expected[name]) {
47+
mis = misMatch(expected[name], testOpts[name]);
48+
testOpts[name] = expected[name];
49+
}
50+
}
51+
if (mis) callback("fail", test.code, mis);
52+
else callback("ok", test.code);
53+
}
54+
} catch(e) {
55+
if (!(e instanceof SyntaxError)) {
56+
throw e;
57+
}
58+
if (test.error) {
59+
if (e.message == test.error) callback("ok", test.code);
60+
else callback("fail", test.code,
61+
"Expected error message: " + test.error + "\nGot error message: " + e.message);
62+
} else {
63+
callback("error", test.code, e.stack || e.toString());
64+
}
65+
}
66+
}
67+
};
68+
69+
function ppJSON(v) { return v instanceof RegExp ? v.toString() : JSON.stringify(v, null, 2); }
70+
function addPath(str, pt) {
71+
if (str.charAt(str.length-1) == ")")
72+
return str.slice(0, str.length-1) + "/" + pt + ")";
73+
return str + " (" + pt + ")";
74+
}
75+
76+
var misMatch = exports.misMatch = function(exp, act) {
77+
if (!exp || !act || (typeof exp != "object") || (typeof act != "object")) {
78+
if (exp !== act) return ppJSON(exp) + " !== " + ppJSON(act);
79+
} else if (exp instanceof RegExp || act instanceof RegExp) {
80+
var left = ppJSON(exp), right = ppJSON(act);
81+
if (left !== right) return left + " !== " + right;
82+
} else if (exp.splice) {
83+
if (!act.slice) return ppJSON(exp) + " != " + ppJSON(act);
84+
if (act.length != exp.length) return "array length mismatch " + exp.length + " != " + act.length;
85+
for (var i = 0; i < act.length; ++i) {
86+
var mis = misMatch(exp[i], act[i]);
87+
if (mis) return addPath(mis, i);
88+
}
89+
} else {
90+
for (var prop in exp) {
91+
var mis = misMatch(exp[prop], act[prop]);
92+
if (mis) return addPath(mis, prop);
93+
}
94+
}
95+
};
96+
97+
function mangle(ast) {
98+
if (typeof ast != "object" || !ast) return;
99+
if (ast.slice) {
100+
for (var i = 0; i < ast.length; ++i) mangle(ast[i]);
101+
} else {
102+
var loc = ast.start && ast.end && {start: ast.start, end: ast.end};
103+
if (loc) { delete ast.start; delete ast.end; }
104+
for (var name in ast) if (ast.hasOwnProperty(name)) mangle(ast[name]);
105+
if (loc) ast.loc = loc;
106+
}
107+
}

test/run.js

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
var driver = require("./driver.js");
2+
require("..");
3+
require("./tests-jsx.js");
4+
5+
function group(name) {
6+
if (typeof console === "object" && console.group) {
7+
console.group(name);
8+
}
9+
}
10+
11+
function groupEnd() {
12+
if (typeof console === "object" && console.groupEnd) {
13+
console.groupEnd(name);
14+
}
15+
}
16+
17+
function log(title, message) {
18+
if (typeof console === "object") console.log(title, message);
19+
}
20+
21+
var stats, modes = {
22+
Normal: {
23+
config: {
24+
parse: require("acorn").parse
25+
}
26+
}
27+
};
28+
29+
function report(state, code, message) {
30+
if (state != "ok") {++stats.failed; log(code, message);}
31+
++stats.testsRun;
32+
}
33+
34+
group("Errors");
35+
36+
for (var name in modes) {
37+
group(name);
38+
var mode = modes[name];
39+
stats = mode.stats = {testsRun: 0, failed: 0};
40+
var t0 = +new Date;
41+
driver.runTests(mode.config, report);
42+
mode.stats.duration = +new Date - t0;
43+
groupEnd();
44+
}
45+
46+
groupEnd();
47+
48+
function outputStats(name, stats) {
49+
log(name + ":", stats.testsRun + " tests run in " + stats.duration + "ms; " +
50+
(stats.failed ? stats.failed + " failures." : "all passed."));
51+
}
52+
53+
var total = {testsRun: 0, failed: 0, duration: 0};
54+
55+
group("Stats");
56+
57+
for (var name in modes) {
58+
var stats = modes[name].stats;
59+
outputStats(name + " parser", stats);
60+
for (var key in stats) total[key] += stats[key];
61+
}
62+
63+
outputStats("Total", total);
64+
65+
groupEnd();
66+
67+
if (total.failed && typeof process === "object") {
68+
process.stdout.write("", function() {
69+
process.exit(1);
70+
});
71+
}

test/tests-jsx.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3607,6 +3607,10 @@ var fbTestFixture = {
36073607
},
36083608
value: {
36093609
type: "Literal",
3610+
loc: {
3611+
start: { line: 1, column: 8 },
3612+
end: { line: 3, column: 15 }
3613+
},
36103614
range: [8, 62],
36113615
value: "M230 80\n\t\tA 45 45, 0, 1, 0, 275 125 \r\n L 275 80 Z",
36123616
raw: "\"M230 80\n\t\tA 45 45, 0, 1, 0, 275 125 \r\n L 275 80 Z\""

0 commit comments

Comments
 (0)