@handlebars/parser 2.0.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +1 -0
- package/{.eslintrc.js → .eslintrc.cjs} +5 -6
- package/.github/workflows/ci.yml +10 -9
- package/.github/workflows/plan-release.yml +93 -0
- package/.github/workflows/publish.yml +42 -0
- package/.release-plan.json +26 -0
- package/CHANGELOG.md +32 -0
- package/RELEASE.md +15 -48
- package/dist/cjs/exception.js +2 -4
- package/dist/cjs/helpers.js +60 -50
- package/dist/cjs/index.js +7 -21
- package/dist/cjs/parse.js +46 -38
- package/dist/cjs/parser.js +130 -97
- package/dist/cjs/printer.js +77 -44
- package/dist/cjs/visitor.js +8 -13
- package/dist/cjs/whitespace-control.js +66 -66
- package/dist/esm/exception.js +1 -1
- package/dist/esm/helpers.js +49 -23
- package/dist/esm/index.js +7 -7
- package/dist/esm/parse.js +41 -6
- package/dist/esm/parser.js +129 -94
- package/dist/esm/printer.js +75 -34
- package/dist/esm/visitor.js +4 -4
- package/dist/esm/whitespace-control.js +64 -59
- package/lib/helpers.js +44 -26
- package/lib/index.js +6 -6
- package/lib/parse.js +43 -6
- package/lib/printer.js +87 -54
- package/lib/visitor.js +19 -19
- package/lib/whitespace-control.js +72 -73
- package/package.json +42 -37
- package/spec/{.eslintrc.js → .eslintrc.cjs} +1 -1
- package/spec/ast.js +94 -44
- package/spec/parser.js +284 -232
- package/spec/utils.js +73 -8
- package/spec/visitor.js +36 -42
- package/src/handlebars.l +22 -4
- package/src/handlebars.yy +23 -5
- package/tsconfig.json +12 -6
- package/types/ast.d.ts +3 -1
package/lib/helpers.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import Exception from './exception';
|
|
1
|
+
import Exception from './exception.js';
|
|
2
2
|
|
|
3
3
|
function validateClose(open, close) {
|
|
4
4
|
close = close.path ? close.path.original : close;
|
|
@@ -17,11 +17,11 @@ export function SourceLocation(source, locInfo) {
|
|
|
17
17
|
this.source = source;
|
|
18
18
|
this.start = {
|
|
19
19
|
line: locInfo.first_line,
|
|
20
|
-
column: locInfo.first_column
|
|
20
|
+
column: locInfo.first_column,
|
|
21
21
|
};
|
|
22
22
|
this.end = {
|
|
23
23
|
line: locInfo.last_line,
|
|
24
|
-
column: locInfo.last_column
|
|
24
|
+
column: locInfo.last_column,
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
27
|
|
|
@@ -36,7 +36,7 @@ export function id(token) {
|
|
|
36
36
|
export function stripFlags(open, close) {
|
|
37
37
|
return {
|
|
38
38
|
open: open.charAt(2) === '~',
|
|
39
|
-
close: close.charAt(close.length - 3) === '~'
|
|
39
|
+
close: close.charAt(close.length - 3) === '~',
|
|
40
40
|
};
|
|
41
41
|
}
|
|
42
42
|
|
|
@@ -44,38 +44,56 @@ export function stripComment(comment) {
|
|
|
44
44
|
return comment.replace(/^\{\{~?!-?-?/, '').replace(/-?-?~?\}\}$/, '');
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
export function preparePath(data, parts, loc) {
|
|
47
|
+
export function preparePath(data, sexpr, parts, loc) {
|
|
48
48
|
loc = this.locInfo(loc);
|
|
49
49
|
|
|
50
|
-
let original
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
let original;
|
|
51
|
+
|
|
52
|
+
if (data) {
|
|
53
|
+
original = '@';
|
|
54
|
+
} else if (sexpr) {
|
|
55
|
+
original = sexpr.original + '.';
|
|
56
|
+
} else {
|
|
57
|
+
original = '';
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
let tail = [];
|
|
61
|
+
let depth = 0;
|
|
53
62
|
|
|
54
63
|
for (let i = 0, l = parts.length; i < l; i++) {
|
|
55
|
-
let part = parts[i].part
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
64
|
+
let part = parts[i].part;
|
|
65
|
+
// If we have [] syntax then we do not treat path references as operators,
|
|
66
|
+
// i.e. foo.[this] resolves to approximately context.foo['this']
|
|
67
|
+
let isLiteral = parts[i].original !== part;
|
|
68
|
+
let separator = parts[i].separator;
|
|
69
|
+
|
|
70
|
+
let partPrefix = separator === '.#' ? '#' : '';
|
|
71
|
+
|
|
72
|
+
original += (separator || '') + part;
|
|
60
73
|
|
|
61
74
|
if (!isLiteral && (part === '..' || part === '.' || part === 'this')) {
|
|
62
|
-
if (
|
|
75
|
+
if (tail.length > 0) {
|
|
63
76
|
throw new Exception('Invalid path: ' + original, { loc });
|
|
64
77
|
} else if (part === '..') {
|
|
65
78
|
depth++;
|
|
66
79
|
}
|
|
67
80
|
} else {
|
|
68
|
-
|
|
81
|
+
tail.push(`${partPrefix}${part}`);
|
|
69
82
|
}
|
|
70
83
|
}
|
|
71
84
|
|
|
85
|
+
let head = sexpr || tail.shift();
|
|
86
|
+
|
|
72
87
|
return {
|
|
73
88
|
type: 'PathExpression',
|
|
89
|
+
this: original.startsWith('this.'),
|
|
74
90
|
data,
|
|
75
91
|
depth,
|
|
76
|
-
|
|
92
|
+
head,
|
|
93
|
+
tail,
|
|
94
|
+
parts: head ? [head, ...tail] : tail,
|
|
77
95
|
original,
|
|
78
|
-
loc
|
|
96
|
+
loc,
|
|
79
97
|
};
|
|
80
98
|
}
|
|
81
99
|
|
|
@@ -92,7 +110,7 @@ export function prepareMustache(path, params, hash, open, strip, locInfo) {
|
|
|
92
110
|
hash,
|
|
93
111
|
escaped,
|
|
94
112
|
strip,
|
|
95
|
-
loc: this.locInfo(locInfo)
|
|
113
|
+
loc: this.locInfo(locInfo),
|
|
96
114
|
};
|
|
97
115
|
}
|
|
98
116
|
|
|
@@ -104,7 +122,7 @@ export function prepareRawBlock(openRawBlock, contents, close, locInfo) {
|
|
|
104
122
|
type: 'Program',
|
|
105
123
|
body: contents,
|
|
106
124
|
strip: {},
|
|
107
|
-
loc: locInfo
|
|
125
|
+
loc: locInfo,
|
|
108
126
|
};
|
|
109
127
|
|
|
110
128
|
return {
|
|
@@ -116,7 +134,7 @@ export function prepareRawBlock(openRawBlock, contents, close, locInfo) {
|
|
|
116
134
|
openStrip: {},
|
|
117
135
|
inverseStrip: {},
|
|
118
136
|
closeStrip: {},
|
|
119
|
-
loc: locInfo
|
|
137
|
+
loc: locInfo,
|
|
120
138
|
};
|
|
121
139
|
}
|
|
122
140
|
|
|
@@ -170,7 +188,7 @@ export function prepareBlock(
|
|
|
170
188
|
openStrip: openBlock.strip,
|
|
171
189
|
inverseStrip,
|
|
172
190
|
closeStrip: close && close.strip,
|
|
173
|
-
loc: this.locInfo(locInfo)
|
|
191
|
+
loc: this.locInfo(locInfo),
|
|
174
192
|
};
|
|
175
193
|
}
|
|
176
194
|
|
|
@@ -185,12 +203,12 @@ export function prepareProgram(statements, loc) {
|
|
|
185
203
|
source: firstLoc.source,
|
|
186
204
|
start: {
|
|
187
205
|
line: firstLoc.start.line,
|
|
188
|
-
column: firstLoc.start.column
|
|
206
|
+
column: firstLoc.start.column,
|
|
189
207
|
},
|
|
190
208
|
end: {
|
|
191
209
|
line: lastLoc.end.line,
|
|
192
|
-
column: lastLoc.end.column
|
|
193
|
-
}
|
|
210
|
+
column: lastLoc.end.column,
|
|
211
|
+
},
|
|
194
212
|
};
|
|
195
213
|
}
|
|
196
214
|
}
|
|
@@ -199,7 +217,7 @@ export function prepareProgram(statements, loc) {
|
|
|
199
217
|
type: 'Program',
|
|
200
218
|
body: statements,
|
|
201
219
|
strip: {},
|
|
202
|
-
loc: loc
|
|
220
|
+
loc: loc,
|
|
203
221
|
};
|
|
204
222
|
}
|
|
205
223
|
|
|
@@ -214,6 +232,6 @@ export function preparePartialBlock(open, program, close, locInfo) {
|
|
|
214
232
|
program,
|
|
215
233
|
openStrip: open.strip,
|
|
216
234
|
closeStrip: close && close.strip,
|
|
217
|
-
loc: this.locInfo(locInfo)
|
|
235
|
+
loc: this.locInfo(locInfo),
|
|
218
236
|
};
|
|
219
237
|
}
|
package/lib/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { default as Visitor } from './visitor';
|
|
2
|
-
export { default as WhitespaceControl } from './whitespace-control';
|
|
3
|
-
export { default as parser } from './parser';
|
|
4
|
-
export { default as Exception } from './exception';
|
|
5
|
-
export { print, PrintVisitor } from './printer';
|
|
6
|
-
export { parse, parseWithoutProcessing } from './parse';
|
|
1
|
+
export { default as Visitor } from './visitor.js';
|
|
2
|
+
export { default as WhitespaceControl } from './whitespace-control.js';
|
|
3
|
+
export { default as parser } from './parser.js';
|
|
4
|
+
export { default as Exception } from './exception.js';
|
|
5
|
+
export { print, PrintVisitor } from './printer.js';
|
|
6
|
+
export { parse, parseWithoutProcessing } from './parse.js';
|
package/lib/parse.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import parser from './parser';
|
|
2
|
-
import WhitespaceControl from './whitespace-control';
|
|
3
|
-
import * as Helpers from './helpers';
|
|
1
|
+
import parser from './parser.js';
|
|
2
|
+
import WhitespaceControl from './whitespace-control.js';
|
|
3
|
+
import * as Helpers from './helpers.js';
|
|
4
4
|
|
|
5
5
|
let baseHelpers = {};
|
|
6
6
|
|
|
@@ -19,13 +19,50 @@ export function parseWithoutProcessing(input, options) {
|
|
|
19
19
|
parser.yy = baseHelpers;
|
|
20
20
|
|
|
21
21
|
// Altering the shared object here, but this is ok as parser is a sync operation
|
|
22
|
-
parser.yy.locInfo = function(locInfo) {
|
|
22
|
+
parser.yy.locInfo = function (locInfo) {
|
|
23
23
|
return new Helpers.SourceLocation(options && options.srcName, locInfo);
|
|
24
24
|
};
|
|
25
25
|
|
|
26
|
-
let
|
|
26
|
+
let squareSyntax;
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
if (typeof options?.syntax?.square === 'function') {
|
|
29
|
+
squareSyntax = options.syntax.square;
|
|
30
|
+
} else if (options?.syntax?.square === 'node') {
|
|
31
|
+
squareSyntax = arrayLiteralNode;
|
|
32
|
+
} else {
|
|
33
|
+
squareSyntax = 'string';
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
let hashSyntax;
|
|
37
|
+
|
|
38
|
+
if (typeof options?.syntax?.hash === 'function') {
|
|
39
|
+
hashSyntax = options.syntax.hash;
|
|
40
|
+
} else {
|
|
41
|
+
hashSyntax = hashLiteralNode;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
parser.yy.syntax = {
|
|
45
|
+
square: squareSyntax,
|
|
46
|
+
hash: hashSyntax,
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
return parser.parse(input);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function arrayLiteralNode(array, loc) {
|
|
53
|
+
return {
|
|
54
|
+
type: 'ArrayLiteral',
|
|
55
|
+
items: array,
|
|
56
|
+
loc,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function hashLiteralNode(hash, loc) {
|
|
61
|
+
return {
|
|
62
|
+
type: 'HashLiteral',
|
|
63
|
+
pairs: hash.pairs,
|
|
64
|
+
loc,
|
|
65
|
+
};
|
|
29
66
|
}
|
|
30
67
|
|
|
31
68
|
export function parse(input, options) {
|
package/lib/printer.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* eslint-disable new-cap */
|
|
2
|
-
import Visitor from './visitor';
|
|
2
|
+
import Visitor from './visitor.js';
|
|
3
3
|
|
|
4
4
|
export function print(ast) {
|
|
5
5
|
return new PrintVisitor().accept(ast);
|
|
@@ -11,7 +11,7 @@ export function PrintVisitor() {
|
|
|
11
11
|
|
|
12
12
|
PrintVisitor.prototype = new Visitor();
|
|
13
13
|
|
|
14
|
-
PrintVisitor.prototype.pad = function(string) {
|
|
14
|
+
PrintVisitor.prototype.pad = function (string) {
|
|
15
15
|
let out = '';
|
|
16
16
|
|
|
17
17
|
for (let i = 0, l = this.padding; i < l; i++) {
|
|
@@ -22,7 +22,7 @@ PrintVisitor.prototype.pad = function(string) {
|
|
|
22
22
|
return out;
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
-
PrintVisitor.prototype.Program = function(program) {
|
|
25
|
+
PrintVisitor.prototype.Program = function (program) {
|
|
26
26
|
let out = '',
|
|
27
27
|
body = program.body,
|
|
28
28
|
i,
|
|
@@ -46,47 +46,50 @@ PrintVisitor.prototype.Program = function(program) {
|
|
|
46
46
|
return out;
|
|
47
47
|
};
|
|
48
48
|
|
|
49
|
-
PrintVisitor.prototype.MustacheStatement = function(mustache) {
|
|
50
|
-
|
|
49
|
+
PrintVisitor.prototype.MustacheStatement = function (mustache) {
|
|
50
|
+
if (mustache.params.length > 0 || mustache.hash) {
|
|
51
|
+
return this.pad('{{ ' + this.callBody(mustache) + ' }}');
|
|
52
|
+
} else {
|
|
53
|
+
return this.pad('{{ ' + this.accept(mustache.path) + ' }}');
|
|
54
|
+
}
|
|
51
55
|
};
|
|
52
|
-
PrintVisitor.prototype.Decorator = function(mustache) {
|
|
53
|
-
return this.pad('{{ DIRECTIVE ' + this.
|
|
56
|
+
PrintVisitor.prototype.Decorator = function (mustache) {
|
|
57
|
+
return this.pad('{{ DIRECTIVE ' + this.callBody(mustache) + ' }}');
|
|
54
58
|
};
|
|
55
59
|
|
|
56
|
-
PrintVisitor.prototype.BlockStatement = PrintVisitor.prototype.DecoratorBlock =
|
|
57
|
-
block
|
|
58
|
-
|
|
59
|
-
let out = '';
|
|
60
|
+
PrintVisitor.prototype.BlockStatement = PrintVisitor.prototype.DecoratorBlock =
|
|
61
|
+
function (block) {
|
|
62
|
+
let out = '';
|
|
60
63
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
this.padding++;
|
|
65
|
-
out += this.pad(this.SubExpression(block));
|
|
66
|
-
if (block.program) {
|
|
67
|
-
out += this.pad('PROGRAM:');
|
|
64
|
+
out += this.pad(
|
|
65
|
+
(block.type === 'DecoratorBlock' ? 'DIRECTIVE ' : '') + 'BLOCK:'
|
|
66
|
+
);
|
|
68
67
|
this.padding++;
|
|
69
|
-
out += this.
|
|
70
|
-
this.padding--;
|
|
71
|
-
}
|
|
72
|
-
if (block.inverse) {
|
|
68
|
+
out += this.pad(this.callBody(block));
|
|
73
69
|
if (block.program) {
|
|
70
|
+
out += this.pad('PROGRAM:');
|
|
74
71
|
this.padding++;
|
|
72
|
+
out += this.accept(block.program);
|
|
73
|
+
this.padding--;
|
|
75
74
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
75
|
+
if (block.inverse) {
|
|
76
|
+
if (block.program) {
|
|
77
|
+
this.padding++;
|
|
78
|
+
}
|
|
79
|
+
out += this.pad('{{^}}');
|
|
80
|
+
this.padding++;
|
|
81
|
+
out += this.accept(block.inverse);
|
|
81
82
|
this.padding--;
|
|
83
|
+
if (block.program) {
|
|
84
|
+
this.padding--;
|
|
85
|
+
}
|
|
82
86
|
}
|
|
83
|
-
|
|
84
|
-
this.padding--;
|
|
87
|
+
this.padding--;
|
|
85
88
|
|
|
86
|
-
|
|
87
|
-
};
|
|
89
|
+
return out;
|
|
90
|
+
};
|
|
88
91
|
|
|
89
|
-
PrintVisitor.prototype.PartialStatement = function(partial) {
|
|
92
|
+
PrintVisitor.prototype.PartialStatement = function (partial) {
|
|
90
93
|
let content = 'PARTIAL:' + partial.name.original;
|
|
91
94
|
if (partial.params[0]) {
|
|
92
95
|
content += ' ' + this.accept(partial.params[0]);
|
|
@@ -96,7 +99,7 @@ PrintVisitor.prototype.PartialStatement = function(partial) {
|
|
|
96
99
|
}
|
|
97
100
|
return this.pad('{{> ' + content + ' }}');
|
|
98
101
|
};
|
|
99
|
-
PrintVisitor.prototype.PartialBlockStatement = function(partial) {
|
|
102
|
+
PrintVisitor.prototype.PartialBlockStatement = function (partial) {
|
|
100
103
|
let content = 'PARTIAL BLOCK:' + partial.name.original;
|
|
101
104
|
if (partial.params[0]) {
|
|
102
105
|
content += ' ' + this.accept(partial.params[0]);
|
|
@@ -113,16 +116,20 @@ PrintVisitor.prototype.PartialBlockStatement = function(partial) {
|
|
|
113
116
|
return this.pad('{{> ' + content + ' }}');
|
|
114
117
|
};
|
|
115
118
|
|
|
116
|
-
PrintVisitor.prototype.ContentStatement = function(content) {
|
|
119
|
+
PrintVisitor.prototype.ContentStatement = function (content) {
|
|
117
120
|
return this.pad("CONTENT[ '" + content.value + "' ]");
|
|
118
121
|
};
|
|
119
122
|
|
|
120
|
-
PrintVisitor.prototype.CommentStatement = function(comment) {
|
|
123
|
+
PrintVisitor.prototype.CommentStatement = function (comment) {
|
|
121
124
|
return this.pad("{{! '" + comment.value + "' }}");
|
|
122
125
|
};
|
|
123
126
|
|
|
124
|
-
PrintVisitor.prototype.SubExpression = function(sexpr) {
|
|
125
|
-
|
|
127
|
+
PrintVisitor.prototype.SubExpression = function (sexpr) {
|
|
128
|
+
return `(${this.callBody(sexpr)})`;
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
PrintVisitor.prototype.callBody = function (callExpr) {
|
|
132
|
+
let params = callExpr.params,
|
|
126
133
|
paramStrings = [],
|
|
127
134
|
hash;
|
|
128
135
|
|
|
@@ -130,49 +137,75 @@ PrintVisitor.prototype.SubExpression = function(sexpr) {
|
|
|
130
137
|
paramStrings.push(this.accept(params[i]));
|
|
131
138
|
}
|
|
132
139
|
|
|
133
|
-
params =
|
|
140
|
+
params =
|
|
141
|
+
paramStrings.length === 0 ? '' : ' [' + paramStrings.join(', ') + ']';
|
|
134
142
|
|
|
135
|
-
hash =
|
|
143
|
+
hash = callExpr.hash ? ' ' + this.accept(callExpr.hash) : '';
|
|
136
144
|
|
|
137
|
-
return this.accept(
|
|
145
|
+
return this.accept(callExpr.path) + params + hash;
|
|
138
146
|
};
|
|
139
147
|
|
|
140
|
-
PrintVisitor.prototype.PathExpression = function(id) {
|
|
141
|
-
let
|
|
142
|
-
|
|
148
|
+
PrintVisitor.prototype.PathExpression = function (id) {
|
|
149
|
+
let head =
|
|
150
|
+
typeof id.head === 'string' ? id.head : `[${this.accept(id.head)}]`;
|
|
151
|
+
let path = [head, ...id.tail].join('/');
|
|
152
|
+
return 'p%' + prefix(id) + path;
|
|
143
153
|
};
|
|
144
154
|
|
|
145
|
-
|
|
155
|
+
function prefix(path) {
|
|
156
|
+
if (path.data) {
|
|
157
|
+
return '@';
|
|
158
|
+
} else if (path.this) {
|
|
159
|
+
return 'this.';
|
|
160
|
+
} else {
|
|
161
|
+
return '';
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
PrintVisitor.prototype.StringLiteral = function (string) {
|
|
146
166
|
return '"' + string.value + '"';
|
|
147
167
|
};
|
|
148
168
|
|
|
149
|
-
PrintVisitor.prototype.NumberLiteral = function(number) {
|
|
150
|
-
return '
|
|
169
|
+
PrintVisitor.prototype.NumberLiteral = function (number) {
|
|
170
|
+
return 'n%' + number.value;
|
|
151
171
|
};
|
|
152
172
|
|
|
153
|
-
PrintVisitor.prototype.BooleanLiteral = function(bool) {
|
|
154
|
-
return '
|
|
173
|
+
PrintVisitor.prototype.BooleanLiteral = function (bool) {
|
|
174
|
+
return 'b%' + bool.value;
|
|
155
175
|
};
|
|
156
176
|
|
|
157
|
-
PrintVisitor.prototype.UndefinedLiteral = function() {
|
|
177
|
+
PrintVisitor.prototype.UndefinedLiteral = function () {
|
|
158
178
|
return 'UNDEFINED';
|
|
159
179
|
};
|
|
160
180
|
|
|
161
|
-
PrintVisitor.prototype.NullLiteral = function() {
|
|
181
|
+
PrintVisitor.prototype.NullLiteral = function () {
|
|
162
182
|
return 'NULL';
|
|
163
183
|
};
|
|
164
184
|
|
|
165
|
-
PrintVisitor.prototype.
|
|
185
|
+
PrintVisitor.prototype.ArrayLiteral = function (array) {
|
|
186
|
+
return `Array[${array.items.map((item) => this.accept(item)).join(', ')}]`;
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
PrintVisitor.prototype.HashLiteral = function (hash) {
|
|
190
|
+
return `Hash{${this.hashPairs(hash)}}`;
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
PrintVisitor.prototype.Hash = function (hash) {
|
|
194
|
+
return `HASH{${this.hashPairs(hash)}}`;
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
PrintVisitor.prototype.hashPairs = function (hash) {
|
|
166
198
|
let pairs = hash.pairs,
|
|
167
199
|
joinedPairs = [];
|
|
168
200
|
|
|
169
201
|
for (let i = 0, l = pairs.length; i < l; i++) {
|
|
170
|
-
joinedPairs.push(this.
|
|
202
|
+
joinedPairs.push(this.HashPair(pairs[i]));
|
|
171
203
|
}
|
|
172
204
|
|
|
173
|
-
return
|
|
205
|
+
return joinedPairs.join(' ');
|
|
174
206
|
};
|
|
175
|
-
|
|
207
|
+
|
|
208
|
+
PrintVisitor.prototype.HashPair = function (pair) {
|
|
176
209
|
return pair.key + '=' + this.accept(pair.value);
|
|
177
210
|
};
|
|
178
211
|
/* eslint-enable new-cap */
|
package/lib/visitor.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import Exception from './exception';
|
|
1
|
+
import Exception from './exception.js';
|
|
2
2
|
|
|
3
3
|
function Visitor() {
|
|
4
4
|
this.parents = [];
|
|
@@ -9,7 +9,7 @@ Visitor.prototype = {
|
|
|
9
9
|
mutating: false,
|
|
10
10
|
|
|
11
11
|
// Visits a given value. If mutating, will replace the value if necessary.
|
|
12
|
-
acceptKey: function(node, name) {
|
|
12
|
+
acceptKey: function (node, name) {
|
|
13
13
|
let value = this.accept(node[name]);
|
|
14
14
|
if (this.mutating) {
|
|
15
15
|
// Hacky sanity check: This may have a few false positives for type for the helper
|
|
@@ -30,7 +30,7 @@ Visitor.prototype = {
|
|
|
30
30
|
|
|
31
31
|
// Performs an accept operation with added sanity check to ensure
|
|
32
32
|
// required keys are not removed.
|
|
33
|
-
acceptRequired: function(node, name) {
|
|
33
|
+
acceptRequired: function (node, name) {
|
|
34
34
|
this.acceptKey(node, name);
|
|
35
35
|
|
|
36
36
|
if (!node[name]) {
|
|
@@ -38,9 +38,9 @@ Visitor.prototype = {
|
|
|
38
38
|
}
|
|
39
39
|
},
|
|
40
40
|
|
|
41
|
-
// Traverses a given array. If mutating, empty
|
|
41
|
+
// Traverses a given array. If mutating, empty responses will be removed
|
|
42
42
|
// for child elements.
|
|
43
|
-
acceptArray: function(array) {
|
|
43
|
+
acceptArray: function (array) {
|
|
44
44
|
for (let i = 0, l = array.length; i < l; i++) {
|
|
45
45
|
this.acceptKey(array, i);
|
|
46
46
|
|
|
@@ -52,7 +52,7 @@ Visitor.prototype = {
|
|
|
52
52
|
}
|
|
53
53
|
},
|
|
54
54
|
|
|
55
|
-
accept: function(object) {
|
|
55
|
+
accept: function (object) {
|
|
56
56
|
if (!object) {
|
|
57
57
|
return;
|
|
58
58
|
}
|
|
@@ -78,7 +78,7 @@ Visitor.prototype = {
|
|
|
78
78
|
}
|
|
79
79
|
},
|
|
80
80
|
|
|
81
|
-
Program: function(program) {
|
|
81
|
+
Program: function (program) {
|
|
82
82
|
this.acceptArray(program.body);
|
|
83
83
|
},
|
|
84
84
|
|
|
@@ -89,31 +89,31 @@ Visitor.prototype = {
|
|
|
89
89
|
DecoratorBlock: visitBlock,
|
|
90
90
|
|
|
91
91
|
PartialStatement: visitPartial,
|
|
92
|
-
PartialBlockStatement: function(partial) {
|
|
92
|
+
PartialBlockStatement: function (partial) {
|
|
93
93
|
visitPartial.call(this, partial);
|
|
94
94
|
|
|
95
95
|
this.acceptKey(partial, 'program');
|
|
96
96
|
},
|
|
97
97
|
|
|
98
|
-
ContentStatement: function(/* content */) {},
|
|
99
|
-
CommentStatement: function(/* comment */) {},
|
|
98
|
+
ContentStatement: function (/* content */) {},
|
|
99
|
+
CommentStatement: function (/* comment */) {},
|
|
100
100
|
|
|
101
101
|
SubExpression: visitSubExpression,
|
|
102
102
|
|
|
103
|
-
PathExpression: function(/* path */) {},
|
|
103
|
+
PathExpression: function (/* path */) {},
|
|
104
104
|
|
|
105
|
-
StringLiteral: function(/* string */) {},
|
|
106
|
-
NumberLiteral: function(/* number */) {},
|
|
107
|
-
BooleanLiteral: function(/* bool */) {},
|
|
108
|
-
UndefinedLiteral: function(/* literal */) {},
|
|
109
|
-
NullLiteral: function(/* literal */) {},
|
|
105
|
+
StringLiteral: function (/* string */) {},
|
|
106
|
+
NumberLiteral: function (/* number */) {},
|
|
107
|
+
BooleanLiteral: function (/* bool */) {},
|
|
108
|
+
UndefinedLiteral: function (/* literal */) {},
|
|
109
|
+
NullLiteral: function (/* literal */) {},
|
|
110
110
|
|
|
111
|
-
Hash: function(hash) {
|
|
111
|
+
Hash: function (hash) {
|
|
112
112
|
this.acceptArray(hash.pairs);
|
|
113
113
|
},
|
|
114
|
-
HashPair: function(pair) {
|
|
114
|
+
HashPair: function (pair) {
|
|
115
115
|
this.acceptRequired(pair, 'value');
|
|
116
|
-
}
|
|
116
|
+
},
|
|
117
117
|
};
|
|
118
118
|
|
|
119
119
|
function visitSubExpression(mustache) {
|