UNPKG

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