Comparing version 2.0.0-beta.0 to 2.0.0-beta.1
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 = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'", "/": "/" }, | ||
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://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://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: "&"}), "<div>&</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:"&"}), "<div>&</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:"&"}), "<div>&amp;</div>"); | ||
assert.equal(doT.template('{{!it.a}}')({a:"& < > / ' \""}), "& < > / ' ""); | ||
assert.equal(doT.template('{{!"& < > / \' \\""}}')(), "& < > / ' ""); | ||
}); | ||
}); | ||
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: "&"}), "<div>&</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://abc.com</div>") | ||
assert.equal(tmpl({foo: "&"}), "<div>&</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://abc.com</div>") | ||
assert.equal(tmpl({foo: "&"}), "<div>&</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
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
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
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
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
9
105
2
38047
27
698