marionette_dust 0.0.2 → 0.0.3

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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +24 -5
  3. data/Rakefile +9 -2
  4. data/lib/dust_engine/dust.rb +4 -4
  5. data/lib/generators/{marionette_dust → md}/common/templates/app.js +5 -2
  6. data/lib/generators/md/common/templates/app.js.coffee +8 -0
  7. data/lib/generators/{marionette_dust → md}/common/templates/controller.js +0 -0
  8. data/lib/generators/md/common/templates/controller.js.coffee +2 -0
  9. data/lib/generators/{marionette_dust → md}/common/templates/entity.js +0 -0
  10. data/lib/generators/md/common/templates/entity.js.coffee +7 -0
  11. data/lib/generators/{marionette_dust → md}/common/templates/template.jst.dust +0 -0
  12. data/lib/generators/{marionette_dust → md}/common/templates/view.js +0 -0
  13. data/lib/generators/md/common/templates/view.js.coffee +3 -0
  14. data/lib/generators/{marionette_dust → md}/helpers.rb +0 -0
  15. data/lib/generators/{marionette_dust → md}/install/install_generator.rb +2 -2
  16. data/lib/generators/{marionette_dust → md}/install/templates/app.js +5 -0
  17. data/lib/generators/{marionette_dust → md}/install/templates/app.js.coffee +0 -0
  18. data/lib/generators/{marionette_dust → md}/scaffold/scaffold_generator.rb +5 -5
  19. data/lib/generators/{marionette_dust → md}/submodule/submodule_generator.rb +4 -5
  20. data/lib/marionette_dust/version.rb +1 -1
  21. data/marionette_dust.gemspec +1 -0
  22. data/test/lib/generators/marionette_dust/install/install_generator_test.rb +47 -0
  23. data/test/lib/generators/marionette_dust/install/templates/app/assets/javascripts/app.js +25 -0
  24. data/test/lib/generators/marionette_dust/install/templates/app/assets/javascripts/app.js.coffee +16 -0
  25. data/test/lib/generators/marionette_dust/install/templates/app/assets/javascripts/application.js +5 -0
  26. data/test/lib/generators/marionette_dust/scaffold_and_submodule/scaffold_generator_test.rb +36 -0
  27. data/test/lib/generators/marionette_dust/scaffold_and_submodule/submodule_generator_test.rb +28 -0
  28. data/test/lib/generators/marionette_dust/scaffold_and_submodule/templates/app/assets/javascripts/app.js +25 -0
  29. data/test/lib/generators/marionette_dust/scaffold_and_submodule/templates/app/assets/javascripts/app.js.coffee +16 -0
  30. data/test/lib/generators/marionette_dust/scaffold_and_submodule/templates/app/assets/javascripts/application.js +5 -0
  31. data/test/lib/generators/marionette_dust/scaffold_and_submodule/templates/app/assets/javascripts/apps/foo/bar/bar_controller.js +3 -0
  32. data/test/lib/generators/marionette_dust/scaffold_and_submodule/templates/app/assets/javascripts/apps/foo/bar/bar_controller.js.coffee +2 -0
  33. data/test/lib/generators/marionette_dust/scaffold_and_submodule/templates/app/assets/javascripts/apps/foo/bar/bar_view.js +5 -0
  34. data/test/lib/generators/marionette_dust/scaffold_and_submodule/templates/app/assets/javascripts/apps/foo/bar/bar_view.js.coffee +3 -0
  35. data/test/lib/generators/marionette_dust/scaffold_and_submodule/templates/app/assets/javascripts/apps/test/test_app.js +13 -0
  36. data/test/lib/generators/marionette_dust/scaffold_and_submodule/templates/app/assets/javascripts/apps/test/test_app.js.coffee +8 -0
  37. data/test/lib/generators/marionette_dust/scaffold_and_submodule/templates/app/assets/javascripts/entities/test.js +9 -0
  38. data/test/lib/generators/marionette_dust/scaffold_and_submodule/templates/app/assets/javascripts/entities/test.js.coffee +7 -0
  39. data/test/lib/generators/marionette_dust/scaffold_and_submodule/templates/app/assets/templates/foo/bar/bar.jst.dust +1 -0
  40. data/test/test_helper.rb +23 -0
  41. data/vendor/assets/javascripts/marionette_dust/{dust-full-2.1.0.js → dust-full-2.2.2.js} +742 -673
  42. data/vendor/assets/javascripts/marionette_dust/index.js +1 -1
  43. metadata +57 -15
@@ -1,12 +1,13 @@
1
1
  //
2
- // Dust - Asynchronous Templating v2.1.0
2
+ // Dust - Asynchronous Templating v2.2.2
3
3
  // http://akdubya.github.com/dustjs
4
4
  //
5
5
  // Copyright (c) 2010, Aleksander Williams
6
6
  // Released under the MIT License.
7
7
  //
8
8
 
9
- var dust = {};
9
+ /*global console */
10
+ dust = {};
10
11
 
