UNPKG

14.1 kBJavaScriptView Raw
1(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.vash = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
2
3exports.context = function(input, lineno, columnno, linebreak) {
4 linebreak = linebreak || '!LB!';
5
6 var lines = input.split(linebreak)
7 , contextSize = lineno === 0 && columnno === 0 ? lines.length - 1 : 3
8 , start = Math.max(0, lineno - contextSize)
9 , end = Math.min(lines.length, lineno + contextSize);
10
11 return lines
12 .slice(start, end)
13 .map(function(line, i, all){
14 var curr = i + start + 1;
15
16 return (curr === lineno ? ' > ' : ' ')
17 + (curr < 10 ? ' ' : '')
18 + curr
19 + ' | '
20 + line;
21 }).join('\n');
22}
23},{}],2:[function(require,module,exports){
24module.exports={
25 "name": "vash",
26 "description": "Razor syntax for JS templating",
27 "version": "0.12.1",
28 "author": "Andrew Petersen <senofpeter@gmail.com>",
29 "homepage": "https://github.com/kirbysayshi/vash",
30 "bin": {
31 "vash": "./bin/vash"
32 },
33 "keywords": [
34 "razor",
35 "parser",
36 "template",
37 "express"
38 ],
39 "repository": {
40 "type": "git",
41 "url": "git://github.com/kirbysayshi/vash"
42 },
43 "main": "index.js",
44 "engines": {
45 "node": ">= 0.10"
46 },
47 "scripts": {
48 "prepublish": "npm run test && npm run build",
49 "coverage": "VASHPATH=../../index.js VASHRUNTIMEPATH=../../runtime.js browserify -t envify -t coverify test/vows/vash.test.js | node | coverify",
50 "build": "browserify index.js --standalone vash > build/vash.js && browserify --standalone vash runtime.js > build/vash-runtime.js && browserify --standalone vash --external fs --external path lib/helpers/index.js > build/vash-runtime-all.js",
51 "test": "VASHPATH=../../index.js VASHRUNTIMEPATH=../../runtime.js vows test/vows/vash.*.js --spec",
52 "docs": "scripts/docs.sh",
53 "docs-dev": "scripts/docs-dev.sh"
54 },
55 "dependencies": {
56 "commander": "~1.1.1",
57 "debug": "^2.2.0",
58 "uglify-js": "^2.6.2"
59 },
60 "devDependencies": {
61 "browserify": "^13.0.0",
62 "coverify": "^1.4.1",
63 "envify": "^3.4.0",
64 "jshint": "0.8.0",
65 "marked": "~0.2.8",
66 "semver": "~1",
67 "vows": "^0.8.1"
68 }
69}
70
71},{}],3:[function(require,module,exports){
72
73var error = require('./lib/error');
74var runtime = {
75 version: require('./package.json').version
76};
77
78var helpers = runtime['helpers'];
79
80module.exports = runtime;
81
82function Helpers( model ) {
83 this.buffer = new Buffer();
84 this.model = model;
85 this.options = null; // added at render time
86
87 this.vl = 0;
88 this.vc = 0;
89};
90
91runtime['helpers']
92 = helpers
93 = Helpers.prototype
94 = { constructor: Helpers, config: {}, tplcache: {} };
95
96// this allows a template to return the context, and coercion
97// will handle it
98helpers.toString = helpers.toHtmlString = function(){
99 // not calling buffer.toString() results in 2x speedup
100 return this.buffer._vo.join('');//.toString();
101}
102
103///////////////////////////////////////////////////////////////////////////
104// HTML ESCAPING
105
106var HTML_REGEX = /[&<>"'`]/g
107 ,HTML_REPLACER = function(match) { return HTML_CHARS[match]; }
108 ,HTML_CHARS = {
109 "&": "&amp;"
110 ,"<": "&lt;"
111 ,">": "&gt;"
112 ,'"': "&quot;"
113 ,"'": "&#x27;"
114 ,"`": "&#x60;"
115 };
116
117helpers['raw'] = function( val ) {
118 var func = function() { return val; };
119
120 val = val != null ? val : "";
121
122 return {
123 toHtmlString: func
124 ,toString: func
125 };
126};
127
128helpers['escape'] = function( val ) {
129 var func = function() { return val; };
130
131 val = val != null ? val : "";
132
133 if ( typeof val.toHtmlString !== "function" ) {
134
135 val = val.toString().replace( HTML_REGEX, HTML_REPLACER );
136
137 return {
138 toHtmlString: func
139 ,toString: func
140 };
141 }
142
143 return val;
144};
145
146// HTML ESCAPING
147///////////////////////////////////////////////////////////////////////////
148
149
150///////////////////////////////////////////////////////////////////////////
151// BUFFER MANIPULATION
152//
153// These are to be used from within helpers, to allow for manipulation of
154// output in a sane manner.
155
156var Buffer = function() {
157 this._vo = [];
158}
159
160Buffer.prototype.mark = function( debugName ) {
161 var mark = new Mark( this, debugName );
162 mark.markedIndex = this._vo.length;
163 this._vo.push( mark.uid );
164 return mark;
165};
166
167Buffer.prototype.fromMark = function( mark ) {
168 var found = mark.findInBuffer();
169
170 if( found > -1 ){
171 // automatically destroy the mark from the buffer
172 mark.destroy();
173 // `found` will still be valid for a manual splice
174 return this._vo.splice( found, this._vo.length );
175 }
176
177 return [];
178};
179
180Buffer.prototype.spliceMark = function( mark, numToRemove, add ){
181 var found = mark.findInBuffer();
182
183 if( found > -1 ){
184 mark.destroy();
185 arguments[0] = found;
186 return this._vo.splice.apply( this._vo, arguments );
187 }
188
189 return [];
190};
191
192Buffer.prototype.empty = function() {
193 return this._vo.splice( 0, this._vo.length );
194};
195
196Buffer.prototype.push = function( buffer ) {
197 return this._vo.push( buffer );
198};
199
200Buffer.prototype.pushConcat = function( buffer ){
201 var buffers;
202 if (Array.isArray(buffer)) {
203 buffers = buffer;
204 } else if ( arguments.length > 1 ) {
205 buffers = Array.prototype.slice.call( arguments );
206 } else {
207 buffers = [buffer];
208 }
209
210 for (var i = 0; i < buffers.length; i++) {
211 this._vo.push( buffers[i] );
212 }
213
214 return this.__vo;
215}
216
217Buffer.prototype.indexOf = function( str ){
218
219 for( var i = 0; i < this._vo.length; i++ ){
220 if(
221 ( str.test && this._vo[i] && this._vo[i].search(str) > -1 )
222 || this._vo[i] == str
223 ){
224 return i;
225 }
226 }
227
228 return -1;
229}
230
231Buffer.prototype.lastIndexOf = function( str ){
232 var i = this._vo.length;
233
234 while( --i >= 0 ){
235 if(
236 ( str.test && this._vo[i] && this._vo[i].search(str) > -1 )
237 || this._vo[i] == str
238 ){
239 return i;
240 }
241 }
242
243 return -1;
244}
245
246Buffer.prototype.splice = function(){
247 return this._vo.splice.apply( this._vo, arguments );
248}
249
250Buffer.prototype.index = function( idx ){
251 return this._vo[ idx ];
252}
253
254Buffer.prototype.flush = function() {
255 return this.empty().join( "" );
256};
257
258Buffer.prototype.toString = Buffer.prototype.toHtmlString = function(){
259 // not using flush because then console.log( tpl() ) would artificially
260 // affect the output
261 return this._vo.join( "" );
262}
263
264// BUFFER MANIPULATION
265///////////////////////////////////////////////////////////////////////////
266
267///////////////////////////////////////////////////////////////////////////
268// MARKS
269// These can be used to manipulate the existing entries in the rendering
270// context. For an example, see the highlight helper.
271
272var Mark = runtime['Mark'] = function( buffer, debugName ){
273 this.uid = '[VASHMARK-'
274 + ~~( Math.random() * 10000000 )
275 + (debugName ? ':' + debugName : '')
276 + ']';
277 this.markedIndex = 0;
278 this.buffer = buffer;
279 this.destroyed = false;
280}
281
282var reMark = Mark.re = /\[VASHMARK\-\d{1,8}(?::[\s\S]+?)?]/g
283
284// tests if a string has a mark-like uid within it
285Mark.uidLike = function( str ){
286 return (str || '').search( reMark ) > -1;
287}
288
289Mark.prototype.destroy = function(){
290
291 var found = this.findInBuffer();
292
293 if( found > -1 ){
294 this.buffer.splice( found, 1 );
295 this.markedIndex = -1;
296 }
297
298 this.destroyed = true;
299}
300
301Mark.prototype.findInBuffer = function(){
302
303 if( this.destroyed ){
304 return -1;
305 }
306
307 if( this.markedIndex && this.buffer.index( this.markedIndex ) === this.uid ){
308 return this.markedIndex;
309 }
310
311 // The mark may be within a string due to block manipulation shenanigans.
312 var escaped = this.uid.replace(/(\[|\])/g, '\\$1');
313 var re = new RegExp(escaped);
314 return this.markedIndex = this.buffer.indexOf( re );
315}
316
317// MARKS
318///////////////////////////////////////////////////////////////////////////
319
320///////////////////////////////////////////////////////////////////////////
321// ERROR REPORTING
322
323// Liberally modified from https://github.com/visionmedia/jade/blob/master/jade.js
324helpers.constructor.reportError = function(e, lineno, chr, orig, lb, atRenderTime){
325
326 lb = lb || '!LB!';
327
328 var contextStr = error.context(orig, lineno, chr, lb);
329
330 e.vashlineno = lineno;
331 e.vashcharno = chr;
332 e.message = 'Problem while '
333 + (atRenderTime ? 'rendering' : 'compiling')
334 + ' template at line '
335 + lineno + ', character ' + chr
336 + '.\nOriginal message: ' + e.message + '.'
337 + '\nContext: \n\n' + contextStr + '\n\n';
338
339 throw e;
340};
341
342helpers['reportError'] = function() {
343 this.constructor.reportError.apply( this, arguments );
344};
345
346// ERROR REPORTING
347///////////////////////////////////////////////////////////////////////////
348
349///////////////////////////////////////////////////////////////////////////
350// VASH.LINK
351// Take a compiled string or function and "link" it to the current vash
352// runtime. This is necessary to allow instantiation of `Helpers` and
353// proper decompilation via `toClientString`.
354//
355// If `options.asHelper` and `options.args` are defined, the `cmpFunc` is
356// interpreted as a compiled helper, and is attached to `runtime.helpers` at
357// a property name equal to `options.asHelper`.
358
359runtime['link'] = function( cmpFunc, options ){
360
361 // TODO: allow options.filename to be used as sourceUrl?
362
363 var originalFunc
364 ,cmpOpts;
365
366 if( !options.args ){
367 // every template has these arguments
368 options.args = [options.modelName, options.helpersName, '__vopts', 'runtime'];
369 }
370
371 if( typeof cmpFunc === 'string' ){
372 originalFunc = cmpFunc;
373
374 try {
375 // do not pollute the args array for later attachment to the compiled
376 // function for later decompilation/linking
377 cmpOpts = options.args.slice();
378 cmpOpts.push(cmpFunc);
379 cmpFunc = Function.apply(null, cmpOpts);
380 } catch(e) {
381 // TODO: add flag to reportError to know if it's at compile time or runtime
382 helpers.reportError(e, 0, 0, originalFunc, /\n/, false);
383 }
384 }
385
386 // need this to enable decompilation / relinking
387 cmpFunc.options = {
388 simple: options.simple
389 ,modelName: options.modelName
390 ,helpersName: options.helpersName
391 }
392
393 var linked;
394
395 if( options.asHelper ){
396
397 cmpFunc.options.args = options.args;
398 cmpFunc.options.asHelper = options.asHelper;
399
400 linked = function(){
401 return cmpFunc.apply(this, slice.call(arguments));
402 }
403
404 helpers[options.asHelper] = linked;
405
406 } else {
407
408 linked = function( model, opts ){
409 if( options.simple ){
410 var ctx = {
411 buffer: []
412 ,escape: Helpers.prototype.escape
413 ,raw: Helpers.prototype.raw
414 }
415 return cmpFunc( model, ctx, opts, runtime );
416 }
417
418 opts = divineRuntimeTplOptions( model, opts );
419 return cmpFunc( model, (opts && opts.context) || new Helpers( model ), opts, runtime );
420 }
421 }
422
423 // show the template-specific code, instead of the generic linked function
424 linked['toString'] = function(){ return cmpFunc.toString(); }
425
426 // shortcut to show the actual linked function
427 linked['_toString'] = function(){ return Function.prototype.toString.call(linked) }
428
429 // This assumes a vash global, and should be deprecated.
430 // TODO: @deprecate
431 linked['toClientString'] = function(){
432 return 'vash.link( '
433 + cmpFunc.toString() + ', '
434 + JSON.stringify( cmpFunc.options ) + ' )';
435 }
436
437 return linked;
438}
439
440// given a model and options, allow for various tpl signatures and options:
441// ( model, {} )
442// ( model, function onRenderEnd(){} )
443// ( model )
444// and model.onRenderEnd
445function divineRuntimeTplOptions( model, opts ){
446
447 // allow for signature: model, callback
448 if( typeof opts === 'function' ) {
449 opts = { onRenderEnd: opts };
450 }
451
452 // allow for passing in onRenderEnd via model
453 if( model && model.onRenderEnd ){
454 opts = opts || {};
455
456 if( !opts.onRenderEnd ){
457 opts.onRenderEnd = model.onRenderEnd;
458 }
459
460 delete model.onRenderEnd;
461 }
462
463 // ensure options can be referenced
464 if( !opts ){
465 opts = {};
466 }
467
468 return opts;
469}
470
471// shortcut for compiled helpers
472var slice = Array.prototype.slice;
473
474// VASH.LINK
475///////////////////////////////////////////////////////////////////////////
476
477///////////////////////////////////////////////////////////////////////////
478// TPL CACHE
479
480runtime['lookup'] = function( path, model ){
481 var tpl = runtime.helpers.tplcache[path];
482 if( !tpl ){ throw new Error('Could not find template: ' + path); }
483 if( model ){ return tpl(model); }
484 else return tpl;
485};
486
487runtime['install'] = function( path, tpl ){
488 var cache = runtime.helpers.tplcache;
489 if( typeof tpl === 'string' ){
490 // Super hacky: if the calling context has a `compile` function,
491 // then `this` is likely full vash. This is simply for backwards
492 // compatibility.
493 // TODO: @deprecate
494 if ( typeof this.compile === 'function') {
495 tpl = this.compile(tpl);
496 } else {
497 throw new Error('.install(path, [string]) is not available in the standalone runtime.');
498 }
499 } else if( typeof path === 'object' ){
500 tpl = path;
501 Object.keys(tpl).forEach(function(path){
502 cache[path] = tpl[path];
503 });
504 return cache;
505 }
506 return cache[path] = tpl;
507};
508
509runtime['uninstall'] = function( path ){
510 var cache = runtime.helpers.tplcache
511 ,deleted = false;
512
513 if( typeof path === 'string' ){
514 return delete cache[path];
515 } else {
516 Object.keys(cache).forEach(function(key){
517 if( cache[key] === path ){ deleted = delete cache[key]; }
518 })
519 return deleted;
520 }
521};
522
523},{"./lib/error":1,"./package.json":2}]},{},[3])(3)
524});
\No newline at end of file