-
Notifications
You must be signed in to change notification settings - Fork 4
/
compiler.js
155 lines (127 loc) · 4.82 KB
/
compiler.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/* eslint-env mocha */
'use strict';
const expect = require(`expect.js`);
const fs = require(`fs`);
const parse5 = require(`parse5-utils`);
const Parser = require(`jade`).Parser;
const path = require(`path`);
const toHTML = require(`vdom-to-html`);
const Compiler = require(`../lib/compiler`);
const VDOM_RUNTIME = require(`../lib/config`).VDOM_CONFIG[`virtual-dom`].runtime;
function fixture(name) {
return fs.readFileSync(path.resolve(__dirname, `fixtures/` + name + `.jade`), `utf8`);
}
function testCompilation(fixtureName, options) {
if (!options) options = {};
options.pretty = true;
const parser = new Parser(fixture(fixtureName));
const tokens = parser.parse();
const compiler = new Compiler(tokens, options);
const js = compiler.compile();
// make sure it's syntactically valid
new Function(js);
return js;
}
describe(`Compiler`, function() {
it(`compiles functions as properties`, function() {
testCompilation(`inline-function`);
});
it(`throws if there is not exactly 1 tag`, function() {
expect(testCompilation).withArgs(`root-if`).to.throwException();
expect(testCompilation).withArgs(`empty`).to.throwException();
expect(testCompilation).withArgs(`multiple-tags`).to.throwException();
});
it(`compiles the boilerplate`, function() {
const js = testCompilation(`boilerplate`);
const root = eval(`${VDOM_RUNTIME}(function(){${js}})()`);
const html = toHTML(root);
parse5.parse(html, true);
});
it(`optionally wraps attributes in a stringify call`, function() {
const js = testCompilation(`attributes`, {rawProps: true, serializeAttrsObjects: true});
expect(js).to.contain(`__vjadeStringifyAttrsIfObj({obj: {foo: 'bar'}})`);
});
it(`compiles attributes`, function() {
const js = testCompilation(`attributes`);
expect(js).not.to.match(/\bclass\b/);
expect(js.match(/"className"/g)).to.have.length(4);
});
it(`compiles data attributes to dataset`, function() {
const js = testCompilation(`attributes`);
expect(js).not.to.match(/\bdata-foo\b/);
expect(js).to.match(/\bdataset\b/);
});
it(`optionally does not compile data attributes to dataset`, function() {
const js = testCompilation(`attributes`, {marshalDataset: false});
expect(js).not.to.match(/\bdataset\b/);
expect(js).to.match(/\bdata-foo\b/);
});
it(`handles basic string interpolation`, function() {
const js = testCompilation(`interpolation`);
expect(js).to.contain(`+ (x + 5) +`);
expect(js).to.contain(`+ (x - 2) +`);
});
it(`compiles if statements`, function() {
const js = testCompilation(`if`);
expect(js).not.to.contain(`undefined(`);
const root = eval(`${VDOM_RUNTIME}(function(){${js}})()`);
const html = toHTML(root);
parse5.parse(html, true);
expect(html).to.contain(`<span></span><span></span>`);
expect(html).not.to.contain(`<em>`);
expect(html).to.contain(`a1`);
expect(html).not.to.contain(`a2`);
expect(html).not.to.contain(`a3`);
});
it(`compiles case statements`, function() {
testCompilation(`case`);
});
it(`compiles top-level JS`, function() {
const js = testCompilation(`top-level-code`);
expect(js).to.contain(`var a = 1;\n`);
expect(js).to.contain(`var b = 2;\n`);
});
it(`compiles JS in blocks`, function() {
const js = testCompilation(`code`);
expect(js).to.contain(`foo = ['bar'];`);
expect(js).to.contain(`var z = [\n 1,\n 2,\n 3\n];`);
});
it(`compiles each`, function() {
testCompilation(`each`);
});
it(`compiles each, index`, function() {
const js = testCompilation(`each-index`);
expect(js).to.contain(`anIndex`);
});
it(`compiles each w/ expressions`, function() {
testCompilation(`each-expression`);
});
it(`compiles a while loop`, function() {
testCompilation(`while`);
});
it(`compiles mixins without arguments`, function() {
const js = testCompilation(`mixin`);
expect(js).to.contain(`jade_mixins['item'].call(this)`);
});
it(`compiles mixins with arguments`, function() {
const js = testCompilation(`mixin-args`);
expect(js).to.contain(`jade_mixins['item'].call(this, 5)`);
});
it(`compiles mixins with rest arguments`, function() {
const js = testCompilation(`mixin-rest`);
expect(js).to.contain(`function(x)`);
expect(js).to.contain(`jade_mixins['item'].call(this, 5, 'a', 'b')`);
});
it(`compiles mixins with blocks`, function() {
const js = testCompilation(`mixin-block`);
expect(js).to.contain(`jade_mixins['item'].call({block: function()`);
});
it(`compiles mixins with attributes`, function() {
const js = testCompilation(`mixin-attrs`);
expect(js).to.contain(`jade_mixins['item'].call({attributes: {`);
});
it(`compiles mixins and exposes $mixins`, function() {
const js = testCompilation(`mixin`);
expect(js).to.contain(`$mixins = jade_mixins`);
});
});