Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

dot

Package Overview
Dependencies
Maintainers
2
Versions
25
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

dot - npm Package Compare versions

Comparing version 2.0.0-beta.0 to 2.0.0-beta.1

.prettierignore

353

doT.js

@@ -0,1 +1,3 @@

"use strict"
// doT.js

@@ -5,141 +7,234 @@ // 2011-2014, Laura Doktorova, https://github.com/olado/doT

(function () {
"use strict";
const doT = {
templateSettings: {
argName: "it",
encoders: {},
selfContained: false,
strip: true,
internalPrefix: "_val",
encodersPrefix: "_enc",
delimiters: {
start: "{{",
end: "}}",
},
},
template,
compile,
setDelimiters,
}
var doT = {
name: "doT",
version: "1.1.1",
templateSettings: {
evaluate: /\{\{([\s\S]+?(\}?)+)\}\}/g,
interpolate: /\{\{=([\s\S]+?)\}\}/g,
encode: /\{\{!([\s\S]+?)\}\}/g,
use: /\{\{#([\s\S]+?)\}\}/g,
useParams: /(^|[^\w$])def(?:\.|\[[\'\"])([\w$\.]+)(?:[\'\"]\])?\s*\:\s*([\w$\.]+|\"[^\"]+\"|\'[^\']+\'|\{[^\}]+\})/g,
define: /\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g,
defineParams:/^\s*([\w$]+):([\s\S]+)/,
conditional: /\{\{\?(\?)?\s*([\s\S]*?)\s*\}\}/g,
iterate: /\{\{~\s*(?:\}\}|([\s\S]+?)\s*\:\s*([\w$]+)\s*(?:\:\s*([\w$]+))?\s*\}\})/g,
varname: "it",
strip: true,
append: true,
selfcontained: false,
doNotSkipEncoded: false
},
template: undefined, //fn, compile template
compile: undefined, //fn, for express
log: true
}, _globals;
module.exports = doT
doT.encodeHTMLSource = function(doNotSkipEncoded) {
var encodeHTMLRules = { "&": "&#38;", "<": "&#60;", ">": "&#62;", '"': "&#34;", "'": "&#39;", "/": "&#47;" },
matchHTML = doNotSkipEncoded ? /[&<>"'\/]/g : /&(?!#?\w+;)|<|>|"|'|\//g;
return function(code) {
return code ? code.toString().replace(matchHTML, function(m) {return encodeHTMLRules[m] || m;}) : "";
};
};
// depends on selfContained mode
const encoderType = {
false: "function",
true: "string",
}
_globals = (function(){ return this || (0,eval)("this"); }());
const defaultSyntax = {
evaluate: /\{\{([\s\S]+?(\}?)+)\}\}/g,
interpolate: /\{\{=([\s\S]+?)\}\}/g,
typeInterpolate: /\{\{%([nsb])=([\s\S]+?)\}\}/g,
encode: /\{\{([a-z_$]+[\w$]*)?!([\s\S]+?)\}\}/g,
use: /\{\{#([\s\S]+?)\}\}/g,
useParams: /(^|[^\w$])def(?:\.|\[[\'\"])([\w$\.]+)(?:[\'\"]\])?\s*\:\s*([\w$]+(?:\.[\w$]+|\[[^\]]+\])*|\"[^\"]+\"|\'[^\']+\'|\{[^\}]+\})/g,
define: /\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g,
defineParams: /^\s*([\w$]+):([\s\S]+)/,
conditional: /\{\{\?(\?)?\s*([\s\S]*?)\s*\}\}/g,
iterate: /\{\{~\s*(?:\}\}|([\s\S]+?)\s*\:\s*([\w$]+)\s*(?:\:\s*([\w$]+))?\s*\}\})/g,
}
/* istanbul ignore else */
if (typeof module !== "undefined" && module.exports) {
module.exports = doT;
} else if (typeof define === "function" && define.amd) {
define(function(){return doT;});
} else {
_globals.doT = doT;
}
let currentSyntax = {...defaultSyntax}
var startend = {
append: { start: "'+(", end: ")+'", startencode: "'+encodeHTML(" },
split: { start: "';out+=(", end: ");out+='", startencode: "';out+=encodeHTML(" }
}, skip = /$^/;
const TYPES = {
n: "number",
s: "string",
b: "boolean",
}
function resolveDefs(c, block, def) {
return ((typeof block === "string") ? block : block.toString())
.replace(c.define || skip, function(m, code, assign, value) {
if (code.indexOf("def.") === 0) {
code = code.substring(4);
}
if (!(code in def)) {
if (assign === ":") {
if (c.defineParams) value.replace(c.defineParams, function(m, param, v) {
def[code] = {arg: param, text: v};
});
if (!(code in def)) def[code]= value;
} else {
new Function("def", "def['"+code+"']=" + value)(def);
}
}
return "";
})
.replace(c.use || skip, function(m, code) {
if (c.useParams) code = code.replace(c.useParams, function(m, s, d, param) {
if (def[d] && def[d].arg && param) {
var rw = unescape((d+":"+param).replace(/'|\\/g, "_"));
def.__exp = def.__exp || {};
def.__exp[rw] = def[d].text.replace(new RegExp("(^|[^\\w$])" + def[d].arg + "([^\\w$])", "g"), "$1" + param + "$2");
return s + "def.__exp['"+rw+"']";
}
});
var v = new Function("def", "return " + code)(def);
return v ? resolveDefs(c, v, def) : v;
});
}
function resolveDefs(c, syn, block, def) {
return (typeof block === "string" ? block : block.toString())
.replace(syn.define, (_, code, assign, value) => {
if (code.indexOf("def.") === 0) {
code = code.substring(4)
}
if (!(code in def)) {
if (assign === ":") {
value.replace(syn.defineParams, (_, param, v) => {
def[code] = {arg: param, text: v}
})
if (!(code in def)) def[code] = value
} else {
new Function("def", `def['${code}']=${value}`)(def)
}
}
return ""
})
.replace(syn.use, (_, code) => {
code = code.replace(syn.useParams, (_, s, d, param) => {
if (def[d] && def[d].arg && param) {
const rw = unescape((d + ":" + param).replace(/'|\\/g, "_"))
def.__exp = def.__exp || {}
def.__exp[rw] = def[d].text.replace(
new RegExp(`(^|[^\\w$])${def[d].arg}([^\\w$])`, "g"),
`$1${param}$2`
)
return s + `def.__exp['${rw}']`
}
})
const v = new Function("def", "return " + code)(def)
return v ? resolveDefs(c, syn, v, def) : v
})
}
function unescape(code) {
return code.replace(/\\('|\\)/g, "$1").replace(/[\r\t\n]/g, " ");
}
function unescape(code) {
return code.replace(/\\('|\\)/g, "$1").replace(/[\r\t\n]/g, " ")
}
doT.template = function(tmpl, c, def) {
c = c || doT.templateSettings;
var cse = c.append ? startend.append : startend.split, needhtmlencode, sid = 0, indv,
str = (c.use || c.define) ? resolveDefs(c, tmpl, def || {}) : tmpl;
function template(tmpl, c, def) {
const ds = c && c.delimiters
const syn = ds && !sameDelimiters(ds) ? getSyntax(ds) : currentSyntax
c = c ? {...doT.templateSettings, ...c} : doT.templateSettings
let sid = 0
let str = resolveDefs(c, syn, tmpl, def || {})
const needEncoders = {}
str = ("var out='" + (c.strip ? str.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g," ")
.replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g,""): str)
.replace(/'|\\/g, "\\$&")
.replace(c.interpolate || skip, function(m, code) {
return cse.start + unescape(code) + cse.end;
})
.replace(c.encode || skip, function(m, code) {
needhtmlencode = true;
return cse.startencode + unescape(code) + cse.end;
})
.replace(c.conditional || skip, function(m, elsecase, code) {
return elsecase ?
(code ? "';}else if(" + unescape(code) + "){out+='" : "';}else{out+='") :
(code ? "';if(" + unescape(code) + "){out+='" : "';}out+='");
})
.replace(c.iterate || skip, function(m, iterate, vname, iname) {
if (!iterate) return "';} } out+='";
sid+=1; indv=iname || "i"+sid; iterate=unescape(iterate);
return "';var arr"+sid+"="+iterate+";if(arr"+sid+"){var "+vname+","+indv+"=-1,l"+sid+"=arr"+sid+".length-1;while("+indv+"<l"+sid+"){"
+vname+"=arr"+sid+"["+indv+"+=1];out+='";
})
.replace(c.evaluate || skip, function(m, code) {
return "';" + unescape(code) + "out+='";
})
+ "';return out;")
.replace(/\n/g, "\\n").replace(/\t/g, '\\t').replace(/\r/g, "\\r")
.replace(/(\s|;|\}|^|\{)out\+='';/g, '$1').replace(/\+''/g, "");
//.replace(/(\s|;|\}|^|\{)out\+=''\+/g,'$1out+=');
str = (
"let out='" +
(c.strip
? str
.trim()
.replace(/[\t ]+(\r|\n)/g, "\n") // remove trailing spaces
.replace(/(\r|\n)[\t ]+/g, " ") // leading spaces reduced to " "
.replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g, "") // remove breaks, tabs and JS comments
: str
)
.replace(/'|\\/g, "\\$&")
.replace(syn.interpolate, (_, code) => `'+(${unescape(code)})+'`)
.replace(syn.typeInterpolate, (_, typ, code) => {
sid++
const val = c.internalPrefix + sid
const error = `throw new Error("expected ${TYPES[typ]}, got "+ (typeof ${val}))`
return `';const ${val}=(${unescape(code)});if(typeof ${val}!=="${
TYPES[typ]
}") ${error};out+=${val}+'`
})
.replace(syn.encode, (_, enc = "", code) => {
needEncoders[enc] = true
code = unescape(code)
const e = c.selfContained ? enc : enc ? "." + enc : '[""]'
return `'+${c.encodersPrefix}${e}(${code})+'`
})
.replace(syn.conditional, (_, elseCase, code) => {
if (code) {
code = unescape(code)
return elseCase ? `';}else if(${code}){out+='` : `';if(${code}){out+='`
}
return elseCase ? "';}else{out+='" : "';}out+='"
})
.replace(syn.iterate, (_, arr, vName, iName) => {
if (!arr) return "';} } out+='"
sid++
const defI = iName ? `let ${iName}=-1;` : ""
const incI = iName ? `${iName}++;` : ""
const val = c.internalPrefix + sid
return `';const ${val}=${unescape(
arr
)};if(${val}){${defI}for (const ${vName} of ${val}){${incI}out+='`
})
.replace(syn.evaluate, (_, code) => `';${unescape(code)}out+='`) +
"';return out;"
)
.replace(/\n/g, "\\n")
.replace(/\t/g, "\\t")
.replace(/\r/g, "\\r")
.replace(/(\s|;|\}|^|\{)out\+='';/g, "$1")
.replace(/\+''/g, "")
if (needhtmlencode) {
if (!c.selfcontained && _globals && !_globals._encodeHTML) _globals._encodeHTML = doT.encodeHTMLSource(c.doNotSkipEncoded);
str = "var encodeHTML = typeof _encodeHTML !== 'undefined' ? _encodeHTML : ("
+ doT.encodeHTMLSource.toString() + "(" + (c.doNotSkipEncoded || '') + "));"
+ str;
}
try {
return new Function(c.varname, str);
} catch (e) {
/* istanbul ignore else */
if (typeof console !== "undefined") console.log("Could not create a template function: " + str);
throw e;
}
};
const args = Array.isArray(c.argName) ? properties(c.argName) : c.argName
doT.compile = function(tmpl, def) {
return doT.template(tmpl, null, def);
};
}());
if (Object.keys(needEncoders).length === 0) {
return try_(() => new Function(args, str))
}
checkEncoders(c, needEncoders)
str = `return function(${args}){${str}};`
return try_(() =>
c.selfContained
? new Function((str = addEncoders(c, needEncoders) + str))()
: new Function(c.encodersPrefix, str)(c.encoders)
)
function try_(f) {
try {
return f()
} catch (e) {
console.log("Could not create a template function: " + str)
throw e
}
}
}
function compile(tmpl, def) {
return template(tmpl, null, def)
}
function sameDelimiters({start, end}) {
const d = doT.templateSettings.delimiters
return d.start === start && d.end === end
}
function setDelimiters(delimiters) {
if (sameDelimiters(delimiters)) {
console.log("delimiters did not change")
return
}
currentSyntax = getSyntax(delimiters)
doT.templateSettings.delimiters = delimiters
}
function getSyntax({start, end}) {
start = escape(start)
end = escape(end)
const syntax = {}
for (const syn in defaultSyntax) {
const s = defaultSyntax[syn]
.toString()
.replace(/\\\{\\\{/g, start)
.replace(/\\\}\\\}/g, end)
syntax[syn] = strToRegExp(s)
}
return syntax
}
const escapeCharacters = /([{}[\]()<>\\\/^$\-.+*?!=|&:])/g
function escape(str) {
return str.replace(escapeCharacters, "\\$1")
}
const regexpPattern = /^\/(.*)\/([\w]*)$/
function strToRegExp(str) {
const [, rx, flags] = str.match(regexpPattern)
return new RegExp(rx, flags)
}
function properties(args) {
return args.reduce((s, a, i) => s + (i ? "," : "") + a, "{") + "}"
}
function checkEncoders(c, encoders) {
const typ = encoderType[c.selfContained]
for (const enc in encoders) {
const e = c.encoders[enc]
if (!e) throw new Error(`unknown encoder "${enc}"`)
if (typeof e !== typ)
throw new Error(`selfContained ${c.selfContained}: encoder type must be "${typ}"`)
}
}
function addEncoders(c, encoders) {
let s = ""
for (const enc in encoders) s += `const ${c.encodersPrefix}${enc}=${c.encoders[enc]};`
return s
}

@@ -10,33 +10,29 @@ {

],
"version": "2.0.0-beta.0",
"main": "index",
"bin": {
"dottojs": "./bin/dot-packer"
},
"version": "2.0.0-beta.1",
"main": "doT.js",
"types": "doT.d.ts",
"homepage": "http://github.com/olado/doT",
"repository": "git://github.com/olado/doT.git",
"author": "Laura Doktorova <ldoktorova@gmail.com>",
"engines": [
"node >=0.2.6"
],
"license": "MIT",
"scripts": {
"eslint": "if-node-version '>=4' eslint *.js --ignore-pattern *.min.js",
"test-cov": "nyc mocha test/*.test.js",
"test": "npm run eslint && npm run test-cov",
"bundle": "uglifyjs doT.js -o doT.min.js -c -m --preamble '/* Laura Doktorova https://github.com/olado/doT */'",
"prepublish": "npm run bundle"
"eslint": "eslint {test/,}*.js --ignore-pattern *.min.js",
"prettier:write": "prettier --write './**/*.{md,json,yaml,js,ts}'",
"prettier:check": "prettier --list-different './**/*.{md,json,yaml,js,ts}'",
"test-spec": "mocha test/*.test.js",
"test-cov": "nyc npm run test-spec",
"test-ts": "tsc doT.d.ts",
"test": "npm run eslint && npm run test-cov && npm run test-ts"
},
"dependencies": {},
"devDependencies": {
"commander": "*",
"coveralls": "^2.11.14",
"eslint": "^3.9.1",
"if-node-version": "^1.1.0",
"jshint": "*",
"mkdirp": "*",
"coveralls": "^3.0.9",
"eslint": "^6.7.2",
"eslint-config-prettier": "^6.11.0",
"husky": "^4.2.5",
"lint-staged": "^10.2.11",
"mocha": "*",
"nyc": "^8.3.2",
"pre-commit": "^1.1.3",
"uglify-js": "*"
"nyc": "^14.1.1",
"prettier": "^2.0.5",
"typescript": "^3.9.7"
},

@@ -52,3 +48,11 @@ "nyc": {

]
},
"husky": {
"hooks": {
"pre-commit": "lint-staged && npm test"
}
},
"lint-staged": {
"*.{md,json,yaml,js,ts}": "prettier --write"
}
}

@@ -11,5 +11,14 @@ # doT

## Note from the maintainer
doT is a really solid piece of software engineering (I didn’t create it) that is rarely updated exactly for this reason.
It took me years to grasp how it works even though it’s only 140 lines of code - it looks like magic.
I used it in my other projects (e.g. [ajv](https://github.com/epoberezkin/ajv)) as the smallest, the fastest and the most functional (all three!) templating engine ever made, that is particularly useful in all code generation scenarios where manipulating AST is an overkill.
It’s a race car of templating engines - doT lacks bells and whistles that other templating engines have, but it allows to achive more than any other, if you use it right (YMMV).
## Features
custom delimiters
runtime evaluation

@@ -21,3 +30,2 @@ runtime interpolation

array iterators
encoding
control whitespace - strip or preserve

@@ -33,55 +41,61 @@ streaming friendly

####Added parameters support in partials
#### Added parameters support in partials
{{##def.macro:param:
<div>{{=param.foo}}</div>
#}}
```html
{{##def.macro:param:
<div>{{=param.foo}}</div>
#}} {{#def.macro:myvariable}}
```
{{#def.macro:myvariable}}
#### Node module now supports auto-compilation of dot templates from specified path
####Node module now supports auto-compilation of dot templates from specified path
```js
var dots = require("dot").process({path: "./views"})
```
var dots = require("dot").process({ path: "./views"});
This will compile .def, .dot, .jst files found under the specified path.
Details
* It ignores sub-directories.
* Template files can have multiple extensions at the same time.
* Files with .def extension can be included in other files via {{#def.name}}
* Files with .dot extension are compiled into functions with the same name and
can be accessed as renderer.filename
* Files with .jst extension are compiled into .js files. Produced .js file can be
loaded as a commonJS, AMD module, or just installed into a global variable (default is set to window.render)
* All inline defines defined in the .jst file are
compiled into separate functions and are available via _render.filename.definename
Basic usage:
```
var dots = require("dot").process({path: "./views"});
dots.mytemplate({foo:"hello world"});
```
The above snippet will:
* Compile all templates in views folder (.dot, .def, .jst)
* Place .js files compiled from .jst templates into the same folder
These files can be used with require, i.e. require("./views/mytemplate")
* Return an object with functions compiled from .dot templates as its properties
* Render mytemplate template
####CLI tool to compile dot templates into js files
./bin/dot-packer -s examples/views -d out/views
- It ignores sub-directories.
- Template files can have multiple extensions at the same time.
- Files with .def extension can be included in other files via {{#def.name}}
- Files with .dot extension are compiled into functions with the same name and
can be accessed as renderer.filename
- Files with .jst extension are compiled into .js files. Produced .js file can be
loaded as a commonJS, AMD module, or just installed into a global variable (default is set to window.render)
- All inline defines defined in the .jst file are
compiled into separate functions and are available via \_render.filename.definename
## Example for express
Many people are using doT with express. I added an example of the best way of doing it examples/express:
Basic usage:
[doT with express](examples/express)
```js
var dots = require("dot").process({path: "./views"})
dots.mytemplate({foo: "hello world"})
```
## Notes
doU.js is here only so that legacy external tests do not break. Use doT.js.
doT.js with doT.templateSettings.append=false provides the same performance as doU.js.
The above snippet will:
_ Compile all templates in views folder (.dot, .def, .jst)
_ Place .js files compiled from .jst templates into the same folder
These files can be used with require, i.e. require("./views/mytemplate")
_ Return an object with functions compiled from .dot templates as its properties
_ Render mytemplate template
## Security considerations
doT allows arbitrary JavaScript code in templates, making it one of the most flexible and powerful templating engines. It means that doT security model assumes that you only use trusted templates and you don't use any user input as any part of the template, as otherwise it can lead to code injection.
It is strongly recommended to compile all templates to JS code as early as possible. Possible options:
- using doT as dev-dependency only and compiling templates to JS files, for example, as described above or using a custom script, during the build. This is the most performant and secure approach and it is strongly recommended.
- if the above approach is not possible for some reason (e.g. templates are dynamically generated using some run-time data), it is recommended to compile templates to in-memory functions during application start phase, before any external input is processed.
- compiling templates lazily, on demand, is less safe. Even though the possibility of the code injection via prototype pollution was patched (#291), there may be some other unknown vulnerabilities that could lead to code injection.
Please report any found vulnerabilities to npm, not via issue tracker.
## Author
Laura Doktorova [@olado](http://twitter.com/olado)
## License
doT is licensed under the MIT License. (See LICENSE-DOT)

@@ -88,0 +102,0 @@

@@ -1,55 +0,54 @@

'use strict';
"use strict"
var test = require('./util').test;
const test = require("./util").test
describe('conditionals', function() {
describe('without else', function() {
var templates = [
'{{?it.one < 2}}{{=it.one}}{{?}}{{=it.two}}',
'{{? it.one < 2 }}{{= it.one }}{{?}}{{= it.two }}'
];
describe("conditionals", () => {
describe("without else", () => {
const templates = [
"{{?it.one < 2}}{{=it.one}}{{?}}{{=it.two}}",
"{{? it.one < 2 }}{{= it.one }}{{?}}{{= it.two }}",
]
it('should evaluate condition and include template if valid', function() {
test(templates, {one: 1, two: 2}, '12')
});
it("should evaluate condition and include template if valid", () => {
test(templates, {one: 1, two: 2}, "12")
})
it('should evaluate condition and do NOT include template if invalid', function() {
test(templates, {one: 3, two: 2}, '2')
});
});
it("should evaluate condition and do NOT include template if invalid", () => {
test(templates, {one: 3, two: 2}, "2")
})
})
describe("with else", () => {
const templates = [
"{{?it.one < 2}}{{=it.one}}{{??}}{{=it.two}}{{?}}",
"{{? it.one < 2 }}{{= it.one }}{{??}}{{= it.two }}{{?}}",
]
describe('with else', function() {
var templates = [
'{{?it.one < 2}}{{=it.one}}{{??}}{{=it.two}}{{?}}',
'{{? it.one < 2 }}{{= it.one }}{{??}}{{= it.two }}{{?}}'
];
it('should evaluate condition and include "if" template if valid', () => {
test(templates, {one: 1, two: 2}, "1")
})
it('should evaluate condition and include "if" template if valid', function() {
test(templates, {one: 1, two: 2}, '1')
});
it('should evaluate condition and include "else" template if invalid', () => {
test(templates, {one: 3, two: 2}, "2")
})
})
it('should evaluate condition and include "else" template if invalid', function() {
test(templates, {one: 3, two: 2}, '2')
});
});
describe("with else if", () => {
const templates = [
"{{?it.one < 2}}{{=it.one}}{{??it.two < 3}}{{=it.two}}{{??}}{{=it.three}}{{?}}",
"{{? it.one < 2 }}{{= it.one }}{{?? it.two < 3 }}{{= it.two }}{{??}}{{= it.three }}{{?}}",
]
describe('with else if', function() {
var templates = [
'{{?it.one < 2}}{{=it.one}}{{??it.two < 3}}{{=it.two}}{{??}}{{=it.three}}{{?}}',
'{{? it.one < 2 }}{{= it.one }}{{?? it.two < 3 }}{{= it.two }}{{??}}{{= it.three }}{{?}}'
];
it('should evaluate condition and include "if" template if valid', () => {
test(templates, {one: 1, two: 2, three: 3}, "1")
})
it('should evaluate condition and include "if" template if valid', function() {
test(templates, {one: 1, two: 2, three: 3}, '1')
});
it('should evaluate condition and include "else if" template if second condition valid', () => {
test(templates, {one: 10, two: 2, three: 3}, "2")
})
it('should evaluate condition and include "else if" template if second condition valid', function() {
test(templates, {one: 10, two: 2, three: 3}, '2')
});
it('should evaluate condition and include "else" template if invalid', function() {
test(templates, {one: 10, two: 20, three: 3}, '3')
});
});
});
it('should evaluate condition and include "else" template if invalid', () => {
test(templates, {one: 10, two: 20, three: 3}, "3")
})
})
})

@@ -1,39 +0,94 @@

'use strict';
"use strict"
var test = require('./util').test;
var doT = require('../doT');
var assert = require('assert');
const doT = require("..")
const assert = require("assert")
describe('defines', function() {
describe('without parameters', function() {
it('should render define', function(){
testDef('{{##def.tmp:<div>{{!it.foo}}</div>#}}{{#def.tmp}}');
});
describe("defines", () => {
describe("without parameters", () => {
it("should render define", () => {
testDef("{{##def.tmp:<div>{{=it.foo}}</div>#}}{{#def.tmp}}")
})
it('should render define if it is passed to doT.compile', function() {
testDef('{{#def.tmp}}', {tmp: '<div>{{!it.foo}}</div>'});
});
});
it("should render define if it is passed to doT.compile", () => {
testDef("{{#def.tmp}}", {tmp: "<div>{{=it.foo}}</div>"})
})
})
describe('with parameters', function() {
it('should render define', function(){
testDef('{{##def.tmp:foo:<div>{{!foo}}</div>#}}{{ var bar = it.foo; }}{{# def.tmp:bar }}');
});
describe("with parameters", () => {
it("should render define", () => {
testDef("{{##def.tmp:foo:<div>{{=foo}}</div>#}}{{ var bar = it.foo; }}{{# def.tmp:bar }}")
})
it('should render define multiline params', function(){
testDef('{{##def.tmp:data:{{=data.openTag}}{{!data.foo}}{{=data.closeTag}}#}}\n' +
'{{# def.tmp:{\n' +
' foo: it.foo,\n' +
' openTag: "<div>",\n' +
' closeTag: "</div>"\n' +
'} }}');
});
});
it("should render define multiline params", () => {
testDef(
"{{##def.tmp:data:{{=data.openTag}}{{=data.foo}}{{=data.closeTag}}#}}\n" +
"{{# def.tmp:{\n" +
" foo: it.foo,\n" +
' openTag: "<div>",\n' +
' closeTag: "</div>"\n' +
"} }}"
)
})
function testDef(tmpl, defines) {
var fn = doT.compile(tmpl, defines);
assert.equal(fn({foo:'http'}), '<div>http</div>');
assert.equal(fn({foo:'http://abc.com'}), '<div>http:&#47;&#47;abc.com</div>');
assert.equal(fn({}), '<div></div>');
function compiledDefinesParamTemplate(param) {
const tmpl = `{{##def.tmp:input:<div>{{=input.foo}}</div>#}}{{#def.tmp:${param}}}`
return doT.template(tmpl)
}
});
it("should render define with standard parameter", () => {
const definesParamCompiled = compiledDefinesParamTemplate("it")
assert.equal(definesParamCompiled({foo: "A"}), "<div>A</div>")
assert.equal(definesParamCompiled({}), "<div>undefined</div>")
})
it("should render define with property parameter", () => {
const definesParamCompiled = compiledDefinesParamTemplate("it.bar")
assert.equal(definesParamCompiled({bar: {foo: "B"}}), "<div>B</div>")
assert.throws(() => {
definesParamCompiled({})
}, /TypeError: Cannot read property 'foo' of undefined/)
})
it("should render define with square bracket property parameter", () => {
const definesParamCompiled = compiledDefinesParamTemplate("it['bar']")
assert.equal(definesParamCompiled({bar: {foo: "C"}}), "<div>C</div>")
assert.throws(() => {
definesParamCompiled({})
}, /TypeError: Cannot read property 'foo' of undefined/)
})
it("should render define with square bracket property with space parameter", () => {
const definesParamCompiled = compiledDefinesParamTemplate("it['bar baz']")
assert.equal(definesParamCompiled({"bar baz": {foo: "D"}}), "<div>D</div>")
assert.throws(() => {
definesParamCompiled({})
}, /TypeError: Cannot read property 'foo' of undefined/)
})
it("should render define with array index property parameter", () => {
const definesParamCompiled = compiledDefinesParamTemplate("it[1]")
assert.equal(definesParamCompiled(["not this", {foo: "E"}, "not this"]), "<div>E</div>")
assert.throws(() => {
definesParamCompiled({})
}, /TypeError: Cannot read property 'foo' of undefined/)
})
it("should render define with deep properties parameter", () => {
const definesParamCompiled = compiledDefinesParamTemplate("it['bar baz'].qux[1]")
assert.equal(
definesParamCompiled({"bar baz": {qux: ["not this", {foo: "F"}, "not this"]}}),
"<div>F</div>"
)
assert.throws(() => {
definesParamCompiled({})
}, /TypeError: Cannot read property 'qux' of undefined/)
})
})
function testDef(tmpl, defines) {
const fn = doT.compile(tmpl, defines)
assert.equal(fn({foo: "http"}), "<div>http</div>")
assert.equal(fn({foo: "http://abc.com"}), "<div>http://abc.com</div>")
assert.equal(fn({}), "<div>undefined</div>")
}
})

@@ -1,76 +0,199 @@

'use strict';
"use strict"
var test = require('./util').test;
var assert = require("assert")
var doT = require("../doT");
const test = require("./util").test
const assert = require("assert")
const doT = require("..")
describe("doT", () => {
const basictemplate = "<div>{{=it.foo}}</div>"
const basiccompiled = doT.template(basictemplate)
describe('doT', function(){
var basictemplate = "<div>{{!it.foo}}</div>";
var basiccompiled = doT.template(basictemplate);
describe("#template()", () => {
it("should return a function", () => {
assert.equal(typeof basiccompiled, "function")
})
})
describe('.name', function (){
it('should have a name', function(){
assert.strictEqual(doT.name, 'doT');
});
});
describe('#template()', function(){
it('should return a function', function(){
assert.equal(typeof basiccompiled, "function");
});
});
describe("#()", () => {
it("should render the template", () => {
assert.equal(basiccompiled({foo: "http"}), "<div>http</div>")
assert.equal(basiccompiled({foo: "http://abc.com"}), "<div>http://abc.com</div>")
assert.equal(basiccompiled({}), "<div>undefined</div>")
})
})
describe('#()', function(){
it('should render the template', function(){
assert.equal(basiccompiled({foo:"http"}), "<div>http</div>");
assert.equal(basiccompiled({foo:"http://abc.com"}), "<div>http:&#47;&#47;abc.com</div>");
assert.equal(basiccompiled({}), "<div></div>");
});
});
describe("encoding with doNotSkipEncoded=false", () => {
it("should not replace &", () => {
const fn = doT.template("<div>{{=it.foo}}</div>")
assert.equal(fn({foo: "&amp;"}), "<div>&amp;</div>")
})
})
describe('encoding with doNotSkipEncoded=false', function() {
it('should not replace &', function() {
global._encodeHTML = undefined;
doT.templateSettings.doNotSkipEncoded = false;
var fn = doT.template('<div>{{!it.foo}}</div>');
assert.equal(fn({foo:"&amp;"}), "<div>&amp;</div>");
});
});
describe("interpolate 2 numbers", () => {
it("should print numbers next to each other", () => {
test(
["{{=it.one}}{{=it.two}}", "{{= it.one}}{{= it.two}}", "{{= it.one }}{{= it.two }}"],
{one: 1, two: 2},
"12"
)
})
})
describe('interpolate 2 numbers', function() {
it('should print numbers next to each other', function() {
test([
'{{=it.one}}{{=it.two}}',
'{{= it.one}}{{= it.two}}',
'{{= it.one }}{{= it.two }}'
], {one:1, two: 2}, '12');
});
});
describe("type-safe interpolation", () => {
it("should interpolate correct types", () => {
test(
[
"{{%n=it.num}}-{{%s=it.str}}-{{%b=it.bool}}",
"{{%n= it.num}}-{{%s= it.str}}-{{%b= it.bool}}",
"{{%n= it.num }}-{{%s= it.str }}-{{%b= it.bool }}",
],
{num: 1, str: "foo", bool: true},
"1-foo-true"
)
})
describe('evaluate JavaScript', function() {
it('should print numbers next to each other', function() {
test([
'{{ it.one = 1; it.two = 2; }}{{= it.one }}{{= it.two }}',
], {}, '12');
});
});
it("should throw render-time exception on incorrect data types", () => {
const numTmpl = doT.template("{{%n=it.num}}")
assert.strictEqual(numTmpl({num: 1}), "1")
assert.throws(() => numTmpl({num: "1"}))
assert.throws(() => numTmpl({num: true}))
describe('encoding with doNotSkipEncoded=true', function() {
it('should replace &', function() {
global._encodeHTML = undefined;
doT.templateSettings.doNotSkipEncoded = true;
assert.equal(doT.template('<div>{{!it.foo}}</div>')({foo:"&amp;"}), "<div>&#38;amp;</div>");
assert.equal(doT.template('{{!it.a}}')({a:"& < > / ' \""}), "&#38; &#60; &#62; &#47; &#39; &#34;");
assert.equal(doT.template('{{!"& < > / \' \\""}}')(), "&#38; &#60; &#62; &#47; &#39; &#34;");
});
});
const strTmpl = doT.template("{{%s=it.str}}")
assert.strictEqual(strTmpl({str: "foo"}), "foo")
assert.throws(() => strTmpl({str: 1}))
assert.throws(() => strTmpl({str: true}))
describe('invalid JS in templates', function() {
it('should throw exception', function() {
assert.throws(function() {
var fn = doT.template('<div>{{= foo + }}</div>');
});
});
});
});
const boolTmpl = doT.template("{{%b=it.bool}}")
assert.strictEqual(boolTmpl({bool: true}), "true")
assert.throws(() => boolTmpl({bool: "true"}))
assert.throws(() => boolTmpl({bool: 1}))
})
})
describe("evaluate JavaScript", () => {
it("should print numbers next to each other", () => {
test(["{{ it.one = 1; it.two = 2; }}{{= it.one }}{{= it.two }}"], {}, "12")
})
})
describe("no HTML encoding by default", () => {
it("should NOT replace &", () => {
assert.equal(doT.template("<div>{{=it.foo}}</div>")({foo: "&amp;"}), "<div>&amp;</div>")
assert.equal(doT.template("{{=it.a}}")({a: "& < > / ' \""}), "& < > / ' \"")
assert.equal(doT.template('{{="& < > / \' \\""}}')(), "& < > / ' \"")
})
})
describe("custom encoders", () => {
describe("selfContained: false (default)", () => {
it("should run specified encoder", () => {
const cfg = {
encoders: {
str: JSON.stringify,
rx: (s) => new RegExp(s).toString(),
},
}
assert.equal(doT.template("{{str! it}}", cfg)({foo: "bar"}), '{"foo":"bar"}')
assert.equal(doT.template("{{rx! it.regex}}", cfg)({regex: "foo.*"}), "/foo.*/")
})
it("should encode HTML with provided encoder", () => {
const encodeHTML = require("../encodeHTML")()
test({
encoders: {
"": encodeHTML,
},
})
function test(cfg) {
const tmpl = doT.template("<div>{{!it.foo}}</div>", cfg)
assert.equal(tmpl({foo: "http://abc.com"}), "<div>http:&#47;&#47;abc.com</div>")
assert.equal(tmpl({foo: "&amp;"}), "<div>&amp;</div>")
}
})
it("should throw compile time exception if encoder is not specified", () => {
const cfg = {
encoders: {
str: JSON.stringify,
},
}
assert.doesNotThrow(() => doT.template("{{str! it}}", cfg))
assert.throws(() => doT.template("{{rx! it}}", cfg), /unknown encoder/)
})
})
describe("selfContained: true", () => {
it("should inline specified encoders passed as strings", () => {
const cfg = {
selfContained: true,
encoders: {
str: "JSON.stringify",
rx: "(s) => new RegExp(s).toString()",
},
}
assert.equal(doT.template("{{str! it}}", cfg)({foo: "bar"}), '{"foo":"bar"}')
assert.equal(doT.template("{{rx! it.regex}}", cfg)({regex: "foo.*"}), "/foo.*/")
})
it("should encode HTML with inlined HTML encoder", () => {
const getEncodeHTML = require("../encodeHTML").toString()
test({
selfContained: true,
encoders: {
"": getEncodeHTML + "()",
},
})
function test(cfg) {
const tmpl = doT.template("<div>{{!it.foo}}</div>", cfg)
assert.equal(tmpl({foo: "http://abc.com"}), "<div>http:&#47;&#47;abc.com</div>")
assert.equal(tmpl({foo: "&amp;"}), "<div>&amp;</div>")
}
})
it("should throw compile-time exception if encoder is not specified", () => {
const cfg = {
selfContained: true,
encoders: {
str: "JSON.stringify",
},
}
assert.doesNotThrow(() => doT.template("{{str! it}}", cfg))
assert.throws(() => doT.template("{{rx! it}}", cfg), /unknown encoder/)
})
it("should throw compile-time exception if encoder is of incorrect type", () => {
const cfg = {
encoders: {
str: JSON.stringify,
rx: "(s) => new RegExp(s).toString()",
},
}
assert.doesNotThrow(() => doT.template("{{str! it}}", cfg))
assert.doesNotThrow(() => doT.template("{{rx! it}}", {...cfg, selfContained: true}))
assert.throws(
() => doT.template("{{str! it}}", {...cfg, selfContained: true}),
/encoder type must be "string"/
)
assert.throws(() => doT.template("{{rx! it}}", cfg), /encoder type must be "function"/)
})
})
})
describe("context destructuring", () => {
it('should interpolate properties without "it"', () => {
const tmpl = doT.template("{{=foo}}{{=bar}}", {argName: ["foo", "bar"]})
console.log(tmpl.toString())
assert.equal(tmpl({foo: 1, bar: 2}), "12")
})
})
describe("invalid JS in templates", () => {
it("should throw exception", () => {
assert.throws(() => {
doT.template("<div>{{= foo + }}</div>")
})
})
})
})

@@ -1,39 +0,89 @@

'use strict';
"use strict"
var test = require('./util').test;
const test = require("./util").test
const assert = require("assert")
describe('iteration', function() {
describe('without index', function() {
it('should repeat string N times', function() {
test([
'{{~it.arr:x}}*{{~}}',
'{{~ it.arr:x }}*{{~}}',
'{{~ it.arr: x }}*{{~}}',
'{{~ it.arr :x }}*{{~}}'
], {arr: Array(3)}, '***');
});
describe("iteration", () => {
describe("without index", () => {
it("should repeat string N times", () => {
test(
[
"{{~it.arr:x}}*{{~}}",
"{{~ it.arr:x }}*{{~}}",
"{{~ it.arr: x }}*{{~}}",
"{{~ it.arr :x }}*{{~}}",
],
{arr: Array(3)},
"***"
)
})
it('should concatenate items', function() {
test(['{{~it.arr:x}}{{=x}}{{~}}'], {arr: [1,2,3]}, '123');
});
});
it("should concatenate items", () => {
test(["{{~it.arr:x}}{{=x}}{{~}}"], {arr: [1, 2, 3]}, "123")
})
})
describe('with index', function() {
it('should repeat string N times', function() {
test([
'{{~it.arr:x:i}}*{{~}}',
'{{~ it.arr : x : i }}*{{~}}'
], {arr: Array(3)}, '***');
});
describe("with index", () => {
it("should repeat string N times", () => {
test(["{{~it.arr:x:i}}*{{~}}", "{{~ it.arr : x : i }}*{{~}}"], {arr: Array(3)}, "***")
})
it('should concatenate indices', function() {
test(['{{~it.arr:x:i}}{{=i}}{{~}}'], {arr: Array(3)}, '012');
});
it("should concatenate indices", () => {
test(["{{~it.arr:x:i}}{{=i}}{{~}}"], {arr: Array(3)}, "012")
})
it('should concatenate indices and items', function() {
test([
'{{~it.arr:x:i}}{{?i}}, {{?}}{{=i}}:{{=x}}{{~}}'
], {arr: [10,20,30]}, '0:10, 1:20, 2:30');
});
});
});
it("should concatenate indices and items", () => {
test(
["{{~it.arr:x:i}}{{?i}}, {{?}}{{=i}}:{{=x}}{{~}}"],
{arr: [10, 20, 30]},
"0:10, 1:20, 2:30"
)
})
it("should interpolate nested array even if the same index variable is used", () => {
test(
["{{~it.arr:x:i}}{{~x:y:i}}{{=y}}{{~}}{{~}}"],
{
arr: [
[1, 2, 3],
[4, 5, 6],
],
},
"123456"
)
})
})
describe("iterables", () => {
const set = new Set([1, 2, 3])
describe("without index", () => {
it("should repeat string N times", () => {
assert.strictEqual(Array.isArray(set.values()), false)
test(["{{~it.arr:x}}*{{~}}"], {arr: set.values()}, "***")
})
it("should concatenate items", () => {
test(["{{~it.arr:x}}{{=x}}{{~}}"], {arr: set.values()}, "123")
})
})
describe("with index", () => {
it("should repeat string N times", () => {
test(["{{~it.arr:x:i}}*{{~}}"], {arr: set.values()}, "***")
})
it("should concatenate indices", () => {
test(["{{~it.arr:x:i}}{{=i}}{{~}}"], {arr: set.values()}, "012")
})
it("should concatenate indices and items", () => {
test(
["{{~it.arr:x:i}}{{?i}}, {{?}}{{=i}}:{{=x}}{{~}}"],
{arr: set.values()},
"0:1, 1:2, 2:3"
)
})
})
})
})

@@ -1,11 +0,11 @@

'use strict';
"use strict"
var assert = require('assert')
var doT = require('../doT');
const assert = require("assert")
const doT = require("../doT")
exports.test = function (templates, data, result) {
templates.forEach(function (tmpl) {
var fn = doT.template(tmpl);
assert.strictEqual(fn(data), result);
});
};
templates.forEach((tmpl) => {
const fn = doT.template(tmpl)
assert.strictEqual(fn(data), result)
})
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc