dustjs-linkedin
Advanced tools
Comparing version 0.6.0 to 1.0.0
@@ -206,3 +206,10 @@ (function(dust) { | ||
"+": function(context, node) { | ||
return ".block(ctx.getBlock(" | ||
if(typeof(node[1].text) === "undefined" && typeof(node[4]) === "undefined"){ | ||
return ".block(ctx.getBlock(" | ||
+ dust.compileNode(context, node[1]) | ||
+ ",chk, ctx)," + dust.compileNode(context, node[2]) + ", {}," | ||
+ dust.compileNode(context, node[3]) | ||
+ ")"; | ||
}else { | ||
return ".block(ctx.getBlock(" | ||
+ escape(node[1].text) | ||
@@ -213,2 +220,3 @@ + ")," + dust.compileNode(context, node[2]) + "," | ||
+ ")"; | ||
} | ||
}, | ||
@@ -215,0 +223,0 @@ |
(function(dust){ | ||
/* make a safe version of console if it is not available | ||
* currently supporting: | ||
* _console.log | ||
* */ | ||
var _console = (typeof console !== 'undefined')? console: { | ||
log: function(){ | ||
/* a noop*/ | ||
} | ||
}; | ||
function isSelect(context) { | ||
var value = context.current(); | ||
return typeof value === "object" && value.isSelect === true; | ||
return typeof value === "object" && value.isSelect === true; | ||
} | ||
@@ -10,8 +20,8 @@ | ||
var params = params || {}, | ||
actual, expected; | ||
actual, | ||
expected; | ||
if (params.key) { | ||
actual = context.get(params.key); | ||
actual = helpers.tap(params.key, chunk, context); | ||
} else if (isSelect(context)) { | ||
actual = context.current().value; | ||
actual = context.current().selectKey; | ||
if (context.current().isResolved) { | ||
@@ -23,4 +33,3 @@ filter = function() { return false; }; | ||
} | ||
expected = params.value; | ||
expected = helpers.tap(params.value, chunk, context); | ||
if (filter(expected, coerce(actual, params.type, context))) { | ||
@@ -64,19 +73,43 @@ if (isSelect(context)) { | ||
}, | ||
contextDump: function(chunk, context, bodies) { | ||
_console.log(JSON.stringify(context.stack)); | ||
return chunk; | ||
}, | ||
// Utility helping to resolve dust references in the given chunk | ||
tap: function( input, chunk, context ){ | ||
// return given input if there is no dust reference to resolve | ||
var output = input; | ||
// dust compiles a string to function, if there are references | ||
if( typeof input === "function"){ | ||
if( ( typeof input.isReference !== "undefined" ) && ( input.isReference === true ) ){ // just a plain function, not a dust `body` function | ||
output = input(); | ||
} else { | ||
output = ''; | ||
chunk.tap(function(data){ | ||
output += data; | ||
return ''; | ||
}).render(input, context).untap(); | ||
if( output === '' ){ | ||
output = false; | ||
} | ||
} | ||
} | ||
return output; | ||
}, | ||
/** | ||
if helper | ||
@param cond, either a string literal value or a dust reference | ||
a string literal value, is enclosed in double quotes, e.g. cond="2>3" | ||
a dust reference is also enclosed in double quotes, e.g. cond="'{val}'' > 3" | ||
cond argument should evaluate to a valid javascript expression | ||
**/ | ||
"if": function( chunk, context, bodies, params ){ | ||
if( params && params.cond ){ | ||
var cond = params.cond; | ||
// resolve dust references in the expression | ||
if( typeof cond === "function" ){ | ||
cond = ''; | ||
chunk.tap( function( data ){ | ||
cond += data; | ||
return ''; | ||
} ).render( params.cond, context ).untap(); | ||
if( cond === '' ){ | ||
cond = false; | ||
} | ||
} | ||
// eval expressions with no dust references | ||
cond = this.tap(cond, chunk, context); | ||
// eval expressions with given dust references | ||
if( eval( cond ) ){ | ||
@@ -91,11 +124,25 @@ return chunk.render( bodies.block, context ); | ||
else { | ||
if( typeof window !== 'undefined' && window.console ){ | ||
window.console.log( "No expression given!" ); | ||
} | ||
_console.log( "No condition given in the if helper!" ); | ||
} | ||
return chunk; | ||
}, | ||
/** | ||
select/eq/lt/lte/gt/gte/default helper | ||
@param key, either a string literal value or a dust reference | ||
a string literal value, is enclosed in double quotes, e.g. key="foo" | ||
a dust reference may or may not be enclosed in double quotes, e.g. key="{val}" and key=val are both valid | ||
@param type (optiona), supported types are number, boolean, string, date, context, defaults to string | ||
**/ | ||
select: function(chunk, context, bodies, params) { | ||
return chunk.render(bodies.block, context.push({ isSelect: true, isResolved: false, value: context.get(params.key) })); | ||
if( params && params.key){ | ||
// returns given input as output, if the input is not a dust reference, else does a context lookup | ||
var key = this.tap(params.key, chunk, context); | ||
return chunk.render(bodies.block, context.push({ isSelect: true, isResolved: false, selectKey: key })); | ||
} | ||
// no key | ||
else { | ||
_console.log( "No key given in the select helper!" ); | ||
} | ||
return chunk; | ||
}, | ||
@@ -123,4 +170,22 @@ | ||
"else": function(chunk, context, bodies, params) { | ||
"default": function(chunk, context, bodies, params) { | ||
return filter(chunk, context, bodies, params, function(expected, actual) { return true; }); | ||
}, | ||
size: function( chunk, context, bodies, params ) { | ||
var subject = params.subject; | ||
var value = 0; | ||
if (!subject) { //undefined, "", 0 | ||
value = 0; | ||
} else if(dust.isArray(subject)) { //array | ||
value = subject.length; | ||
} else if (!isNaN(subject)) { //numeric values | ||
value = subject; | ||
} else if (Object(subject) === subject) { //object test | ||
var nr = 0; | ||
for(var k in subject) if(Object.hasOwnProperty.call(subject,k)) nr++; | ||
value = nr; | ||
} else { | ||
value = (subject + '').length; //any other value (strings etc.) | ||
} | ||
return chunk.write(value); | ||
} | ||
@@ -127,0 +192,0 @@ }; |
@@ -166,8 +166,2 @@ var dust = {}; | ||
Context.prototype.push = function(head, idx, len) { | ||
if( head ){ | ||
// loop index for a block section | ||
head['$idx'] = idx; | ||
// loop size for a block section | ||
head['$len'] = len; | ||
} | ||
return new Context(new Stack(head, this.stack, idx, len), this.global, this.blocks); | ||
@@ -184,3 +178,8 @@ }; | ||
Context.prototype.getBlock = function(key) { | ||
Context.prototype.getBlock = function(key, chk, ctx) { | ||
if (typeof key === "function") { | ||
key = key(chk, ctx).data; | ||
chk.data = ""; | ||
} | ||
var blocks = this.blocks; | ||
@@ -267,6 +266,12 @@ | ||
Stream.prototype.emit = function(type, data) { | ||
var events = this.events; | ||
if (events && events[type]) { | ||
events[type](data); | ||
if (!this.events) return false; | ||
var handler = this.events[type]; | ||
if (!handler) return false; | ||
if (typeof handler == 'function') { | ||
handler(data); | ||
} else { | ||
var listeners = handler.slice(0); | ||
for (var i = 0, l = listeners.length; i < l; i++) { | ||
listeners[i](data); | ||
} | ||
} | ||
@@ -279,6 +284,23 @@ }; | ||
} | ||
this.events[type] = callback; | ||
if (!this.events[type]) { | ||
this.events[type] = callback; | ||
} else if(typeof this.events[type] === 'function') { | ||
this.events[type] = [this.events[type], callback]; | ||
} else { | ||
this.events[type].push(callback); | ||
} | ||
return this; | ||
}; | ||
Stream.prototype.pipe = function(stream) { | ||
this.on("data", function(data) { | ||
stream.write(data, "utf8"); | ||
}).on("end", function() { | ||
stream.end(); | ||
}).on("error", function(err) { | ||
stream.error(err); | ||
}); | ||
return this; | ||
}; | ||
function Chunk(root, next, taps) { | ||
@@ -343,3 +365,5 @@ this.root = root; | ||
if (typeof elem === "function") { | ||
elem = elem(this, context, null, {auto: auto, filters: filters}); | ||
elem.isReference = true; | ||
// Changed the function calling to use apply with the current context to make sure that "this" is wat we expect it to be inside the function | ||
elem = elem.apply(context.current(), [this, context, null, {auto: auto, filters: filters}]); | ||
if (elem instanceof Chunk) { | ||
@@ -358,3 +382,3 @@ return elem; | ||
if (typeof elem === "function") { | ||
elem = elem(this, context, bodies, params); | ||
elem = elem.apply(context.current(), [this, context, bodies, params]); | ||
if (elem instanceof Chunk) { | ||
@@ -375,5 +399,9 @@ return elem; | ||
var len = elem.length, chunk = this; | ||
context.stack.head['$len'] = len; | ||
for (var i=0; i<len; i++) { | ||
context.stack.head['$idx'] = i; | ||
chunk = body(chunk, context.push(elem[i], i, len)); | ||
} | ||
context.stack.head['$idx'] = undefined; | ||
context.stack.head['$len'] = undefined; | ||
return chunk; | ||
@@ -384,3 +412,10 @@ } | ||
} else if (elem || elem === 0) { | ||
if (body) return body(this, context.push(elem)); | ||
if (body) { | ||
context.stack.head['$idx'] = 0; | ||
context.stack.head['$len'] = 1; | ||
chunk = body(this, context.push(elem)); | ||
context.stack.head['$idx'] = undefined; | ||
context.stack.head['$len'] = undefined; | ||
return chunk; | ||
} | ||
} else if (skip) { | ||
@@ -536,2 +571,3 @@ return skip(this, context); | ||
if (typeof exports !== "undefined") { | ||
//TODO: Remove the helpers from dust core in the next release. | ||
dust.helpers = require("./dust-helpers").helpers; | ||
@@ -538,0 +574,0 @@ if (typeof process !== "undefined") { |
{ | ||
"name": "dustjs-linkedin", | ||
"version": "0.6.0", | ||
"version": "1.0.0", | ||
"author": "Aleksander Williams", | ||
@@ -14,2 +14,6 @@ "description": "Asynchronous templates for the browser and node.js", | ||
"email":"vbasavaraj@linkedin.com" | ||
}, | ||
{ | ||
"name": "Sarah Clatterbuck", | ||
"email": "sclatter@linkedin.com" | ||
} | ||
@@ -28,5 +32,6 @@ ], | ||
"keywords": ["templates", "views"], | ||
"devDependencies": { | ||
"dependencies": { | ||
"jasmine-node" : "1.0.x", | ||
"cover" : "0.2.x" | ||
"cover" : "0.2.x", | ||
"uglify-js" : "1.3.3" | ||
}, | ||
@@ -33,0 +38,0 @@ "license": "MIT", |
Dust [![Build Status](https://secure.travis-ci.org/linkedin/dustjs.png)](http://travis-ci.org/linkedin/dustjs) | ||
==== | ||
Demo & Guide | ||
------------ | ||
ß | ||
Extensive docs and a full demo are available at <http://akdubya.github.com/dustjs> | ||
This is the LinkedIn fork of Dust. | ||
> Asynchronous templates for the browser and node.js | ||
#### <http://akdubya.github.com/dustjs> # | ||
Highlights! | ||
---- | ||
I like [Mustache](http://mustache.github.com) and variants but none of them offers quite what I need. | ||
Use Dust if you want these things: | ||
* async/streaming operation | ||
* browser/node compatibility | ||
* extended Mustache/ctemplate syntax | ||
* clean, low-level API | ||
* [high performance](http://akdubya.github.com/dustjs/benchmark/index.html) | ||
* composable templates | ||
This is the LinkedIn fork of dust.js | ||
==================================== | ||
Details in the blog post : http://engineering.linkedin.com/frontend/leaving-jsps-dust-moving-linkedin-dustjs-client-side-templates | ||
We will gradually be extending this library with helper functions and bug fixes. | ||
Current LinkedIn additions include: | ||
-------------------------- | ||
* Fix to peg.js to print the line and column number for syntax errors in dust templates | ||
* Fix to support > node0.4 | ||
* Addition of jasmine test suite, BDD with dust.js | ||
* There are cases of rendering logic that are best done in templates. @if helper that relies entirely on the js eval for expression evaluation, The perf results are here: <http://jsperf.com/dust-if>. We intend to replace the slow js eval with a expression parser soon | ||
* Section index for lists of maps stored in the dust context for ease of writing simple logic in templates | ||
* Section size for lists of maps stored in the dust context for ease of writing simple logic in templates | ||
Installation | ||
------------ | ||
For Linkedin Dustjs | ||
$ npm install dustjs-linkedin | ||
To render compiled templates in the browser: | ||
<script src="dust-core-0.6.0.min.js"></script> | ||
To compile a template on the command line, use the dustc command. | ||
Its syntax is: | ||
dustc [{-n|--name}=<template_name>] {inputfilename|-} [<outputfilename>] | ||
For example, to compile a template on the command line and have it | ||
registered under the same name as the source file: | ||
$ dustc template.html | ||
You can customize the name under which the template is registered: | ||
$ dustc --name=mytemplate template.html | ||
Running Tests | ||
------------ | ||
To run tests: | ||
$ make test | ||
To generate code coverage report: | ||
$ npm install cover -g | ||
$ make coverage | ||
To view HTML test coverage report: | ||
$ open cover_html/index.html | ||
Read more here : <http://linkedin.github.com/dustjs/> |
@@ -66,2 +66,42 @@ (function(exports){ | ||
}); | ||
suite.test("renderSource (pipe)", function() { | ||
var unit = this; | ||
dust.renderSource('Hello World', {}).pipe({ | ||
write: function (data) { | ||
try { | ||
unit.equals('Hello World', data); | ||
} catch(err) { | ||
unit.fail(err); | ||
return; | ||
} | ||
}, | ||
end: function () { | ||
unit.pass(); | ||
} | ||
}) | ||
}); | ||
suite.test("renderSource (multipe listeners)", function() { | ||
var unit = this; | ||
dust.renderSource('Hello World', {}).on('data', function(data) { | ||
try { | ||
unit.equals('Hello World', data); | ||
} catch(err) { | ||
unit.fail(err); | ||
return; | ||
} | ||
}).on('data', function(data) { | ||
try { | ||
unit.equals('Hello World', data); | ||
} catch(err) { | ||
unit.fail(err); | ||
return; | ||
} | ||
}).on('end', function() { | ||
unit.pass(); | ||
}).on('error', function(err) { | ||
unit.fail(err); | ||
}); | ||
}); | ||
} | ||
@@ -68,0 +108,0 @@ |
@@ -7,3 +7,3 @@ var jasmine = require('jasmine-node'), | ||
dust = require('../../../lib/dust'), | ||
dustExamples = require('../spec/examples'); | ||
grammarTests = require('../spec/grammarTests'); | ||
@@ -10,0 +10,0 @@ for(key in jasmine) |
describe ("Test the basic functionality of dust", function() { | ||
for (var index = 0; index < dustExamples.length; index++) { | ||
var test = dustExamples[index]; | ||
it (test.message, render(test)); | ||
for (var index = 0; index < grammarTests.length; index++) { | ||
var test = grammarTests[index]; | ||
it ("RENDER: " + test.message, render(test)); | ||
it ("STREAM: " + test.message, stream(test)); | ||
it ("PIPE: " + test.message, pipe(test)); | ||
}; | ||
}); | ||
function render(test) { | ||
function render(test) { | ||
return function() { | ||
@@ -21,2 +23,100 @@ try { | ||
}; | ||
} | ||
} | ||
function stream(test) { | ||
return function() { | ||
var output ="", flag; | ||
runs(function(){ | ||
flag = false; | ||
output = ""; | ||
try { | ||
dust.loadSource(dust.compile(test.source, test.name)); | ||
dust.stream(test.name, test.context) | ||
.on("data", function(data) { | ||
output += data; | ||
}) | ||
.on("end", function() { | ||
flag = true; | ||
}) | ||
.on("error", function(err) { | ||
output = err.message; | ||
}); | ||
} catch(error) { | ||
output = error.message; | ||
flag= true; | ||
} | ||
}); | ||
waitsFor(function(){ | ||
return flag; | ||
}, "the output", 500); | ||
runs(function(){ | ||
if (test.error) { | ||
expect(test.error || {} ).toEqual(output); | ||
} else { | ||
expect(test.expected).toEqual(output); | ||
} | ||
}); | ||
} | ||
}; | ||
function pipe(test) { | ||
return function() { | ||
var output, outputTwo, flag, flagTwo; | ||
runs(function(){ | ||
flag = false; | ||
flagTwo = false; | ||
output = ""; | ||
outputTwo = ""; | ||
try { | ||
dust.loadSource(dust.compile(test.source, test.name)); | ||
var tpl = dust.stream(test.name, test.context); | ||
tpl.pipe({ | ||
write: function (data) { | ||
output += data; | ||
}, | ||
end: function () { | ||
flag = true; | ||
}, | ||
error: function (err) { | ||
flag = true; | ||
output = err.message; | ||
} | ||
}); | ||
// Pipe to a second stream to test multiple event-listeners | ||
tpl.pipe({ | ||
write: function (data) { | ||
outputTwo += data; | ||
}, | ||
end: function () { | ||
flagTwo = true; | ||
}, | ||
error: function (err) { | ||
flagTwo = true; | ||
outputTwo = err.message; | ||
} | ||
}); | ||
} catch(error) { | ||
output = error.message; | ||
outputTwo = error.message; | ||
flag= true; | ||
flagTwo= true; | ||
} | ||
}); | ||
waitsFor(function(){ | ||
return flag && flagTwo; | ||
}, "the output", 500); | ||
runs(function(){ | ||
if (test.error) { | ||
expect(test.error || {} ).toEqual(output); | ||
expect(test.error || {} ).toEqual(outputTwo); | ||
} else { | ||
expect(test.expected).toEqual(output); | ||
expect(test.expected).toEqual(outputTwo); | ||
} | ||
}); | ||
} | ||
}; |
@@ -1,57 +0,56 @@ | ||
To run the tests | ||
---------------- | ||
With MakeFile: | ||
* unit Test : "make test" | ||
* jasmine test: "make jasmine" | ||
note: the commands mentioned above has to be executed in the project root folder. | ||
Dust original Unit tests | ||
Dust core unit-tests | ||
------------------------ | ||
This test are developed to be run with nodejs, so if you want to run them you should execute this command in the terminal: "node test/server.js" | ||
core tests run on node, use the following command | ||
Unit tests using Jasmine | ||
------------------------ | ||
node test/server.js | ||
How to run the unit-tests? | ||
Dust unit-tests using jasmine | ||
----------------------------- | ||
In this distributions of dust, we have unit tests in Jasmine for both the client and the nodejs version. | ||
If you want to run the client version just open the html page called specRunner.html located on "test/jasmine-test/client/specRunner.html". | ||
In the current distribution of dust, we have unit tests in jasmine for both the client and the nodejs version. | ||
If you want to run the client version just open the html page called specRunner.html located in | ||
test/jasmine-test/client/specRunner.html | ||
In order to run the server distribution of dust, run this command in the terminal: "node test/jasmine-test/server/specRunner.js" | ||
pre-requisites for tests on node server version: | ||
Pre-requisites for tests on node server version: | ||
---------------------------------- | ||
* install nodejs 0.6 or greater | ||
* install npm | ||
* install Jasmine test framework (npm install -g jasmine-node) | ||
* install jasmine test framework : npm install -g jasmine-node | ||
To get the coverage report | ||
-------------------------- | ||
In order to run the node.js version of dust, run this command in the terminal | ||
We are using a tool called node-cover, it can be installed by npm executing "npm install cover -g". | ||
node test/jasmine-test/server/specRunner.js | ||
Once you have installed cover, you should use it in this way: | ||
Execute Cover. | ||
-------------- | ||
Run tests with make | ||
------------------- | ||
* core unit tests: | ||
make test | ||
"cover run test/jasmine-test/server/specRunner.js" // it will execute all the test and create a folder with results. | ||
* jasmine unit test | ||
make jasmine | ||
Watch standard results | ||
---------------------- | ||
Note: the above commands has to be run in the project root folder. | ||
"cover report" //it will show you a table con % code covered, missed lines, #lines, %blocks, Missed blocked and # blocks. | ||
Code coverage report | ||
----------------------------- | ||
Watch html results | ||
------------------ | ||
We are using a tool called node-cover, it can be installed by npm with the following command: | ||
"cover report html" //it will create a folder in the location where you executed the command with html files showing the coverage. | ||
npm install cover -g | ||
The results are very complete, it creates one html file per js file used by the test. | ||
Once you have installed cover, you can use it to generate the code coverage results | ||
The lines that are not covered are painted on red. | ||
Run Cover | ||
-------------- | ||
cover run test/jasmine-test/server/specRunner.js // runs all the test and creates a folder with results. | ||
cover report // shows you a table with % code covered, missed lines, #lines, %blocks, missed blocks and # blocks. | ||
cover report html //creates a folder the location where you run the command and the report is in html. | ||
Cover creates one html file per js file used by the test. The lines that are not covered are shown on red. | ||
var uutest = require('./uutest'), | ||
dust = require('../lib/dust'), | ||
tests = require('./jasmine-test/spec/examples'), | ||
tests = require('./jasmine-test/spec/grammarTests'), | ||
coreSetup = require('./core').coreSetup; | ||
@@ -5,0 +5,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
858313
0
15868
3
68
3
8
9
+ Addedcover@0.2.x
+ Addedjasmine-node@1.0.x
+ Addeduglify-js@1.3.3
+ Added@xmldom/xmldom@0.8.10(transitive)
+ Addedcli-table@0.0.2(transitive)
+ Addedcoffee-script@1.12.7(transitive)
+ Addedcolors@0.3.0(transitive)
+ Addedcover@0.2.9(transitive)
+ Addedjasmine-node@1.0.28(transitive)
+ Addedjasmine-reporters@2.5.2(transitive)
+ Addedmkdirp@1.0.4(transitive)
+ Addedrequirejs@2.3.7(transitive)
+ Addeduglify-js@1.3.3(transitive)
+ Addedunderscore@1.13.71.2.4(transitive)
+ Addedunderscore.string@2.0.0(transitive)
+ Addedwalkdir@0.4.1(transitive)
+ Addedwhich@1.0.9(transitive)