UNPKG

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