11
12
  function getGlobal(){
12
13
  return (function(){
@@ -16,768 +17,817 @@ function getGlobal(){
16
17
 
17
18
  (function(dust) {
18
19
 
19
- if(!dust) {
20
- return;
21
- }
22
- var ERROR = 'ERROR',
23
- WARN = 'WARN',
24
- INFO = 'INFO',
25
- DEBUG = 'DEBUG',
26
- levels = [DEBUG, INFO, WARN, ERROR],
27
- logger = function() {};
28
-
29
- dust.isDebug = false;
30
- dust.debugLevel = INFO;
31
-
32
- // Try to find the console logger in window scope (browsers) or top level scope (node.js)
33
- if (typeof window !== 'undefined' && window && window.console && window.console.log) {
34
- logger = window.console.log;
35
- } else if (typeof console !== 'undefined' && console && console.log) {
36
- logger = console.log;
37
- }
38
-
39
- /**
40
- * If dust.isDebug is true, Log dust debug statements, info statements, warning statements, and errors.
41
- * This default implementation will print to the console if it exists.
42
- * @param {String} message the message to print
43
- * @param {String} type the severity of the message(ERROR, WARN, INFO, or DEBUG)
44
- * @public
45
- */
46
- dust.log = function(message, type) {
47
- var type = type || INFO;
48
- if(dust.isDebug && levels.indexOf(type) >= levels.indexOf(dust.debugLevel)) {
49
- if(!dust.logQueue) {
50
- dust.logQueue = [];
51
- }
52
- dust.logQueue.push({message: message, type: type});
53
- logger.call(console || window.console, "[DUST " + type + "]: " + message);
20
+ if(!dust) {
21
+ return;
54
22
  }
55
- };
56
-
57
- /**
58
- * If debugging is turned on(dust.isDebug=true) log the error message and throw it.
59
- * Otherwise try to keep rendering. This is useful to fail hard in dev mode, but keep rendering in production.
60
- * @param {Error} error the error message to throw
61
- * @param {Object} chunk the chunk the error was thrown from
62
- * @public
63
- */
64
- dust.onError = function(error, chunk) {
65
- dust.log(error.message || error, ERROR);
66
- if(dust.isDebug) {
67
- throw error;
68
- } else {
69
- return chunk;
23
+ var ERROR = 'ERROR',
24
+ WARN = 'WARN',
25
+ INFO = 'INFO',
26
+ DEBUG = 'DEBUG',
27
+ levels = [DEBUG, INFO, WARN, ERROR],
28
+ logger = function() {};
29
+
30
+ dust.isDebug = false;
31
+ dust.debugLevel = INFO;
32
+
33
+ // Try to find the console logger in window scope (browsers) or top level scope (node.js)
34
+ if (typeof window !== 'undefined' && window && window.console && window.console.log) {
35
+ logger = window.console.log;
36
+ } else if (typeof console !== 'undefined' && console && console.log) {
37
+ logger = console.log;
70
38
  }
71
- };
72
39
 
73
- dust.helpers = {};
40
+ /**
41
+ * If dust.isDebug is true, Log dust debug statements, info statements, warning statements, and errors.
42
+ * This default implementation will print to the console if it exists.
43
+ * @param {String} message the message to print
44
+ * @param {String} type the severity of the message(ERROR, WARN, INFO, or DEBUG)
45
+ * @public
46
+ */
47
+ dust.log = function(message, type) {
48
+ var type = type || INFO;
49
+ if(dust.isDebug && levels.indexOf(type) >= levels.indexOf(dust.debugLevel)) {
50
+ if(!dust.logQueue) {
51
+ dust.logQueue = [];
52
+ }
53
+ dust.logQueue.push({message: message, type: type});
54
+ logger.call(console || window.console, '[DUST ' + type + ']: ' + message);
55
+ }
56
+ };
74
57
 
75
- dust.cache = {};
58
+ /**
59
+ * If debugging is turned on(dust.isDebug=true) log the error message and throw it.
60
+ * Otherwise try to keep rendering. This is useful to fail hard in dev mode, but keep rendering in production.
61
+ * @param {Error} error the error message to throw
62
+ * @param {Object} chunk the chunk the error was thrown from
63
+ * @public
64
+ */
65
+ dust.onError = function(error, chunk) {
66
+ dust.log(error.message || error, ERROR);
67
+ if(dust.isDebug) {
68
+ throw error;
69
+ } else {
70
+ return chunk;
71
+ }
72
+ };
76
73
 
77
- dust.register = function(name, tmpl) {
78
- if (!name) return;
79
- dust.cache[name] = tmpl;
80
- };
74
+ dust.helpers = {};
81
75
 
82
- dust.render = function(name, context, callback) {
83
- var chunk = new Stub(callback).head;
84
- try {
85
- dust.load(name, chunk, Context.wrap(context, name)).end();
86
- } catch (err) {
87
- dust.onError(err, chunk);
88
- }
89
- };
76
+ dust.cache = {};
77
+
78
+ dust.register = function(name, tmpl) {
79
+ if (!name) {
80
+ return;
81
+ }
82
+ dust.cache[name] = tmpl;
83
+ };
90
84
 
91
- dust.stream = function(name, context) {
92
- var stream = new Stream();
93
- dust.nextTick(function() {
85
+ dust.render = function(name, context, callback) {
86
+ var chunk = new Stub(callback).head;
94
87
  try {
95
- dust.load(name, stream.head, Context.wrap(context, name)).end();
88
+ dust.load(name, chunk, Context.wrap(context, name)).end();
96
89
  } catch (err) {
97
- dust.onError(err, stream.head);
90
+ dust.onError(err, chunk);
98
91
  }
99
- });
100
- return stream;
101
- };
102
-
103
- dust.renderSource = function(source, context, callback) {
104
- return dust.compileFn(source)(context, callback);
105
- };
92
+ };
106
93
 
107
- dust.compileFn = function(source, name) {
108
- var tmpl = dust.loadSource(dust.compile(source, name));
109
- return function(context, callback) {
110
- var master = callback ? new Stub(callback) : new Stream();
94
+ dust.stream = function(name, context) {
95
+ var stream = new Stream();
111
96
  dust.nextTick(function() {
112
- if(typeof tmpl === 'function') {
113
- tmpl(master.head, Context.wrap(context, name)).end();
114
- }
115
- else {
116
- dust.onError(new Error('Template [' + name + '] cannot be resolved to a Dust function'));
97
+ try {
98
+ dust.load(name, stream.head, Context.wrap(context, name)).end();
99
+ } catch (err) {
100
+ dust.onError(err, stream.head);
117
101
  }
118
102
  });
119
- return master;
103
+ return stream;
120
104
  };
121
- };
122
105
 
123
- dust.load = function(name, chunk, context) {
124
- var tmpl = dust.cache[name];
125
- if (tmpl) {
126
- return tmpl(chunk, context);
127
- } else {
128
- if (dust.onLoad) {
129
- return chunk.map(function(chunk) {
130
- dust.onLoad(name, function(err, src) {
131
- if (err) return chunk.setError(err);
132
- if (!dust.cache[name]) dust.loadSource(dust.compile(src, name));
133
- dust.cache[name](chunk, context).end();
134
- });
106
+ dust.renderSource = function(source, context, callback) {
107
+ return dust.compileFn(source)(context, callback);
108
+ };
109
+
110
+ dust.compileFn = function(source, name) {
111
+ var tmpl = dust.loadSource(dust.compile(source, name));
112
+ return function(context, callback) {
113
+ var master = callback ? new Stub(callback) : new Stream();
114
+ dust.nextTick(function() {
115
+ if(typeof tmpl === 'function') {
116
+ tmpl(master.head, Context.wrap(context, name)).end();
117
+ }
118
+ else {
119
+ dust.onError(new Error('Template [' + name + '] cannot be resolved to a Dust function'));
120
+ }
135
121
  });
136
- }
137
- return chunk.setError(new Error("Template Not Found: " + name));
138
- }
139
- };
122
+ return master;
123
+ };
124
+ };
140
125
 
141
- dust.loadSource = function(source, path) {
142
- return eval(source);
143
- };
126
+ dust.load = function(name, chunk, context) {
127
+ var tmpl = dust.cache[name];
128
+ if (tmpl) {
129
+ return tmpl(chunk, context);
130
+ } else {
131
+ if (dust.onLoad) {
132
+ return chunk.map(function(chunk) {
133
+ dust.onLoad(name, function(err, src) {
134
+ if (err) {
135
+ return chunk.setError(err);
136
+ }
137
+ if (!dust.cache[name]) {
138
+ dust.loadSource(dust.compile(src, name));
139
+ }
140
+ dust.cache[name](chunk, context).end();
141
+ });
142
+ });
143
+ }
144
+ return chunk.setError(new Error('Template Not Found: ' + name));
145
+ }
146
+ };
144
147
 
145
- if (Array.isArray) {
146
- dust.isArray = Array.isArray;
147
- } else {
148
- dust.isArray = function(arr) {
149
- return Object.prototype.toString.call(arr) === "[object Array]";
148
+ dust.loadSource = function(source, path) {
149
+ return eval(source);
150
150
  };
151
- }
152
151
 
153
- dust.nextTick = (function() {
154
- if (typeof process !== "undefined") {
155
- return process.nextTick;
152
+ if (Array.isArray) {
153
+ dust.isArray = Array.isArray;
156
154
  } else {
157
- return function(callback) {
158
- setTimeout(callback,0);
155
+ dust.isArray = function(arr) {
156
+ return Object.prototype.toString.call(arr) === '[object Array]';
159
157
  };
160
158
  }
161
- } )();
162
159
 
163
- dust.isEmpty = function(value) {
164
- if (dust.isArray(value) && !value.length) return true;
165
- if (value === 0) return false;
166
- return (!value);
167
- };
160
+ dust.nextTick = (function() {
161
+ if (typeof process !== 'undefined') {
162
+ return process.nextTick;
163
+ } else {
164
+ return function(callback) {
165
+ setTimeout(callback,0);
166
+ };
167
+ }
168
+ } )();
169
+
170
+ dust.isEmpty = function(value) {
171
+ if (dust.isArray(value) && !value.length) {
172
+ return true;
173
+ }
174
+ if (value === 0) {
175
+ return false;
176
+ }
177
+ return (!value);
178
+ };
168
179
 
169
- // apply the filter chain and return the output string
170
- dust.filter = function(string, auto, filters) {
171
- if (filters) {
172
- for (var i=0, len=filters.length; i<len; i++) {
173
- var name = filters[i];
174
- if (name === "s") {
175
- auto = null;
176
- dust.log('Using unescape filter on [' + string + ']', DEBUG);
180
+ // apply the filter chain and return the output string
181
+ dust.filter = function(string, auto, filters) {
182
+ if (filters) {
183
+ for (var i=0, len=filters.length; i<len; i++) {
184
+ var name = filters[i];
185
+ if (name === 's') {
186
+ auto = null;
187
+ dust.log('Using unescape filter on [' + string + ']', DEBUG);
188
+ }
189
+ else if (typeof dust.filters[name] === 'function') {
190
+ string = dust.filters[name](string);
191
+ }
192
+ else {
193
+ dust.onError(new Error('Invalid filter [' + name + ']'));
194
+ }
177
195
  }
178
- else if (typeof dust.filters[name] === 'function') {
179
- string = dust.filters[name](string);
196
+ }
197
+ // by default always apply the h filter, unless asked to unescape with |s
198
+ if (auto) {
199
+ string = dust.filters[auto](string);
200
+ }
201
+ return string;
202
+ };
203
+
204
+ dust.filters = {
205
+ h: function(value) { return dust.escapeHtml(value); },
206
+ j: function(value) { return dust.escapeJs(value); },
207
+ u: encodeURI,
208
+ uc: encodeURIComponent,
209
+ js: function(value) {
210
+ if (!JSON) {
211
+ dust.log('JSON is undefined. JSON stringify has not been used on [' + value + ']', WARN);
212
+ return value;
213
+ } else {
214
+ return JSON.stringify(value);
180
215
  }
181
- else {
182
- dust.onError(new Error('Invalid filter [' + name + ']'));
216
+ },
217
+ jp: function(value) {
218
+ if (!JSON) {dust.log('JSON is undefined. JSON parse has not been used on [' + value + ']', WARN);
219
+ return value;
220
+ } else {
221
+ return JSON.parse(value);
183
222
  }
184
223
  }
224
+ };
225
+
226
+ function Context(stack, global, blocks, templateName) {
227
+ this.stack = stack;
228
+ this.global = global;
229
+ this.blocks = blocks;
230
+ this.templateName = templateName;
185
231
  }
186
- // by default always apply the h filter, unless asked to unescape with |s
187
- if (auto) {
188
- string = dust.filters[auto](string);
189
- }
190
- return string;
191
- };
192
232
 
193
- dust.filters = {
194
- h: function(value) { return dust.escapeHtml(value); },
195
- j: function(value) { return dust.escapeJs(value); },
196
- u: encodeURI,
197
- uc: encodeURIComponent,
198
- js: function(value) {
199
- if (!JSON) {
200
- dust.log('JSON is undefined. JSON stringify has not been used on [' + value + ']', WARN);
201
- return value;
202
- } else {
203
- return JSON.stringify(value);
204
- }
205
- },
206
- jp: function(value) {
207
- if (!JSON) {dust.log('JSON is undefined. JSON parse has not been used on [' + value + ']', WARN);
208
- return value;
209
- } else {
210
- return JSON.parse(value);
233
+ dust.makeBase = function(global) {
234
+ return new Context(new Stack(), global);
235
+ };
236
+
237
+ Context.wrap = function(context, name) {
238
+ if (context instanceof Context) {
239
+ return context;
211
240
  }
212
- }
213
- };
241
+ return new Context(new Stack(context), {}, null, name);
242
+ };
214
243
 
215
- function Context(stack, global, blocks, templateName) {
216
- this.stack = stack;
217
- this.global = global;
218
- this.blocks = blocks;
219
- this.templateName = templateName;
220
- }
244
+ /**
245
+ * Public API for getting a value from the context.
246
+ * @method get
247
+ * @param {string|array} path The path to the value. Supported formats are:
248
+ * 'key'
249
+ * 'path.to.key'
250
+ * '.path.to.key'
251
+ * ['path', 'to', 'key']
252
+ * ['key']
253
+ * @param {boolean} [cur=false] Boolean which determines if the search should be limited to the
254
+ * current context (true), or if get should search in parent contexts as well (false).
255
+ * @public
256
+ * @returns {string|object}
257
+ */
258
+ Context.prototype.get = function(path, cur) {
259
+ if (typeof path === 'string') {
260
+ if (path[0] === '.') {
261
+ cur = true;
262
+ path = path.substr(1);
263
+ }
264
+ path = path.split('.');
265
+ }
266
+ return this._get(cur, path);
267
+ };
221
268
 
222
- dust.makeBase = function(global) {
223
- return new Context(new Stack(), global);
224
- };
269
+ /**
270
+ * Get a value from the context
271
+ * @method _get
272
+ * @param {boolean} cur Get only from the current context
273
+ * @param {array} down An array of each step in the path
274
+ * @private
275
+ * @return {string | object}
276
+ */
277
+ Context.prototype._get = function(cur, down) {
278
+ var ctx = this.stack,
279
+ i = 1,
280
+ value, first, len, ctxThis;
281
+ dust.log('Searching for reference [{' + down.join('.') + '}] in template [' + this.getTemplateName() + ']', DEBUG);
282
+ first = down[0];
283
+ len = down.length;
284
+
285
+ if (cur && len === 0) {
286
+ ctxThis = ctx;
287
+ ctx = ctx.head;
288
+ } else {
289
+ if (!cur) {
290
+ // Search up the stack for the first value
291
+ while (ctx) {
292
+ if (ctx.isObject) {
293
+ ctxThis = ctx.head;
294
+ value = ctx.head[first];
295
+ if (value !== undefined) {
296
+ break;
297
+ }
298
+ }
299
+ ctx = ctx.tail;
300
+ }
225
301
 
226
- Context.wrap = function(context, name) {
227
- if (context instanceof Context) {
228
- return context;
229
- }
230
- return new Context(new Stack(context), {}, null, name);
231
- };
302
+ if (value !== undefined) {
303
+ ctx = value;
304
+ } else {
305
+ ctx = this.global ? this.global[first] : undefined;
306
+ }
307
+ } else {
308
+ // if scope is limited by a leading dot, don't search up the tree
309
+ ctx = ctx.head[first];
310
+ }
232
311
 
233
- Context.prototype.get = function(key) {
234
- var ctx = this.stack, value, globalValue;
235
- dust.log('Searching for reference [{' + key + '}] in template [' + this.templateName + ']', DEBUG);
236
- while(ctx) {
237
- if (ctx.isObject) {
238
- value = ctx.head[key];
239
- if (!(value === undefined)) {
240
- return value;
312
+ while (ctx && i < len) {
313
+ ctxThis = ctx;
314
+ ctx = ctx[down[i]];
315
+ i++;
241
316
  }
242
317
  }
243
- ctx = ctx.tail;
244
- }
245
- globalValue = this.global ? this.global[key] : undefined;
246
- if(typeof globalValue === 'undefined') {
247
- dust.log('Cannot find the value for reference [{' + key + '}] in template [' + this.templateName + ']');
248
- }
249
- return globalValue;
250
- };
251
318
 
252
- //supports dot path resolution, function wrapped apply, and searching global paths
253
- Context.prototype.getPath = function(cur, down) {
254
- var ctx = this.stack, ctxThis,
255
- len = down.length,
256
- tail = cur ? undefined : this.stack.tail;
257
-
258
- dust.log('Searching for reference [{' + down.join('.') + '}] in template [' + this.templateName + ']', DEBUG);
259
- if (cur && len === 0) return ctx.head;
260
- ctx = ctx.head;
261
- var i = 0;
262
- while(ctx && i < len) {
263
- ctxThis = ctx;
264
- ctx = ctx[down[i]];
265
- i++;
266
- while (!ctx && !cur){
267
- // i is the count of number of path elements matched. If > 1 then we have a partial match
268
- // and do not continue to search for the rest of the path.
269
- // Note: a falsey value at the end of a matched path also comes here.
270
- // This returns the value or undefined if we just have a partial match.
271
- if (i > 1) return ctx;
272
- if (tail){
273
- ctx = tail.head;
274
- tail = tail.tail;
275
- i=0;
276
- } else if (!cur) {
277
- //finally search this.global. we set cur to true to halt after
278
- ctx = this.global;
279
- cur = true;
280
- i=0;
281
- }
319
+ // Return the ctx or a function wrapping the application of the context.
320
+ if (typeof ctx === 'function') {
321
+ var fn = function() {
322
+ return ctx.apply(ctxThis, arguments);
323
+ };
324
+ fn.isFunction = true;
325
+ return fn;
326
+ } else {
327
+ if (ctx === undefined) {
328
+ dust.log('Cannot find the value for reference [{' + down.join('.') + '}] in template [' + this.getTemplateName() + ']');
329
+ }
330
+ return ctx;
282
331
  }
283
- }
284
- if (typeof ctx == 'function'){
285
- //wrap to preserve context 'this' see #174
286
- return function(){
287
- return ctx.apply(ctxThis,arguments);
288
- };
289
- }
290
- else {
291
- return ctx;
292
- }
293
- };
294
-
295
- Context.prototype.push = function(head, idx, len) {
296
- return new Context(new Stack(head, this.stack, idx, len), this.global, this.blocks, this.templateName);
297
- };
332
+ };
298
333
 
299
- Context.prototype.rebase = function(head) {
300
- return new Context(new Stack(head), this.global, this.blocks, this.templateName);
301
- };
334
+ Context.prototype.getPath = function(cur, down) {
335
+ return this._get(cur, down);
336
+ };
302
337
 
303
- Context.prototype.current = function() {
304
- return this.stack.head;
305
- };
338
+ Context.prototype.push = function(head, idx, len) {
339
+ return new Context(new Stack(head, this.stack, idx, len), this.global, this.blocks, this.getTemplateName());
340
+ };
306
341
 
307
- Context.prototype.getBlock = function(key, chk, ctx) {
308
- if (typeof key === "function") {
309
- var tempChk = new Chunk();
310
- key = key(tempChk, this).data.join("");
311
- }
342
+ Context.prototype.rebase = function(head) {
343
+ return new Context(new Stack(head), this.global, this.blocks, this.getTemplateName());
344
+ };
312
345
 
313
- var blocks = this.blocks;
346
+ Context.prototype.current = function() {
347
+ return this.stack.head;
348
+ };
314
349
 
315
- if (!blocks) {
316
- dust.log('No blocks for context[{' + key + '}] in template [' + this.templateName + ']', DEBUG);
317
- return;
318
- }
319
- var len = blocks.length, fn;
320
- while (len--) {
321
- fn = blocks[len][key];
322
- if (fn) return fn;
323
- }
324
- };
350
+ Context.prototype.getBlock = function(key, chk, ctx) {
351
+ if (typeof key === 'function') {
352
+ var tempChk = new Chunk();
353
+ key = key(tempChk, this).data.join('');
354
+ }
325
355
 
326
- Context.prototype.shiftBlocks = function(locals) {
327
- var blocks = this.blocks,
328
- newBlocks;
356
+ var blocks = this.blocks;
329
357
 
330
- if (locals) {
331
358
  if (!blocks) {
332
- newBlocks = [locals];
333
- } else {
334
- newBlocks = blocks.concat([locals]);
359
+ dust.log('No blocks for context[{' + key + '}] in template [' + this.getTemplateName() + ']', DEBUG);
360
+ return;
335
361
  }
336
- return new Context(this.stack, this.global, newBlocks, this.templateName);
337
- }
338
- return this;
339
- };
340
-
341
- function Stack(head, tail, idx, len) {
342
- this.tail = tail;
343
- this.isObject = !dust.isArray(head) && head && typeof head === "object";
344
- this.head = head;
345
- this.index = idx;
346
- this.of = len;
347
- }
348
-
349
- function Stub(callback) {
350
- this.head = new Chunk(this);
351
- this.callback = callback;
352
- this.out = '';
353
- }
362
+ var len = blocks.length, fn;
363
+ while (len--) {
364
+ fn = blocks[len][key];
365
+ if (fn) {
366
+ return fn;
367
+ }
368
+ }
369
+ };
354
370
 
355
- Stub.prototype.flush = function() {
356
- var chunk = this.head;
371
+ Context.prototype.shiftBlocks = function(locals) {
372
+ var blocks = this.blocks,
373
+ newBlocks;
357
374
 
358
- while (chunk) {
359
- if (chunk.flushable) {
360
- this.out += chunk.data.join(""); //ie7 perf
361
- } else if (chunk.error) {
362
- this.callback(chunk.error);
363
- dust.onError(new Error('Chunk error [' + chunk.error + '] thrown. Ceasing to render this template.'));
364
- this.flush = function() {};
365
- return;
366
- } else {
367
- return;
375
+ if (locals) {
376
+ if (!blocks) {
377
+ newBlocks = [locals];
378
+ } else {
379
+ newBlocks = blocks.concat([locals]);
380
+ }
381
+ return new Context(this.stack, this.global, newBlocks, this.getTemplateName());
368
382
  }
369
- chunk = chunk.next;
370
- this.head = chunk;
383
+ return this;
384
+ };
385
+
386
+ Context.prototype.getTemplateName = function() {
387
+ return this.templateName;
371
388
  }
372
- this.callback(null, this.out);
373
- };
374
389
 
375
- function Stream() {
376
- this.head = new Chunk(this);
377
- }
390
+ function Stack(head, tail, idx, len) {
391
+ this.tail = tail;
392
+ this.isObject = !dust.isArray(head) && head && typeof head === 'object';
393
+ this.head = head;
394
+ this.index = idx;
395
+ this.of = len;
396
+ }
378
397
 
379
- Stream.prototype.flush = function() {
380
- var chunk = this.head;
398
+ function Stub(callback) {
399
+ this.head = new Chunk(this);
400
+ this.callback = callback;
401
+ this.out = '';
402
+ }
381
403
 
382
- while(chunk) {
383
- if (chunk.flushable) {
384
- this.emit('data', chunk.data.join("")); //ie7 perf
385
- } else if (chunk.error) {
386
- this.emit('error', chunk.error);
387
- dust.onError(new Error('Chunk error [' + chunk.error + '] thrown. Ceasing to render this template.'));
388
- this.flush = function() {};
389
- return;
390
- } else {
391
- return;
404
+ Stub.prototype.flush = function() {
405
+ var chunk = this.head;
406
+
407
+ while (chunk) {
408
+ if (chunk.flushable) {
409
+ this.out += chunk.data.join(''); //ie7 perf
410
+ } else if (chunk.error) {
411
+ this.callback(chunk.error);
412
+ dust.onError(new Error('Chunk error [' + chunk.error + '] thrown. Ceasing to render this template.'));
413
+ this.flush = function() {};
414
+ return;
415
+ } else {
416
+ return;
417
+ }
418
+ chunk = chunk.next;
419
+ this.head = chunk;
392
420
  }
393
- chunk = chunk.next;
394
- this.head = chunk;
395
- }
396
- this.emit('end');
397
- };
421
+ this.callback(null, this.out);
422
+ };
398
423
 
399
- Stream.prototype.emit = function(type, data) {
400
- if (!this.events) {
401
- dust.log('No events to emit', INFO);
402
- return false;
424
+ function Stream() {
425
+ this.head = new Chunk(this);
403
426
  }
404
- var handler = this.events[type];
405
- if (!handler) {
406
- dust.log('Event type [' + type + '] does not exist', WARN);
407
- return false;
408
- }
409
- if (typeof handler === 'function') {
410
- handler(data);
411
- } else if (dust.isArray(handler)) {
412
- var listeners = handler.slice(0);
413
- for (var i = 0, l = listeners.length; i < l; i++) {
414
- listeners[i](data);
427
+
428
+ Stream.prototype.flush = function() {
429
+ var chunk = this.head;
430
+
431
+ while(chunk) {
432
+ if (chunk.flushable) {
433
+ this.emit('data', chunk.data.join('')); //ie7 perf
434
+ } else if (chunk.error) {
435
+ this.emit('error', chunk.error);
436
+ dust.onError(new Error('Chunk error [' + chunk.error + '] thrown. Ceasing to render this template.'));
437
+ this.flush = function() {};
438
+ return;
439
+ } else {
440
+ return;
441
+ }
442
+ chunk = chunk.next;
443
+ this.head = chunk;
415
444
  }
416
- } else {
417
- dust.onError(new Error('Event Handler [' + handler + '] is not of a type that is handled by emit'));
418
- }
419
- };
445
+ this.emit('end');
446
+ };
420
447
 
421
- Stream.prototype.on = function(type, callback) {
422
- if (!this.events) {
423
- this.events = {};
424
- }
425
- if (!this.events[type]) {
426
- dust.log('Event type [' + type + '] does not exist. Using just the specified callback.', WARN);
427
- if(callback) {
428
- this.events[type] = callback;
448
+ Stream.prototype.emit = function(type, data) {
449
+ if (!this.events) {
450
+ dust.log('No events to emit', INFO);
451
+ return false;
452
+ }
453
+ var handler = this.events[type];
454
+ if (!handler) {
455
+ dust.log('Event type [' + type + '] does not exist', WARN);
456
+ return false;
457
+ }
458
+ if (typeof handler === 'function') {
459
+ handler(data);
460
+ } else if (dust.isArray(handler)) {
461
+ var listeners = handler.slice(0);
462
+ for (var i = 0, l = listeners.length; i < l; i++) {
463
+ listeners[i](data);
464
+ }
429
465
  } else {
430
- dust.log('Callback for type [' + type + '] does not exist. Listener not registered.', WARN);
466
+ dust.onError(new Error('Event Handler [' + handler + '] is not of a type that is handled by emit'));
431
467
  }
432
- } else if(typeof this.events[type] === 'function') {
433
- this.events[type] = [this.events[type], callback];
434
- } else {
435
- this.events[type].push(callback);
436
- }
437
- return this;
438
- };
468
+ };
439
469
 
440
- Stream.prototype.pipe = function(stream) {
441
- this.on("data", function(data) {
442
- try {
443
- stream.write(data, "utf8");
444
- } catch (err) {
445
- dust.onError(err, stream.head);
470
+ Stream.prototype.on = function(type, callback) {
471
+ if (!this.events) {
472
+ this.events = {};
446
473
  }
447
- }).on("end", function() {
448
- try {
449
- return stream.end();
450
- } catch (err) {
451
- dust.onError(err, stream.head);
474
+ if (!this.events[type]) {
475
+ dust.log('Event type [' + type + '] does not exist. Using just the specified callback.', WARN);
476
+ if(callback) {
477
+ this.events[type] = callback;
478
+ } else {
479
+ dust.log('Callback for type [' + type + '] does not exist. Listener not registered.', WARN);
480
+ }
481
+ } else if(typeof this.events[type] === 'function') {
482
+ this.events[type] = [this.events[type], callback];
483
+ } else {
484
+ this.events[type].push(callback);
452
485
  }
453
- }).on("error", function(err) {
454
- stream.error(err);
455
- });
456
- return this;
457
- };
458
-
459
- function Chunk(root, next, taps) {
460
- this.root = root;
461
- this.next = next;
462
- this.data = []; //ie7 perf
463
- this.flushable = false;
464
- this.taps = taps;
465
- }
466
-
467
- Chunk.prototype.write = function(data) {
468
- var taps = this.taps;
486
+ return this;
487
+ };
469
488
 
470
- if (taps) {
471
- data = taps.go(data);
472
- }
473
- this.data.push(data);
474
- return this;
475
- };
489
+ Stream.prototype.pipe = function(stream) {
490
+ this.on('data', function(data) {
491
+ try {
492
+ stream.write(data, 'utf8');
493
+ } catch (err) {
494
+ dust.onError(err, stream.head);
495
+ }
496
+ }).on('end', function() {
497
+ try {
498
+ return stream.end();
499
+ } catch (err) {
500
+ dust.onError(err, stream.head);
501
+ }
502
+ }).on('error', function(err) {
503
+ stream.error(err);
504
+ });
505
+ return this;
506
+ };
476
507
 
477
- Chunk.prototype.end = function(data) {
478
- if (data) {
479
- this.write(data);
508
+ function Chunk(root, next, taps) {
509
+ this.root = root;
510
+ this.next = next;
511
+ this.data = []; //ie7 perf
512
+ this.flushable = false;
513
+ this.taps = taps;
480
514
  }
481
- this.flushable = true;
482
- this.root.flush();
483
- return this;
484
- };
485
515
 
486
- Chunk.prototype.map = function(callback) {
487
- var cursor = new Chunk(this.root, this.next, this.taps),
488
- branch = new Chunk(this.root, cursor, this.taps);
516
+ Chunk.prototype.write = function(data) {
517
+ var taps = this.taps;
489
518
 
490
- this.next = branch;
491
- this.flushable = true;
492
- callback(branch);
493
- return cursor;
494
- };
519
+ if (taps) {
520
+ data = taps.go(data);
521
+ }
522
+ this.data.push(data);
523
+ return this;
524
+ };
495
525
 
496
- Chunk.prototype.tap = function(tap) {
497
- var taps = this.taps;
526
+ Chunk.prototype.end = function(data) {
527
+ if (data) {
528
+ this.write(data);
529
+ }
530
+ this.flushable = true;
531
+ this.root.flush();
532
+ return this;
533
+ };
498
534
 
499
- if (taps) {
500
- this.taps = taps.push(tap);
501
- } else {
502
- this.taps = new Tap(tap);
503
- }
504
- return this;
505
- };
535
+ Chunk.prototype.map = function(callback) {
536
+ var cursor = new Chunk(this.root, this.next, this.taps),
537
+ branch = new Chunk(this.root, cursor, this.taps);
506
538
 
507
- Chunk.prototype.untap = function() {
508
- this.taps = this.taps.tail;
509
- return this;
510
- };
539
+ this.next = branch;
540
+ this.flushable = true;
541
+ callback(branch);
542
+ return cursor;
543
+ };
511
544
 
512
- Chunk.prototype.render = function(body, context) {
513
- return body(this, context);
514
- };
545
+ Chunk.prototype.tap = function(tap) {
546
+ var taps = this.taps;
515
547
 
516
- Chunk.prototype.reference = function(elem, context, auto, filters) {
517
- if (typeof elem === "function") {
518
- elem.isFunction = true;
519
- // Changed the function calling to use apply with the current context to make sure
520
- // that "this" is wat we expect it to be inside the function
521
- elem = elem.apply(context.current(), [this, context, null, {auto: auto, filters: filters}]);
522
- if (elem instanceof Chunk) {
523
- return elem;
548
+ if (taps) {
549
+ this.taps = taps.push(tap);
550
+ } else {
551
+ this.taps = new Tap(tap);
524
552
  }
525
- }
526
- if (!dust.isEmpty(elem)) {
527
- return this.write(dust.filter(elem, auto, filters));
528
- } else {
529
553
  return this;
530
- }
531
- };
554
+ };
555
+
556
+ Chunk.prototype.untap = function() {
557
+ this.taps = this.taps.tail;
558
+ return this;
559
+ };
560
+
561
+ Chunk.prototype.render = function(body, context) {
562
+ return body(this, context);
563
+ };
532
564
 
533
- Chunk.prototype.section = function(elem, context, bodies, params) {
534
- // anonymous functions
535
- if (typeof elem === "function") {
536
- elem = elem.apply(context.current(), [this, context, bodies, params]);
537
- // functions that return chunks are assumed to have handled the body and/or have modified the chunk
538
- // use that return value as the current chunk and go to the next method in the chain
539
- if (elem instanceof Chunk) {
540
- return elem;
565
+ Chunk.prototype.reference = function(elem, context, auto, filters) {
566
+ if (typeof elem === 'function') {
567
+ elem.isFunction = true;
568
+ // Changed the function calling to use apply with the current context to make sure
569
+ // that "this" is wat we expect it to be inside the function
570
+ elem = elem.apply(context.current(), [this, context, null, {auto: auto, filters: filters}]);
571
+ if (elem instanceof Chunk) {
572
+ return elem;
573
+ }
541
574
  }
542
- }
543
- var body = bodies.block,
544
- skip = bodies['else'];
575
+ if (!dust.isEmpty(elem)) {
576
+ return this.write(dust.filter(elem, auto, filters));
577
+ } else {
578
+ return this;
579
+ }
580
+ };
545
581
 
546
- // a.k.a Inline parameters in the Dust documentations
547
- if (params) {
548
- context = context.push(params);
549
- }
582
+ Chunk.prototype.section = function(elem, context, bodies, params) {
583
+ // anonymous functions
584
+ if (typeof elem === 'function') {
585
+ elem = elem.apply(context.current(), [this, context, bodies, params]);
586
+ // functions that return chunks are assumed to have handled the body and/or have modified the chunk
587
+ // use that return value as the current chunk and go to the next method in the chain
588
+ if (elem instanceof Chunk) {
589
+ return elem;
590
+ }
591
+ }
592
+ var body = bodies.block,
593
+ skip = bodies['else'];
550
594
 
551
- /*
552
- Dust's default behavior is to enumerate over the array elem, passing each object in the array to the block.
553
- When elem resolves to a value or object instead of an array, Dust sets the current context to the value
554
- and renders the block one time.
555
- */
556
- //non empty array is truthy, empty array is falsy
557
- if (dust.isArray(elem)) {
558
- if (body) {
559
- var len = elem.length, chunk = this;
560
- if (len > 0) {
561
- // any custom helper can blow up the stack
562
- // and store a flattened context, guard defensively
563
- if(context.stack.head) {
564
- context.stack.head['$len'] = len;
565
- }
566
- for (var i=0; i<len; i++) {
595
+ // a.k.a Inline parameters in the Dust documentations
596
+ if (params) {
597
+ context = context.push(params);
598
+ }
599
+
600
+ /*
601
+ Dust's default behavior is to enumerate over the array elem, passing each object in the array to the block.
602
+ When elem resolves to a value or object instead of an array, Dust sets the current context to the value
603
+ and renders the block one time.
604
+ */
605
+ //non empty array is truthy, empty array is falsy
606
+ if (dust.isArray(elem)) {
607
+ if (body) {
608
+ var len = elem.length, chunk = this;
609
+ if (len > 0) {
610
+ // any custom helper can blow up the stack
611
+ // and store a flattened context, guard defensively
612
+ if(context.stack.head) {
613
+ context.stack.head['$len'] = len;
614
+ }
615
+ for (var i=0; i<len; i++) {
616
+ if(context.stack.head) {
617
+ context.stack.head['$idx'] = i;
618
+ }
619
+ chunk = body(chunk, context.push(elem[i], i, len));
620
+ }
567
621
  if(context.stack.head) {
568
- context.stack.head['$idx'] = i;
622
+ context.stack.head['$idx'] = undefined;
623
+ context.stack.head['$len'] = undefined;
569
624
  }
570
- chunk = body(chunk, context.push(elem[i], i, len));
625
+ return chunk;
571
626
  }
572
- if(context.stack.head) {
573
- context.stack.head['$idx'] = undefined;
574
- context.stack.head['$len'] = undefined;
627
+ else if (skip) {
628
+ return skip(this, context);
575
629
  }
576
- return chunk;
577
630
  }
578
- else if (skip) {
579
- return skip(this, context);
580
- }
581
- }
582
- }
583
- // true is truthy but does not change context
584
- else if (elem === true) {
585
- if (body) {
631
+ } else if (elem === true) {
632
+ // true is truthy but does not change context
633
+ if (body) {
586
634
  return body(this, context);
587
- }
588
- }
589
- // everything that evaluates to true are truthy ( e.g. Non-empty strings and Empty objects are truthy. )
590
- // zero is truthy
591
- // for anonymous functions that did not returns a chunk, truthiness is evaluated based on the return value
592
- //
593
- else if (elem || elem === 0) {
594
- if (body) return body(this, context.push(elem));
595
- // nonexistent, scalar false value, scalar empty string, null,
596
- // undefined are all falsy
597
- } else if (skip) {
598
- return skip(this, context);
599
- }
600
- dust.log('Not rendering section (#) block in template [' + context.templateName + '], because above key was not found', DEBUG);
601
- return this;
602
- };
635
+ }
636
+ } else if (elem || elem === 0) {
637
+ // everything that evaluates to true are truthy ( e.g. Non-empty strings and Empty objects are truthy. )
638
+ // zero is truthy
639
+ // for anonymous functions that did not returns a chunk, truthiness is evaluated based on the return value
640
+ if (body) {
641
+ return body(this, context.push(elem));
642
+ }
643
+ // nonexistent, scalar false value, scalar empty string, null,
644
+ // undefined are all falsy
645
+ } else if (skip) {
646
+ return skip(this, context);
647
+ }
648
+ dust.log('Not rendering section (#) block in template [' + context.getTemplateName() + '], because above key was not found', DEBUG);
649
+ return this;
650
+ };
603
651
 
604
- Chunk.prototype.exists = function(elem, context, bodies) {
605
- var body = bodies.block,
606
- skip = bodies['else'];
652
+ Chunk.prototype.exists = function(elem, context, bodies) {
653
+ var body = bodies.block,
654
+ skip = bodies['else'];
607
655
 
608
- if (!dust.isEmpty(elem)) {
609
- if (body) return body(this, context);
610
- } else if (skip) {
611
- return skip(this, context);
612
- }
613
- dust.log('Not rendering exists (?) block in template [' + context.templateName + '], because above key was not found', DEBUG);
614
- return this;
615
- };
656
+ if (!dust.isEmpty(elem)) {
657
+ if (body) {
658
+ return body(this, context);
659
+ }
660
+ } else if (skip) {
661
+ return skip(this, context);
662
+ }
663
+ dust.log('Not rendering exists (?) block in template [' + context.getTemplateName() + '], because above key was not found', DEBUG);
664
+ return this;
665
+ };
616
666
 
617
- Chunk.prototype.notexists = function(elem, context, bodies) {
618
- var body = bodies.block,
619
- skip = bodies['else'];
667
+ Chunk.prototype.notexists = function(elem, context, bodies) {
668
+ var body = bodies.block,
669
+ skip = bodies['else'];
620
670
 
621
- if (dust.isEmpty(elem)) {
622
- if (body) return body(this, context);
623
- } else if (skip) {
624
- return skip(this, context);
625
- }
626
- dust.log('Not rendering not exists (^) block check in template [' + context.templateName + '], because above key was found', DEBUG);
627
- return this;
628
- };
671
+ if (dust.isEmpty(elem)) {
672
+ if (body) {
673
+ return body(this, context);
674
+ }
675
+ } else if (skip) {
676
+ return skip(this, context);
677
+ }
678
+ dust.log('Not rendering not exists (^) block check in template [' + context.getTemplateName() + '], because above key was found', DEBUG);
679
+ return this;
680
+ };
629
681
 
630
- Chunk.prototype.block = function(elem, context, bodies) {
631
- var body = bodies.block;
682
+ Chunk.prototype.block = function(elem, context, bodies) {
683
+ var body = bodies.block;
632
684
 
633
- if (elem) {
634
- body = elem;
635
- }
685
+ if (elem) {
686
+ body = elem;
687
+ }
636
688
 
637
- if (body) {
638
- return body(this, context);
639
- }
640
- return this;
641
- };
689
+ if (body) {
690
+ return body(this, context);
691
+ }
692
+ return this;
693
+ };
642
694
 
643
- Chunk.prototype.partial = function(elem, context, params) {
644
- var partialContext;
645
- //put the params context second to match what section does. {.} matches the current context without parameters
646
- // start with an empty context
647
- partialContext = dust.makeBase(context.global);
648
- partialContext.blocks = context.blocks;
649
- if (context.stack && context.stack.tail){
650
- // grab the stack(tail) off of the previous context if we have it
651
- partialContext.stack = context.stack.tail;
652
- }
653
- if (params){
654
- //put params on
655
- partialContext = partialContext.push(params);
656
- }
657
- // templateName can be static (string) or dynamic (function)
658
- // e.g. {>"static_template"/}
659
- // {>"{dynamic_template}"/}
660
- if (elem) {
661
- partialContext.templateName = elem;
662
- }
695
+ Chunk.prototype.partial = function(elem, context, params) {
696
+ var partialContext;
697
+ //put the params context second to match what section does. {.} matches the current context without parameters
698
+ // start with an empty context
699
+ partialContext = dust.makeBase(context.global);
700
+ partialContext.blocks = context.blocks;
701
+ if (context.stack && context.stack.tail){
702
+ // grab the stack(tail) off of the previous context if we have it
703
+ partialContext.stack = context.stack.tail;
704
+ }
705
+ if (params){
706
+ //put params on
707
+ partialContext = partialContext.push(params);
708
+ }
663
709
 
664
- //reattach the head
665
- partialContext = partialContext.push(context.stack.head);
666
-
667
- var partialChunk;
668
- if (typeof elem === "function") {
669
- partialChunk = this.capture(elem, partialContext, function(name, chunk) {
670
- dust.load(name, chunk, partialContext).end();
671
- });
672
- }
673
- else {
674
- partialChunk = dust.load(elem, this, partialContext);
675
- }
676
- return partialChunk;
677
- };
710
+ if(typeof elem === 'string') {
711
+ partialContext.templateName = elem;
712
+ }
678
713
 
679
- Chunk.prototype.helper = function(name, context, bodies, params) {
680
- var chunk = this;
681
- // handle invalid helpers, similar to invalid filters
682
- try {
683
- if(dust.helpers[name]) {
684
- return dust.helpers[name](chunk, context, bodies, params);
714
+ //reattach the head
715
+ partialContext = partialContext.push(context.stack.head);
716
+
717
+ var partialChunk;
718
+ if (typeof elem === 'function') {
719
+ partialChunk = this.capture(elem, partialContext, function(name, chunk) {
720
+ partialContext.templateName = partialContext.templateName || name;
721
+ dust.load(name, chunk, partialContext).end();
722
+ });
685
723
  } else {
686
- return dust.onError(new Error('Invalid helper [' + name + ']'), chunk);
724
+ partialChunk = dust.load(elem, this, partialContext);
687
725
  }
688
- } catch (err) {
689
- return dust.onError(err, chunk);
690
- }
691
- };
726
+ return partialChunk;
727
+ };
692
728
 
693
- Chunk.prototype.capture = function(body, context, callback) {
694
- return this.map(function(chunk) {
695
- var stub = new Stub(function(err, out) {
696
- if (err) {
697
- chunk.setError(err);
729
+ Chunk.prototype.helper = function(name, context, bodies, params) {
730
+ var chunk = this;
731
+ // handle invalid helpers, similar to invalid filters
732
+ try {
733
+ if(dust.helpers[name]) {
734
+ return dust.helpers[name](chunk, context, bodies, params);
698
735
  } else {
699
- callback(out, chunk);
736
+ return dust.onError(new Error('Invalid helper [' + name + ']'), chunk);
700
737
  }
738
+ } catch (err) {
739
+ return dust.onError(err, chunk);
740
+ }
741
+ };
742
+
743
+ Chunk.prototype.capture = function(body, context, callback) {
744
+ return this.map(function(chunk) {
745
+ var stub = new Stub(function(err, out) {
746
+ if (err) {
747
+ chunk.setError(err);
748
+ } else {
749
+ callback(out, chunk);
750
+ }
751
+ });
752
+ body(stub.head, context).end();
701
753
  });
702
- body(stub.head, context).end();
703
- });
704
- };
754
+ };
705
755
 
706
- Chunk.prototype.setError = function(err) {
707
- this.error = err;
708
- this.root.flush();
709
- return this;
710
- };
756
+ Chunk.prototype.setError = function(err) {
757
+ this.error = err;
758
+ this.root.flush();
759
+ return this;
760
+ };
711
761
 
712
- function Tap(head, tail) {
713
- this.head = head;
714
- this.tail = tail;
715
- }
762
+ function Tap(head, tail) {
763
+ this.head = head;
764
+ this.tail = tail;
765
+ }
716
766
 
717
- Tap.prototype.push = function(tap) {
718
- return new Tap(tap, this);
719
- };
767
+ Tap.prototype.push = function(tap) {
768
+ return new Tap(tap, this);
769
+ };
720
770
 
721
- Tap.prototype.go = function(value) {
722
- var tap = this;
771
+ Tap.prototype.go = function(value) {
772
+ var tap = this;
723
773
 
724
- while(tap) {
725
- value = tap.head(value);
726
- tap = tap.tail;
727
- }
728
- return value;
729
- };
774
+ while(tap) {
775
+ value = tap.head(value);
776
+ tap = tap.tail;
777
+ }
778
+ return value;
779
+ };
730
780
 
731
- var HCHARS = new RegExp(/[&<>\"\']/),
732
- AMP = /&/g,
733
- LT = /</g,
734
- GT = />/g,
735
- QUOT = /\"/g,
736
- SQUOT = /\'/g;
737
-
738
- dust.escapeHtml = function(s) {
739
- if (typeof s === "string") {
740
- if (!HCHARS.test(s)) {
741
- return s;
781
+ var HCHARS = new RegExp(/[&<>\"\']/),
782
+ AMP = /&/g,
783
+ LT = /</g,
784
+ GT = />/g,
785
+ QUOT = /\"/g,
786
+ SQUOT = /\'/g;
787
+
788
+ dust.escapeHtml = function(s) {
789
+ if (typeof s === 'string') {
790
+ if (!HCHARS.test(s)) {
791
+ return s;
792
+ }
793
+ return s.replace(AMP,'&amp;').replace(LT,'&lt;').replace(GT,'&gt;').replace(QUOT,'&quot;').replace(SQUOT, '&#39;');
742
794
  }
743
- return s.replace(AMP,'&amp;').replace(LT,'&lt;').replace(GT,'&gt;').replace(QUOT,'&quot;').replace(SQUOT, '&#39;');
744
- }
745
- return s;
746
- };
795
+ return s;
796
+ };
747
797
 
748
- var BS = /\\/g,
749
- FS = /\//g,
750
- CR = /\r/g,
751
- LS = /\u2028/g,
752
- PS = /\u2029/g,
753
- NL = /\n/g,
754
- LF = /\f/g,
755
- SQ = /'/g,
756
- DQ = /"/g,
757
- TB = /\t/g;
758
-
759
- dust.escapeJs = function(s) {
760
- if (typeof s === "string") {
761
- return s
762
- .replace(BS, '\\\\')
763
- .replace(FS, '\\/')
764
- .replace(DQ, '\\"')
765
- .replace(SQ, "\\'")
766
- .replace(CR, '\\r')
767
- .replace(LS, '\\u2028')
768
- .replace(PS, '\\u2029')
769
- .replace(NL, '\\n')
770
- .replace(LF, '\\f')
771
- .replace(TB, "\\t");
772
- }
773
- return s;
774
- };
798
+ var BS = /\\/g,
799
+ FS = /\//g,
800
+ CR = /\r/g,
801
+ LS = /\u2028/g,
802
+ PS = /\u2029/g,
803
+ NL = /\n/g,
804
+ LF = /\f/g,
805
+ SQ = /'/g,
806
+ DQ = /"/g,
807
+ TB = /\t/g;
808
+
809
+ dust.escapeJs = function(s) {
810
+ if (typeof s === 'string') {
811
+ return s
812
+ .replace(BS, '\\\\')
813
+ .replace(FS, '\\/')
814
+ .replace(DQ, '\\"')
815
+ .replace(SQ, '\\\'')
816
+ .replace(CR, '\\r')
817
+ .replace(LS, '\\u2028')
818
+ .replace(PS, '\\u2029')
819
+ .replace(NL, '\\n')
820
+ .replace(LF, '\\f')
821
+ .replace(TB, '\\t');
822
+ }
823
+ return s;
824
+ };
775
825
 
776
826
  })(dust);
777
827
 
778
- if (typeof exports !== "undefined") {
779
- if (typeof process !== "undefined") {
780
- require('./server')(dust);
828
+ if (typeof exports !== 'undefined') {
829
+ if (typeof process !== 'undefined') {
830
+ require('./server')(dust);
781
831
  }
782
832
  module.exports = dust;
783
833
  }
@@ -788,9 +838,11 @@ dust.compile = function(source, name) {
788
838
  var ast = filterAST(dust.parse(source));
789
839
  return compile(ast, name);
790
840
  }
791
- catch(err)
841
+ catch (err)
792
842
  {
793
- if(!err.line || !err.column) throw err;
843
+ if (!err.line || !err.column) {
844
+ throw err;
845
+ }
794
846
  throw new SyntaxError(err.message + " At line : " + err.line + ", column : " + err.column);
795
847
  }
796
848
  };
@@ -827,35 +879,42 @@ dust.optimizers = {
827
879
  path: noop,
828
880
  literal: noop,
829
881
  comment: nullify,
830
- line: nullify,
831
- col: nullify
882
+ line: nullify,
883
+ col: nullify
832
884
  };
833
885
 
834
886
  dust.pragmas = {
835
887
  esc: function(compiler, context, bodies, params) {
836
- var old = compiler.auto;
837
- if (!context) context = 'h';
888
+ var old = compiler.auto,
889
+ out;
890
+ if (!context) {
891
+ context = 'h';
892
+ }
838
893
  compiler.auto = (context === 's') ? '' : context;
839
- var out = compileParts(compiler, bodies.block);
894
+ out = compileParts(compiler, bodies.block);
840
895
  compiler.auto = old;
841
896
  return out;
842
897
  }
843
898
  };
844
899
 
845
900
  function visit(context, node) {
846
- var out = [node[0]];
847
- for (var i=1, len=node.length; i<len; i++) {
848
- var res = dust.filterNode(context, node[i]);
849
- if (res) out.push(res);
901
+ var out = [node[0]],
902
+ i, len, res;
903
+ for (i=1, len=node.length; i<len; i++) {
904
+ res = dust.filterNode(context, node[i]);
905
+ if (res) {
906
+ out.push(res);
907
+ }
850
908
  }
851
909
  return out;
852
910
  };
853
911
 
854
912
  // Compacts consecutive buffer nodes into a single node
855
913
  function compactBuffers(context, node) {
856
- var out = [node[0]], memo;
857
- for (var i=1, len=node.length; i<len; i++) {
858
- var res = dust.filterNode(context, node[i]);
914
+ var out = [node[0]],
915
+ memo, i, len, res;
916
+ for (i=1, len=node.length; i<len; i++) {
917
+ res = dust.filterNode(context, node[i]);
859
918
  if (res) {
860
919
  if (res[0] === 'buffer') {
861
920
  if (memo) {
@@ -881,8 +940,14 @@ var specialChars = {
881
940
  "rb": "}"
882
941
  };
883
942
 
884
- function convertSpecial(context, node) { return ['buffer', specialChars[node[1]]] };
885
- function noop(context, node) { return node };
943
+ function convertSpecial(context, node) {
944
+ return ['buffer', specialChars[node[1]]]
945
+ };
946
+
947
+ function noop(context, node) {
948
+ return node
949
+ };
950
+
886
951
  function nullify(){};
887
952
 
888
953
  function compile(ast, name) {
@@ -906,9 +971,10 @@ function compile(ast, name) {
906
971
 
907
972
  function compileBlocks(context) {
908
973
  var out = [],
909
- blocks = context.blocks;
974
+ blocks = context.blocks,
975
+ name;
910
976
 
911
- for (var name in blocks) {
977
+ for (name in blocks) {
912
978
  out.push("'" + name + "':" + blocks[name]);
913
979
  }
914
980
  if (out.length) {
@@ -921,9 +987,10 @@ function compileBlocks(context) {
921
987
  function compileBodies(context) {
922
988
  var out = [],
923
989
  bodies = context.bodies,
924
- blx = context.blocks;
990
+ blx = context.blocks,
991
+ i, len;
925
992
 
926
- for (var i=0, len=bodies.length; i<len; i++) {
993
+ for (i=0, len=bodies.length; i<len; i++) {
927
994
  out[i] = "function body_" + i + "(chk,ctx){"
928
995
  + blx + "return chk" + bodies[i] + ";}";
929
996
  }
@@ -931,8 +998,9 @@ function compileBodies(context) {
931
998
  };
932
999
 
933
1000
  function compileParts(context, body) {
934
- var parts = '';
935
- for (var i=1, len=body.length; i<len; i++) {
1001
+ var parts = '',
1002
+ i, len;
1003
+ for (i=1, len=body.length; i<len; i++) {
936
1004
  parts += dust.compileNode(context, body[i]);
937
1005
  }
938
1006
  return parts;
@@ -944,7 +1012,8 @@ dust.compileNode = function(context, node) {
944
1012
 
945
1013
  dust.nodes = {
946
1014
  body: function(context, node) {
947
- var id = context.index++, name = "body_" + id;
1015
+ var id = context.index++,
1016
+ name = "body_" + id;
948
1017
  context.bodies[id] = compileParts(context, node);
949
1018
  return name;
950
1019
  },
@@ -1085,7 +1154,7 @@ dust.nodes = {
1085
1154
  },
1086
1155
 
1087
1156
  key: function(context, node) {
1088
- return "ctx.get(\"" + node[1] + "\")";
1157
+ return "ctx._get(false, [\"" + node[1] + "\"])";
1089
1158
  },
1090
1159
 
1091
1160
  path: function(context, node) {
@@ -1099,7 +1168,7 @@ dust.nodes = {
1099
1168
  else
1100
1169
  list.push("\"" + keys[i] + "\"");
1101
1170
  }
1102
- return "ctx.getPath(" + current + ",[" + list.join(',') + "])";
1171
+ return "ctx._get(" + current + ",[" + list.join(',') + "])";
1103
1172
  },
1104
1173
 
1105
1174
  literal: function(context, node) {