marionette_dust 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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) {