1 import Exception from '../exception';
3 function validateClose(open, close) {
4 close = close.path ? close.path.original : close;
6 if (open.path.original !== close) {
7 let errorNode = {loc: open.path.loc};
9 throw new Exception(open.path.original + " doesn't match " + close, errorNode);
13 export function SourceLocation(source, locInfo) {
16 line: locInfo.first_line,
17 column: locInfo.first_column
20 line: locInfo.last_line,
21 column: locInfo.last_column
25 export function id(token) {
26 if (/^\[.*\]$/.test(token)) {
27 return token.substr(1, token.length - 2);
33 export function stripFlags(open, close) {
35 open: open.charAt(2) === '~',
36 close: close.charAt(close.length - 3) === '~'
40 export function stripComment(comment) {
41 return comment.replace(/^\{\{~?\!-?-?/, '')
42 .replace(/-?-?~?\}\}$/, '');
45 export function preparePath(data, parts, loc) {
46 loc = this.locInfo(loc);
48 let original = data ? '@' : '',
53 for (let i = 0, l = parts.length; i < l; i++) {
54 let part = parts[i].part,
55 // If we have [] syntax then we do not treat path references as operators,
56 // i.e. foo.[this] resolves to approximately context.foo['this']
57 isLiteral = parts[i].original !== part;
58 original += (parts[i].separator || '') + part;
60 if (!isLiteral && (part === '..' || part === '.' || part === 'this')) {
62 throw new Exception('Invalid path: ' + original, {loc});
63 } else if (part === '..') {
73 type: 'PathExpression',
82 export function prepareMustache(path, params, hash, open, strip, locInfo) {
83 // Must use charAt to support IE pre-10
84 let escapeFlag = open.charAt(3) || open.charAt(2),
85 escaped = escapeFlag !== '{' && escapeFlag !== '&';
87 let decorator = (/\*/.test(open));
89 type: decorator ? 'Decorator' : 'MustacheStatement',
95 loc: this.locInfo(locInfo)
99 export function prepareRawBlock(openRawBlock, contents, close, locInfo) {
100 validateClose(openRawBlock, close);
102 locInfo = this.locInfo(locInfo);
111 type: 'BlockStatement',
112 path: openRawBlock.path,
113 params: openRawBlock.params,
114 hash: openRawBlock.hash,
123 export function prepareBlock(openBlock, program, inverseAndProgram, close, inverted, locInfo) {
124 if (close && close.path) {
125 validateClose(openBlock, close);
128 let decorator = (/\*/.test(openBlock.open));
130 program.blockParams = openBlock.blockParams;
135 if (inverseAndProgram) {
137 throw new Exception('Unexpected inverse block on decorator', inverseAndProgram);
140 if (inverseAndProgram.chain) {
141 inverseAndProgram.program.body[0].closeStrip = close.strip;
144 inverseStrip = inverseAndProgram.strip;
145 inverse = inverseAndProgram.program;
155 type: decorator ? 'DecoratorBlock' : 'BlockStatement',
156 path: openBlock.path,
157 params: openBlock.params,
158 hash: openBlock.hash,
161 openStrip: openBlock.strip,
163 closeStrip: close && close.strip,
164 loc: this.locInfo(locInfo)
168 export function prepareProgram(statements, loc) {
169 if (!loc && statements.length) {
170 const firstLoc = statements[0].loc,
171 lastLoc = statements[statements.length - 1].loc;
173 /* istanbul ignore else */
174 if (firstLoc && lastLoc) {
176 source: firstLoc.source,
178 line: firstLoc.start.line,
179 column: firstLoc.start.column
182 line: lastLoc.end.line,
183 column: lastLoc.end.column
198 export function preparePartialBlock(open, program, close, locInfo) {
199 validateClose(open, close);
202 type: 'PartialBlockStatement',
207 openStrip: open.strip,
208 closeStrip: close && close.strip,
209 loc: this.locInfo(locInfo)