Merge branch 'master' of https://github.com/ryanmurakami/handlebars.js
This commit is contained in:
+2
-2
@@ -13,12 +13,12 @@ env:
|
||||
- secure: Nm4AgSfsgNB21kgKrF9Tl7qVZU8YYREhouQunFracTcZZh2NZ2XH5aHuSiXCj88B13Cr/jGbJKsZ4T3QS3wWYtz6lkyVOx3H3iI+TMtqhD9RM3a7A4O+4vVN8IioB2YjhEu0OKjwgX5gp+0uF+pLEi7Hpj6fupD3AbbL5uYcKg8=
|
||||
matrix:
|
||||
include:
|
||||
- node_js: '0.12'
|
||||
- node_js: '5'
|
||||
env:
|
||||
- PUBLISH=true
|
||||
- secure: pLTzghtVll9yGKJI0AaB0uI8GypfWxLTaIB0ZL8//yN3nAEIKMhf/RRilYTsn/rKj2NUa7vt2edYILi3lttOUlCBOwTc9amiRms1W8Lwr/3IdWPeBLvLuH1zNJRm2lBAwU4LBSqaOwhGaxOQr6KHTnWudhNhgOucxpZfvfI/dFw=
|
||||
- secure: yERYCf7AwL11D9uMtacly/THGV8BlzsMmrt+iQVvGA3GaY6QMmfYqf6P6cCH98sH5etd1Y+1e6YrPeMjqI6lyRllT7FptoyOdHulazQe86VQN4sc0EpqMlH088kB7gGjTut9Z+X9ViooT5XEh9WA5jXEI9pXhQJNoIHkWPuwGuY=
|
||||
- node_js: '4.0.0'
|
||||
- node_js: '4'
|
||||
cache:
|
||||
directories:
|
||||
- node_modules
|
||||
|
||||
+5
-6
@@ -125,7 +125,7 @@ module.exports = function(grunt) {
|
||||
options: {
|
||||
mangle: true,
|
||||
compress: true,
|
||||
preserveComments: 'some'
|
||||
preserveComments: /(?:^!|@(?:license|preserve|cc_on))/
|
||||
},
|
||||
dist: {
|
||||
files: [{
|
||||
@@ -166,11 +166,10 @@ module.exports = function(grunt) {
|
||||
browsers: [
|
||||
{browserName: 'chrome'},
|
||||
{browserName: 'firefox', platform: 'Linux'},
|
||||
{browserName: 'safari', version: 7, platform: 'OS X 10.9'},
|
||||
{browserName: 'safari', version: 6, platform: 'OS X 10.8'},
|
||||
{browserName: 'safari', version: 9, platform: 'OS X 10.11'},
|
||||
{browserName: 'safari', version: 8, platform: 'OS X 10.10'},
|
||||
{browserName: 'internet explorer', version: 11, platform: 'Windows 8.1'},
|
||||
{browserName: 'internet explorer', version: 10, platform: 'Windows 8'},
|
||||
{browserName: 'internet explorer', version: 9, platform: 'Windows 7'}
|
||||
{browserName: 'internet explorer', version: 10, platform: 'Windows 8'}
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -211,7 +210,7 @@ module.exports = function(grunt) {
|
||||
this.registerTask('globals', ['webpack']);
|
||||
this.registerTask('tests', ['concat:tests']);
|
||||
|
||||
this.registerTask('release', 'Build final packages', ['eslint', 'amd', 'uglify', 'copy:dist', 'copy:components', 'copy:cdnjs']);
|
||||
this.registerTask('release', 'Build final packages', ['eslint', 'amd', 'uglify', 'test:min', 'copy:dist', 'copy:components', 'copy:cdnjs']);
|
||||
|
||||
// Load tasks from npm
|
||||
grunt.loadNpmTasks('grunt-contrib-clean');
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "handlebars",
|
||||
"version": "4.0.4",
|
||||
"version": "4.0.5",
|
||||
"main": "handlebars.js",
|
||||
"license": "MIT",
|
||||
"dependencies": {}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<package>
|
||||
<metadata>
|
||||
<id>handlebars.js</id>
|
||||
<version>4.0.4</version>
|
||||
<version>4.0.5</version>
|
||||
<authors>handlebars.js Authors</authors>
|
||||
<licenseUrl>https://github.com/wycats/handlebars.js/blob/master/LICENSE</licenseUrl>
|
||||
<projectUrl>https://github.com/wycats/handlebars.js/</projectUrl>
|
||||
|
||||
@@ -4,7 +4,7 @@ import {registerDefaultHelpers} from './helpers';
|
||||
import {registerDefaultDecorators} from './decorators';
|
||||
import logger from './logger';
|
||||
|
||||
export const VERSION = '4.0.4';
|
||||
export const VERSION = '4.0.5';
|
||||
export const COMPILER_REVISION = 7;
|
||||
|
||||
export const REVISION_CHANGES = {
|
||||
|
||||
@@ -49,8 +49,6 @@ Compiler.prototype = {
|
||||
this.opcodes = [];
|
||||
this.children = [];
|
||||
this.options = options;
|
||||
this.stringParams = options.stringParams;
|
||||
this.trackIds = options.trackIds;
|
||||
|
||||
options.blockParams = options.blockParams || [];
|
||||
|
||||
@@ -393,49 +391,7 @@ Compiler.prototype = {
|
||||
},
|
||||
|
||||
pushParam: function(val) {
|
||||
let value = val.value != null ? val.value : val.original || '';
|
||||
|
||||
if (this.stringParams) {
|
||||
if (value.replace) {
|
||||
value = value
|
||||
.replace(/^(\.?\.\/)*/g, '')
|
||||
.replace(/\//g, '.');
|
||||
}
|
||||
|
||||
if (val.depth) {
|
||||
this.addDepth(val.depth);
|
||||
}
|
||||
this.opcode('getContext', val.depth || 0);
|
||||
this.opcode('pushStringParam', value, val.type);
|
||||
|
||||
if (val.type === 'SubExpression') {
|
||||
// SubExpressions get evaluated and passed in
|
||||
// in string params mode.
|
||||
this.accept(val);
|
||||
}
|
||||
} else {
|
||||
if (this.trackIds) {
|
||||
let blockParamIndex;
|
||||
if (val.parts && !AST.helpers.scopedId(val) && !val.depth) {
|
||||
blockParamIndex = this.blockParamIndex(val.parts[0]);
|
||||
}
|
||||
if (blockParamIndex) {
|
||||
let blockParamChild = val.parts.slice(1).join('.');
|
||||
this.opcode('pushId', 'BlockParam', blockParamIndex, blockParamChild);
|
||||
} else {
|
||||
value = val.original || value;
|
||||
if (value.replace) {
|
||||
value = value
|
||||
.replace(/^this(?:\.|$)/, '')
|
||||
.replace(/^\.\//, '')
|
||||
.replace(/^\.$/, '');
|
||||
}
|
||||
|
||||
this.opcode('pushId', val.type, value);
|
||||
}
|
||||
}
|
||||
this.accept(val);
|
||||
}
|
||||
this.accept(val);
|
||||
},
|
||||
|
||||
setupFullMustacheParams: function(sexpr, program, inverse, omitEmpty) {
|
||||
@@ -505,25 +461,12 @@ export function compile(input, options = {}, env) {
|
||||
}
|
||||
|
||||
// Template is only compiled on first use and cached after that point.
|
||||
function ret(context, execOptions) {
|
||||
return function(context, execOptions) {
|
||||
if (!compiled) {
|
||||
compiled = compileInput();
|
||||
}
|
||||
return compiled.call(this, context, execOptions);
|
||||
}
|
||||
ret._setup = function(setupOptions) {
|
||||
if (!compiled) {
|
||||
compiled = compileInput();
|
||||
}
|
||||
return compiled._setup(setupOptions);
|
||||
};
|
||||
ret._child = function(i, data, blockParams, depths) {
|
||||
if (!compiled) {
|
||||
compiled = compileInput();
|
||||
}
|
||||
return compiled._child(i, data, blockParams, depths);
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
function argEquals(a, b) {
|
||||
|
||||
@@ -57,8 +57,6 @@ JavaScriptCompiler.prototype = {
|
||||
compile: function(environment, options, context, asObject) {
|
||||
this.environment = environment;
|
||||
this.options = options;
|
||||
this.stringParams = this.options.stringParams;
|
||||
this.trackIds = this.options.trackIds;
|
||||
this.precompile = !asObject;
|
||||
|
||||
this.name = this.environment.name;
|
||||
@@ -498,37 +496,7 @@ JavaScriptCompiler.prototype = {
|
||||
this.push([this.aliasable('container.lambda'), '(', this.popStack(), ', ', this.contextName(0), ')']);
|
||||
},
|
||||
|
||||
// [pushStringParam]
|
||||
//
|
||||
// On stack, before: ...
|
||||
// On stack, after: string, currentContext, ...
|
||||
//
|
||||
// This opcode is designed for use in string mode, which
|
||||
// provides the string value of a parameter along with its
|
||||
// depth rather than resolving it immediately.
|
||||
pushStringParam: function(string, type) {
|
||||
this.pushContext();
|
||||
this.pushString(type);
|
||||
|
||||
// If it's a subexpression, the string result
|
||||
// will be pushed after this opcode.
|
||||
if (type !== 'SubExpression') {
|
||||
if (typeof string === 'string') {
|
||||
this.pushString(string);
|
||||
} else {
|
||||
this.pushStackLiteral(string);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
emptyHash: function(omitEmpty) {
|
||||
if (this.trackIds) {
|
||||
this.push('{}'); // hashIds
|
||||
}
|
||||
if (this.stringParams) {
|
||||
this.push('{}'); // hashContexts
|
||||
this.push('{}'); // hashTypes
|
||||
}
|
||||
this.pushStackLiteral(omitEmpty ? 'undefined' : '{}');
|
||||
},
|
||||
pushHash: function() {
|
||||
@@ -541,14 +509,6 @@ JavaScriptCompiler.prototype = {
|
||||
let hash = this.hash;
|
||||
this.hash = this.hashes.pop();
|
||||
|
||||
if (this.trackIds) {
|
||||
this.push(this.objectLiteral(hash.ids));
|
||||
}
|
||||
if (this.stringParams) {
|
||||
this.push(this.objectLiteral(hash.contexts));
|
||||
this.push(this.objectLiteral(hash.types));
|
||||
}
|
||||
|
||||
this.push(this.objectLiteral(hash.values));
|
||||
},
|
||||
|
||||
@@ -727,44 +687,7 @@ JavaScriptCompiler.prototype = {
|
||||
//
|
||||
// Pops a value off the stack and assigns it to the current hash
|
||||
assignToHash: function(key) {
|
||||
let value = this.popStack(),
|
||||
context,
|
||||
type,
|
||||
id;
|
||||
|
||||
if (this.trackIds) {
|
||||
id = this.popStack();
|
||||
}
|
||||
if (this.stringParams) {
|
||||
type = this.popStack();
|
||||
context = this.popStack();
|
||||
}
|
||||
|
||||
let hash = this.hash;
|
||||
if (context) {
|
||||
hash.contexts[key] = context;
|
||||
}
|
||||
if (type) {
|
||||
hash.types[key] = type;
|
||||
}
|
||||
if (id) {
|
||||
hash.ids[key] = id;
|
||||
}
|
||||
hash.values[key] = value;
|
||||
},
|
||||
|
||||
pushId: function(type, name, child) {
|
||||
if (type === 'BlockParam') {
|
||||
this.pushStackLiteral(
|
||||
'blockParams[' + name[0] + '].path[' + name[1] + ']'
|
||||
+ (child ? ' + ' + JSON.stringify('.' + child) : ''));
|
||||
} else if (type === 'PathExpression') {
|
||||
this.pushString(name);
|
||||
} else if (type === 'SubExpression') {
|
||||
this.pushStackLiteral('true');
|
||||
} else {
|
||||
this.pushStackLiteral('null');
|
||||
}
|
||||
this.hash.values[key] = this.popStack();
|
||||
},
|
||||
|
||||
// HELPERS
|
||||
@@ -997,9 +920,6 @@ JavaScriptCompiler.prototype = {
|
||||
|
||||
setupParams: function(helper, paramSize, params) {
|
||||
let options = {},
|
||||
contexts = [],
|
||||
types = [],
|
||||
ids = [],
|
||||
objectArgs = !params,
|
||||
param;
|
||||
|
||||
@@ -1010,14 +930,6 @@ JavaScriptCompiler.prototype = {
|
||||
options.name = this.quotedString(helper);
|
||||
options.hash = this.popStack();
|
||||
|
||||
if (this.trackIds) {
|
||||
options.hashIds = this.popStack();
|
||||
}
|
||||
if (this.stringParams) {
|
||||
options.hashTypes = this.popStack();
|
||||
options.hashContexts = this.popStack();
|
||||
}
|
||||
|
||||
let inverse = this.popStack(),
|
||||
program = this.popStack();
|
||||
|
||||
@@ -1034,28 +946,12 @@ JavaScriptCompiler.prototype = {
|
||||
while (i--) {
|
||||
param = this.popStack();
|
||||
params[i] = param;
|
||||
|
||||
if (this.trackIds) {
|
||||
ids[i] = this.popStack();
|
||||
}
|
||||
if (this.stringParams) {
|
||||
types[i] = this.popStack();
|
||||
contexts[i] = this.popStack();
|
||||
}
|
||||
}
|
||||
|
||||
if (objectArgs) {
|
||||
options.args = this.source.generateArray(params);
|
||||
}
|
||||
|
||||
if (this.trackIds) {
|
||||
options.ids = this.source.generateArray(ids);
|
||||
}
|
||||
if (this.stringParams) {
|
||||
options.types = this.source.generateArray(types);
|
||||
options.contexts = this.source.generateArray(contexts);
|
||||
}
|
||||
|
||||
if (this.options.data) {
|
||||
options.data = 'data';
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ function Exception(message, node) {
|
||||
message += ' - ' + line + ':' + column;
|
||||
}
|
||||
|
||||
let tmp = Error.prototype.constructor.call(this, message);
|
||||
let tmp = Error.prototype.constructor.call(this, message, loc && loc.source, line);
|
||||
|
||||
// Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work.
|
||||
for (let idx = 0; idx < errorProps.length; idx++) {
|
||||
@@ -24,9 +24,20 @@ function Exception(message, node) {
|
||||
Error.captureStackTrace(this, Exception);
|
||||
}
|
||||
|
||||
if (loc) {
|
||||
this.lineNumber = line;
|
||||
this.column = column;
|
||||
try {
|
||||
if (loc) {
|
||||
this.lineNumber = line;
|
||||
|
||||
// Work around issue under safari where we can't directly set the column value
|
||||
/* istanbul ignore next */
|
||||
if (Object.defineProperty) {
|
||||
Object.defineProperty(this, 'column', {value: column});
|
||||
} else {
|
||||
this.column = column;
|
||||
}
|
||||
}
|
||||
} catch (nop) {
|
||||
/* Ignore if the browser is very particular */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {appendContextPath, createFrame, isArray} from '../utils';
|
||||
import {isArray} from '../utils';
|
||||
|
||||
export default function(instance) {
|
||||
instance.registerHelper('blockHelperMissing', function(context, options) {
|
||||
@@ -11,21 +11,11 @@ export default function(instance) {
|
||||
return inverse(this);
|
||||
} else if (isArray(context)) {
|
||||
if (context.length > 0) {
|
||||
if (options.ids) {
|
||||
options.ids = [options.name];
|
||||
}
|
||||
|
||||
return instance.helpers.each(context, options);
|
||||
} else {
|
||||
return inverse(this);
|
||||
}
|
||||
} else {
|
||||
if (options.data && options.ids) {
|
||||
let data = createFrame(options.data);
|
||||
data.contextPath = appendContextPath(options.data.contextPath, options.name);
|
||||
options = {data: data};
|
||||
}
|
||||
|
||||
return fn(context, options);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {appendContextPath, blockParams, createFrame, isArray, isFunction} from '../utils';
|
||||
import {createFrame, isArray, isFunction} from '../utils';
|
||||
import Exception from '../exception';
|
||||
|
||||
export default function(instance) {
|
||||
@@ -11,12 +11,7 @@ export default function(instance) {
|
||||
inverse = options.inverse,
|
||||
i = 0,
|
||||
ret = '',
|
||||
data,
|
||||
contextPath;
|
||||
|
||||
if (options.data && options.ids) {
|
||||
contextPath = appendContextPath(options.data.contextPath, options.ids[0]) + '.';
|
||||
}
|
||||
data;
|
||||
|
||||
if (isFunction(context)) { context = context.call(this); }
|
||||
|
||||
@@ -30,15 +25,11 @@ export default function(instance) {
|
||||
data.index = index;
|
||||
data.first = index === 0;
|
||||
data.last = !!last;
|
||||
|
||||
if (contextPath) {
|
||||
data.contextPath = contextPath + field;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ret + fn(context[field], {
|
||||
data: data,
|
||||
blockParams: blockParams([context[field], field], [contextPath + field, null])
|
||||
blockParams: [context[field], field]
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {appendContextPath, blockParams, createFrame, isEmpty, isFunction} from '../utils';
|
||||
import {isEmpty, isFunction} from '../utils';
|
||||
|
||||
export default function(instance) {
|
||||
instance.registerHelper('with', function(context, options) {
|
||||
@@ -8,14 +8,10 @@ export default function(instance) {
|
||||
|
||||
if (!isEmpty(context)) {
|
||||
let data = options.data;
|
||||
if (options.data && options.ids) {
|
||||
data = createFrame(options.data);
|
||||
data.contextPath = appendContextPath(options.data.contextPath, options.ids[0]);
|
||||
}
|
||||
|
||||
return fn(context, {
|
||||
data: data,
|
||||
blockParams: blockParams([context], [data && data.contextPath])
|
||||
blockParams: [context]
|
||||
});
|
||||
} else {
|
||||
return options.inverse(this);
|
||||
|
||||
@@ -8,5 +8,6 @@ export default function(Handlebars) {
|
||||
if (root.Handlebars === Handlebars) {
|
||||
root.Handlebars = $Handlebars;
|
||||
}
|
||||
return Handlebars;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -38,9 +38,6 @@ export function template(templateSpec, env) {
|
||||
function invokePartialWrapper(partial, context, options) {
|
||||
if (options.hash) {
|
||||
context = Utils.extend({}, context, options.hash);
|
||||
if (options.ids) {
|
||||
options.ids[0] = true;
|
||||
}
|
||||
}
|
||||
|
||||
partial = env.VM.resolvePartial.call(this, partial, context, options);
|
||||
@@ -132,7 +129,7 @@ export function template(templateSpec, env) {
|
||||
function ret(context, options = {}) {
|
||||
let data = options.data;
|
||||
|
||||
ret._setup(options);
|
||||
_setup(options);
|
||||
if (!options.partial && templateSpec.useData) {
|
||||
data = initData(context, data);
|
||||
}
|
||||
@@ -140,7 +137,7 @@ export function template(templateSpec, env) {
|
||||
blockParams = templateSpec.useBlockParams ? [] : undefined;
|
||||
if (templateSpec.useDepths) {
|
||||
if (options.depths) {
|
||||
depths = context !== options.depths[0] ? [context].concat(options.depths) : options.depths;
|
||||
depths = context != options.depths[0] ? [context].concat(options.depths) : options.depths;
|
||||
} else {
|
||||
depths = [context];
|
||||
}
|
||||
@@ -154,7 +151,7 @@ export function template(templateSpec, env) {
|
||||
}
|
||||
ret.isTop = true;
|
||||
|
||||
ret._setup = function(options) {
|
||||
function _setup(options) {
|
||||
if (!options.partial) {
|
||||
container.helpers = container.merge(options.helpers, env.helpers);
|
||||
|
||||
@@ -169,25 +166,15 @@ export function template(templateSpec, env) {
|
||||
container.partials = options.partials;
|
||||
container.decorators = options.decorators;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ret._child = function(i, data, blockParams, depths) {
|
||||
if (templateSpec.useBlockParams && !blockParams) {
|
||||
throw new Exception('must pass block params');
|
||||
}
|
||||
if (templateSpec.useDepths && !depths) {
|
||||
throw new Exception('must pass parent depths');
|
||||
}
|
||||
|
||||
return wrapProgram(container, i, templateSpec[i], data, 0, blockParams, depths);
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
export function wrapProgram(container, i, fn, data, declaredBlockParams, blockParams, depths) {
|
||||
function prog(context, options = {}) {
|
||||
let currentDepths = depths;
|
||||
if (depths && context !== depths[0]) {
|
||||
if (depths && context != depths[0]) {
|
||||
currentDepths = [context].concat(depths);
|
||||
}
|
||||
|
||||
@@ -224,9 +211,6 @@ export function resolvePartial(partial, context, options) {
|
||||
|
||||
export function invokePartial(partial, context, options) {
|
||||
options.partial = true;
|
||||
if (options.ids) {
|
||||
options.data.contextPath = options.ids[0] || options.data.contextPath;
|
||||
}
|
||||
|
||||
let partialBlock;
|
||||
if (options.fn && options.fn !== noop) {
|
||||
|
||||
@@ -98,11 +98,3 @@ export function createFrame(object) {
|
||||
return frame;
|
||||
}
|
||||
|
||||
export function blockParams(params, ids) {
|
||||
params.path = ids;
|
||||
return params;
|
||||
}
|
||||
|
||||
export function appendContextPath(contextPath, id) {
|
||||
return (contextPath ? contextPath + '.' : '') + id;
|
||||
}
|
||||
|
||||
+5
-3
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "handlebars",
|
||||
"barename": "handlebars",
|
||||
"version": "4.0.4",
|
||||
"version": "4.0.5",
|
||||
"description": "Handlebars provides the power necessary to let you build semantic templates effectively with no frustration",
|
||||
"homepage": "http://www.handlebarsjs.com/",
|
||||
"keywords": [
|
||||
@@ -26,7 +26,7 @@
|
||||
"source-map": "^0.4.4"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"uglify-js": "~2.4"
|
||||
"uglify-js": "^2.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"aws-sdk": "^2.1.49",
|
||||
@@ -54,7 +54,9 @@
|
||||
"mock-stdin": "^0.3.0",
|
||||
"mustache": "^2.1.3",
|
||||
"semver": "^5.0.1",
|
||||
"underscore": "^1.5.1"
|
||||
"underscore": "^1.5.1",
|
||||
"webpack": "^1.12.6",
|
||||
"webpack-dev-server": "^1.12.1"
|
||||
},
|
||||
"main": "lib/index.js",
|
||||
"bin": {
|
||||
|
||||
@@ -16,7 +16,6 @@ var template = Handlebars.precompile(script, {
|
||||
assumeObjects: true,
|
||||
compat: false,
|
||||
strict: true,
|
||||
trackIds: true,
|
||||
knownHelpersOnly: false
|
||||
});
|
||||
|
||||
|
||||
+13
-1
@@ -2,7 +2,19 @@
|
||||
|
||||
## Development
|
||||
|
||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.4...master)
|
||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.5...master)
|
||||
|
||||
## v4.0.5 - November 19th, 2015
|
||||
- [#1132](https://github.com/wycats/handlebars.js/pull/1132) - Update uglify-js to avoid vulnerability ([@plynchnlm](https://api.github.com/users/plynchnlm))
|
||||
- [#1129](https://github.com/wycats/handlebars.js/issues/1129) - Minified lib returns an empty string ([@bricss](https://api.github.com/users/bricss))
|
||||
- Return current handlebars instance from noConflict - 685cf92
|
||||
- Add webpack to dev dependency to support npm 3 - 7a6c228
|
||||
- Further relax uglify dependency - 0a3b3c2
|
||||
- Include tests for minimized artifacts - c21118d
|
||||
- Fix lint errors under latest eslint - 9f59de9
|
||||
- Add print-script helper script - 98a6717
|
||||
|
||||
[Commits](https://github.com/wycats/handlebars.js/compare/v4.0.4...v4.0.5)
|
||||
|
||||
## v4.0.4 - October 29th, 2015
|
||||
- [#1121](https://github.com/wycats/handlebars.js/pull/1121) - Include partial name in 'undefined partial' exception message ([@shinypb](https://api.github.com/users/shinypb))
|
||||
|
||||
Vendored
+6
-1
@@ -4,7 +4,12 @@ var fs = require('fs'),
|
||||
vm = require('vm');
|
||||
|
||||
global.Handlebars = 'no-conflict';
|
||||
vm.runInThisContext(fs.readFileSync(__dirname + '/../../dist/handlebars.js'), 'dist/handlebars.js');
|
||||
|
||||
var filename = 'dist/handlebars.js';
|
||||
if (global.minimizedTest) {
|
||||
filename = 'dist/handlebars.min.js';
|
||||
}
|
||||
vm.runInThisContext(fs.readFileSync(__dirname + '/../../' + filename), filename);
|
||||
|
||||
global.CompilerContext = {
|
||||
browser: true,
|
||||
|
||||
Vendored
+20
-4
@@ -7,19 +7,35 @@ var errors = 0,
|
||||
testDir = path.dirname(__dirname),
|
||||
grep = process.argv[2];
|
||||
|
||||
// Lazy hack, but whatever
|
||||
if (grep === '--min') {
|
||||
global.minimizedTest = true;
|
||||
grep = undefined;
|
||||
}
|
||||
|
||||
var files = fs.readdirSync(testDir)
|
||||
.filter(function(name) { return (/.*\.js$/).test(name); })
|
||||
.map(function(name) { return testDir + '/' + name; });
|
||||
|
||||
run('./runtime', function() {
|
||||
run('./browser', function() {
|
||||
run('./node', function() {
|
||||
if (global.minimizedTest) {
|
||||
run('./runtime', function() {
|
||||
run('./browser', function() {
|
||||
/* eslint-disable no-process-exit */
|
||||
process.exit(errors);
|
||||
/* eslint-enable no-process-exit */
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
run('./runtime', function() {
|
||||
run('./browser', function() {
|
||||
run('./node', function() {
|
||||
/* eslint-disable no-process-exit */
|
||||
process.exit(errors);
|
||||
/* eslint-enable no-process-exit */
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function run(env, callback) {
|
||||
|
||||
Vendored
+6
-1
@@ -4,7 +4,12 @@ var fs = require('fs'),
|
||||
vm = require('vm');
|
||||
|
||||
global.Handlebars = 'no-conflict';
|
||||
vm.runInThisContext(fs.readFileSync(__dirname + '/../../dist/handlebars.runtime.js'), 'dist/handlebars.runtime.js');
|
||||
|
||||
var filename = 'dist/handlebars.runtime.js';
|
||||
if (global.minimizedTest) {
|
||||
filename = 'dist/handlebars.runtime.min.js';
|
||||
}
|
||||
vm.runInThisContext(fs.readFileSync(__dirname + '/../../' + filename), filename);
|
||||
|
||||
var parse = require('../../dist/cjs/handlebars/compiler/base').parse;
|
||||
var compiler = require('../../dist/cjs/handlebars/compiler/compiler');
|
||||
|
||||
@@ -247,4 +247,25 @@ describe('Regressions', function() {
|
||||
};
|
||||
shouldCompileToWithPartials(string, [{}, {}, partials], true, 'Outer');
|
||||
});
|
||||
|
||||
it('GH-1135 : Context handling within each iteration', function() {
|
||||
var obj = {array: [1], name: 'John'};
|
||||
var helpers = {
|
||||
myif: function(conditional, options) {
|
||||
if (conditional) {
|
||||
return options.fn(this);
|
||||
} else {
|
||||
return options.inverse(this);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
shouldCompileTo(
|
||||
'{{#each array}}\n'
|
||||
+ ' 1. IF: {{#if true}}{{../name}}-{{../../name}}-{{../../../name}}{{/if}}\n'
|
||||
+ ' 2. MYIF: {{#myif true}}{{../name}}={{../../name}}={{../../../name}}{{/myif}}\n'
|
||||
+ '{{/each}}', [obj, helpers],
|
||||
' 1. IF: John--\n'
|
||||
+ ' 2. MYIF: John==\n');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -32,43 +32,6 @@ describe('runtime', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('#child', function() {
|
||||
if (!Handlebars.compile) {
|
||||
return;
|
||||
}
|
||||
|
||||
it('should throw for depthed methods without depths', function() {
|
||||
shouldThrow(function() {
|
||||
var template = Handlebars.compile('{{#foo}}{{../bar}}{{/foo}}');
|
||||
// Calling twice to hit the non-compiled case.
|
||||
template._setup({});
|
||||
template._setup({});
|
||||
template._child(1);
|
||||
}, Error, 'must pass parent depths');
|
||||
});
|
||||
|
||||
it('should throw for block param methods without params', function() {
|
||||
shouldThrow(function() {
|
||||
var template = Handlebars.compile('{{#foo as |foo|}}{{foo}}{{/foo}}');
|
||||
// Calling twice to hit the non-compiled case.
|
||||
template._setup({});
|
||||
template._setup({});
|
||||
template._child(1);
|
||||
}, Error, 'must pass block params');
|
||||
});
|
||||
it('should expose child template', function() {
|
||||
var template = Handlebars.compile('{{#foo}}bar{{/foo}}');
|
||||
// Calling twice to hit the non-compiled case.
|
||||
equal(template._child(1)(), 'bar');
|
||||
equal(template._child(1)(), 'bar');
|
||||
});
|
||||
it('should render depthed content', function() {
|
||||
var template = Handlebars.compile('{{#foo}}{{../bar}}{{/foo}}');
|
||||
// Calling twice to hit the non-compiled case.
|
||||
equal(template._child(1, undefined, [], [{bar: 'baz'}])(), 'baz');
|
||||
});
|
||||
});
|
||||
|
||||
describe('#noConflict', function() {
|
||||
if (!CompilerContext.browser) {
|
||||
return;
|
||||
|
||||
@@ -1,176 +0,0 @@
|
||||
describe('string params mode', function() {
|
||||
it('arguments to helpers can be retrieved from options hash in string form', function() {
|
||||
var template = CompilerContext.compile('{{wycats is.a slave.driver}}', {stringParams: true});
|
||||
|
||||
var helpers = {
|
||||
wycats: function(passiveVoice, noun) {
|
||||
return 'HELP ME MY BOSS ' + passiveVoice + ' ' + noun;
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({}, {helpers: helpers});
|
||||
|
||||
equals(result, 'HELP ME MY BOSS is.a slave.driver', 'String parameters output');
|
||||
});
|
||||
|
||||
it('when using block form, arguments to helpers can be retrieved from options hash in string form', function() {
|
||||
var template = CompilerContext.compile('{{#wycats is.a slave.driver}}help :({{/wycats}}', {stringParams: true});
|
||||
|
||||
var helpers = {
|
||||
wycats: function(passiveVoice, noun, options) {
|
||||
return 'HELP ME MY BOSS ' + passiveVoice + ' ' +
|
||||
noun + ': ' + options.fn(this);
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({}, {helpers: helpers});
|
||||
|
||||
equals(result, 'HELP ME MY BOSS is.a slave.driver: help :(', 'String parameters output');
|
||||
});
|
||||
|
||||
it('when inside a block in String mode, .. passes the appropriate context in the options hash', function() {
|
||||
var template = CompilerContext.compile('{{#with dale}}{{tomdale ../need dad.joke}}{{/with}}', {stringParams: true});
|
||||
|
||||
var helpers = {
|
||||
tomdale: function(desire, noun, options) {
|
||||
return 'STOP ME FROM READING HACKER NEWS I ' +
|
||||
options.contexts[0][desire] + ' ' + noun;
|
||||
},
|
||||
|
||||
'with': function(context, options) {
|
||||
return options.fn(options.contexts[0][context]);
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({
|
||||
dale: {},
|
||||
|
||||
need: 'need-a'
|
||||
}, {helpers: helpers});
|
||||
|
||||
equals(result, 'STOP ME FROM READING HACKER NEWS I need-a dad.joke', 'Proper context variable output');
|
||||
});
|
||||
|
||||
it('information about the types is passed along', function() {
|
||||
var template = CompilerContext.compile("{{tomdale 'need' dad.joke true false}}", { stringParams: true });
|
||||
|
||||
var helpers = {
|
||||
tomdale: function(desire, noun, trueBool, falseBool, options) {
|
||||
equal(options.types[0], 'StringLiteral', 'the string type is passed');
|
||||
equal(options.types[1], 'PathExpression', 'the expression type is passed');
|
||||
equal(options.types[2], 'BooleanLiteral', 'the expression type is passed');
|
||||
equal(desire, 'need', 'the string form is passed for strings');
|
||||
equal(noun, 'dad.joke', 'the string form is passed for expressions');
|
||||
equal(trueBool, true, 'raw booleans are passed through');
|
||||
equal(falseBool, false, 'raw booleans are passed through');
|
||||
return 'Helper called';
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({}, { helpers: helpers });
|
||||
equal(result, 'Helper called');
|
||||
});
|
||||
|
||||
it('hash parameters get type information', function() {
|
||||
var template = CompilerContext.compile("{{tomdale he.says desire='need' noun=dad.joke bool=true}}", { stringParams: true });
|
||||
|
||||
var helpers = {
|
||||
tomdale: function(exclamation, options) {
|
||||
equal(exclamation, 'he.says');
|
||||
equal(options.types[0], 'PathExpression');
|
||||
|
||||
equal(options.hashTypes.desire, 'StringLiteral');
|
||||
equal(options.hashTypes.noun, 'PathExpression');
|
||||
equal(options.hashTypes.bool, 'BooleanLiteral');
|
||||
equal(options.hash.desire, 'need');
|
||||
equal(options.hash.noun, 'dad.joke');
|
||||
equal(options.hash.bool, true);
|
||||
return 'Helper called';
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({}, { helpers: helpers });
|
||||
equal(result, 'Helper called');
|
||||
});
|
||||
|
||||
it('hash parameters get context information', function() {
|
||||
var template = CompilerContext.compile("{{#with dale}}{{tomdale he.says desire='need' noun=../dad/joke bool=true}}{{/with}}", { stringParams: true });
|
||||
|
||||
var context = {dale: {}};
|
||||
|
||||
var helpers = {
|
||||
tomdale: function(exclamation, options) {
|
||||
equal(exclamation, 'he.says');
|
||||
equal(options.types[0], 'PathExpression');
|
||||
|
||||
equal(options.contexts.length, 1);
|
||||
equal(options.hashContexts.noun, context);
|
||||
equal(options.hash.desire, 'need');
|
||||
equal(options.hash.noun, 'dad.joke');
|
||||
equal(options.hash.bool, true);
|
||||
return 'Helper called';
|
||||
},
|
||||
'with': function(withContext, options) {
|
||||
return options.fn(options.contexts[0][withContext]);
|
||||
}
|
||||
};
|
||||
|
||||
var result = template(context, { helpers: helpers });
|
||||
equal(result, 'Helper called');
|
||||
});
|
||||
|
||||
it('when inside a block in String mode, .. passes the appropriate context in the options hash to a block helper', function() {
|
||||
var template = CompilerContext.compile('{{#with dale}}{{#tomdale ../need dad.joke}}wot{{/tomdale}}{{/with}}', {stringParams: true});
|
||||
|
||||
var helpers = {
|
||||
tomdale: function(desire, noun, options) {
|
||||
return 'STOP ME FROM READING HACKER NEWS I ' +
|
||||
options.contexts[0][desire] + ' ' + noun + ' ' +
|
||||
options.fn(this);
|
||||
},
|
||||
|
||||
'with': function(context, options) {
|
||||
return options.fn(options.contexts[0][context]);
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({
|
||||
dale: {},
|
||||
|
||||
need: 'need-a'
|
||||
}, {helpers: helpers});
|
||||
|
||||
equals(result, 'STOP ME FROM READING HACKER NEWS I need-a dad.joke wot', 'Proper context variable output');
|
||||
});
|
||||
|
||||
it('with nested block ambiguous', function() {
|
||||
var template = CompilerContext.compile('{{#with content}}{{#view}}{{firstName}} {{lastName}}{{/view}}{{/with}}', {stringParams: true});
|
||||
|
||||
var helpers = {
|
||||
'with': function() {
|
||||
return 'WITH';
|
||||
},
|
||||
view: function() {
|
||||
return 'VIEW';
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({}, {helpers: helpers});
|
||||
equals(result, 'WITH');
|
||||
});
|
||||
|
||||
it('should handle DATA', function() {
|
||||
var template = CompilerContext.compile('{{foo @bar}}', { stringParams: true });
|
||||
|
||||
var helpers = {
|
||||
foo: function(bar, options) {
|
||||
equal(bar, '@bar');
|
||||
equal(options.types[0], 'PathExpression');
|
||||
return 'Foo!';
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({}, { helpers: helpers });
|
||||
equal(result, 'Foo!');
|
||||
});
|
||||
});
|
||||
@@ -162,50 +162,6 @@ describe('subexpressions', function() {
|
||||
shouldCompileTo(string, [context, helpers], '<input aria-label="Name" placeholder="Example User" />');
|
||||
});
|
||||
|
||||
it('in string params mode,', function() {
|
||||
var template = CompilerContext.compile('{{snog (blorg foo x=y) yeah a=b}}', {stringParams: true});
|
||||
|
||||
var helpers = {
|
||||
snog: function(a, b, options) {
|
||||
equals(a, 'foo');
|
||||
equals(options.types.length, 2, 'string params for outer helper processed correctly');
|
||||
equals(options.types[0], 'SubExpression', 'string params for outer helper processed correctly');
|
||||
equals(options.types[1], 'PathExpression', 'string params for outer helper processed correctly');
|
||||
return a + b;
|
||||
},
|
||||
|
||||
blorg: function(a, options) {
|
||||
equals(options.types.length, 1, 'string params for inner helper processed correctly');
|
||||
equals(options.types[0], 'PathExpression', 'string params for inner helper processed correctly');
|
||||
return a;
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({
|
||||
foo: {},
|
||||
yeah: {}
|
||||
}, {helpers: helpers});
|
||||
|
||||
equals(result, 'fooyeah');
|
||||
});
|
||||
|
||||
it('as hashes in string params mode', function() {
|
||||
var template = CompilerContext.compile('{{blog fun=(bork)}}', {stringParams: true});
|
||||
|
||||
var helpers = {
|
||||
blog: function(options) {
|
||||
equals(options.hashTypes.fun, 'SubExpression');
|
||||
return 'val is ' + options.hash.fun;
|
||||
},
|
||||
bork: function() {
|
||||
return 'BORK';
|
||||
}
|
||||
};
|
||||
|
||||
var result = template({}, {helpers: helpers});
|
||||
equals(result, 'val is BORK');
|
||||
});
|
||||
|
||||
it('subexpression functions on the context', function() {
|
||||
var string = '{{foo (bar)}}!';
|
||||
var context = {
|
||||
|
||||
@@ -1,237 +0,0 @@
|
||||
describe('track ids', function() {
|
||||
var context;
|
||||
beforeEach(function() {
|
||||
context = {is: {a: 'foo'}, slave: {driver: 'bar'}};
|
||||
});
|
||||
|
||||
it('should not include anything without the flag', function() {
|
||||
var template = CompilerContext.compile('{{wycats is.a slave.driver}}');
|
||||
|
||||
var helpers = {
|
||||
wycats: function(passiveVoice, noun, options) {
|
||||
equal(options.ids, undefined);
|
||||
equal(options.hashIds, undefined);
|
||||
|
||||
return 'success';
|
||||
}
|
||||
};
|
||||
|
||||
equals(template({}, {helpers: helpers}), 'success');
|
||||
});
|
||||
it('should include argument ids', function() {
|
||||
var template = CompilerContext.compile('{{wycats is.a slave.driver}}', {trackIds: true});
|
||||
|
||||
var helpers = {
|
||||
wycats: function(passiveVoice, noun, options) {
|
||||
equal(options.ids[0], 'is.a');
|
||||
equal(options.ids[1], 'slave.driver');
|
||||
|
||||
return 'HELP ME MY BOSS ' + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun;
|
||||
}
|
||||
};
|
||||
|
||||
equals(template(context, {helpers: helpers}), 'HELP ME MY BOSS is.a:foo slave.driver:bar');
|
||||
});
|
||||
it('should include hash ids', function() {
|
||||
var template = CompilerContext.compile('{{wycats bat=is.a baz=slave.driver}}', {trackIds: true});
|
||||
|
||||
var helpers = {
|
||||
wycats: function(options) {
|
||||
equal(options.hashIds.bat, 'is.a');
|
||||
equal(options.hashIds.baz, 'slave.driver');
|
||||
|
||||
return 'HELP ME MY BOSS ' + options.hashIds.bat + ':' + options.hash.bat + ' ' + options.hashIds.baz + ':' + options.hash.baz;
|
||||
}
|
||||
};
|
||||
|
||||
equals(template(context, {helpers: helpers}), 'HELP ME MY BOSS is.a:foo slave.driver:bar');
|
||||
});
|
||||
it('should note ../ and ./ references', function() {
|
||||
var template = CompilerContext.compile('{{wycats ./is.a ../slave.driver this.is.a this}}', {trackIds: true});
|
||||
|
||||
var helpers = {
|
||||
wycats: function(passiveVoice, noun, thiz, thiz2, options) {
|
||||
equal(options.ids[0], 'is.a');
|
||||
equal(options.ids[1], '../slave.driver');
|
||||
equal(options.ids[2], 'is.a');
|
||||
equal(options.ids[3], '');
|
||||
|
||||
return 'HELP ME MY BOSS ' + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun;
|
||||
}
|
||||
};
|
||||
|
||||
equals(template(context, {helpers: helpers}), 'HELP ME MY BOSS is.a:foo ../slave.driver:undefined');
|
||||
});
|
||||
it('should note @data references', function() {
|
||||
var template = CompilerContext.compile('{{wycats @is.a @slave.driver}}', {trackIds: true});
|
||||
|
||||
var helpers = {
|
||||
wycats: function(passiveVoice, noun, options) {
|
||||
equal(options.ids[0], '@is.a');
|
||||
equal(options.ids[1], '@slave.driver');
|
||||
|
||||
return 'HELP ME MY BOSS ' + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun;
|
||||
}
|
||||
};
|
||||
|
||||
equals(template({}, {helpers: helpers, data: context}), 'HELP ME MY BOSS @is.a:foo @slave.driver:bar');
|
||||
});
|
||||
|
||||
it('should return null for constants', function() {
|
||||
var template = CompilerContext.compile('{{wycats 1 "foo" key=false}}', {trackIds: true});
|
||||
|
||||
var helpers = {
|
||||
wycats: function(passiveVoice, noun, options) {
|
||||
equal(options.ids[0], null);
|
||||
equal(options.ids[1], null);
|
||||
equal(options.hashIds.key, null);
|
||||
|
||||
return 'HELP ME MY BOSS ' + passiveVoice + ' ' + noun + ' ' + options.hash.key;
|
||||
}
|
||||
};
|
||||
|
||||
equals(template(context, {helpers: helpers}), 'HELP ME MY BOSS 1 foo false');
|
||||
});
|
||||
it('should return true for subexpressions', function() {
|
||||
var template = CompilerContext.compile('{{wycats (sub)}}', {trackIds: true});
|
||||
|
||||
var helpers = {
|
||||
sub: function() { return 1; },
|
||||
wycats: function(passiveVoice, options) {
|
||||
equal(options.ids[0], true);
|
||||
|
||||
return 'HELP ME MY BOSS ' + passiveVoice;
|
||||
}
|
||||
};
|
||||
|
||||
equals(template(context, {helpers: helpers}), 'HELP ME MY BOSS 1');
|
||||
});
|
||||
|
||||
it('should use block param paths', function() {
|
||||
var template = CompilerContext.compile('{{#doIt as |is|}}{{wycats is.a slave.driver is}}{{/doIt}}', {trackIds: true});
|
||||
|
||||
var helpers = {
|
||||
doIt: function(options) {
|
||||
var blockParams = [this.is];
|
||||
blockParams.path = ['zomg'];
|
||||
return options.fn(this, {blockParams: blockParams});
|
||||
},
|
||||
wycats: function(passiveVoice, noun, blah, options) {
|
||||
equal(options.ids[0], 'zomg.a');
|
||||
equal(options.ids[1], 'slave.driver');
|
||||
equal(options.ids[2], 'zomg');
|
||||
|
||||
return 'HELP ME MY BOSS ' + options.ids[0] + ':' + passiveVoice + ' ' + options.ids[1] + ':' + noun;
|
||||
}
|
||||
};
|
||||
|
||||
equals(template(context, {helpers: helpers}), 'HELP ME MY BOSS zomg.a:foo slave.driver:bar');
|
||||
});
|
||||
|
||||
describe('builtin helpers', function() {
|
||||
var helpers = {
|
||||
blockParams: function(name, options) {
|
||||
return name + ':' + options.ids[0] + '\n';
|
||||
},
|
||||
wycats: function(name, options) {
|
||||
return name + ':' + options.data.contextPath + '\n';
|
||||
}
|
||||
};
|
||||
|
||||
describe('#each', function() {
|
||||
it('should track contextPath for arrays', function() {
|
||||
var template = CompilerContext.compile('{{#each array}}{{wycats name}}{{/each}}', {trackIds: true});
|
||||
|
||||
equals(template({array: [{name: 'foo'}, {name: 'bar'}]}, {helpers: helpers}), 'foo:array.0\nbar:array.1\n');
|
||||
});
|
||||
it('should track contextPath for keys', function() {
|
||||
var template = CompilerContext.compile('{{#each object}}{{wycats name}}{{/each}}', {trackIds: true});
|
||||
|
||||
equals(template({object: {foo: {name: 'foo'}, bar: {name: 'bar'}}}, {helpers: helpers}), 'foo:object.foo\nbar:object.bar\n');
|
||||
});
|
||||
it('should handle nesting', function() {
|
||||
var template = CompilerContext.compile('{{#each .}}{{#each .}}{{wycats name}}{{/each}}{{/each}}', {trackIds: true});
|
||||
|
||||
equals(template({array: [{name: 'foo'}, {name: 'bar'}]}, {helpers: helpers}), 'foo:.array..0\nbar:.array..1\n');
|
||||
});
|
||||
it('should handle block params', function() {
|
||||
var template = CompilerContext.compile('{{#each array as |value|}}{{blockParams value.name}}{{/each}}', {trackIds: true});
|
||||
|
||||
equals(template({array: [{name: 'foo'}, {name: 'bar'}]}, {helpers: helpers}), 'foo:array.0.name\nbar:array.1.name\n');
|
||||
});
|
||||
});
|
||||
describe('#with', function() {
|
||||
it('should track contextPath', function() {
|
||||
var template = CompilerContext.compile('{{#with field}}{{wycats name}}{{/with}}', {trackIds: true});
|
||||
|
||||
equals(template({field: {name: 'foo'}}, {helpers: helpers}), 'foo:field\n');
|
||||
});
|
||||
it('should handle nesting', function() {
|
||||
var template = CompilerContext.compile('{{#with bat}}{{#with field}}{{wycats name}}{{/with}}{{/with}}', {trackIds: true});
|
||||
|
||||
equals(template({bat: {field: {name: 'foo'}}}, {helpers: helpers}), 'foo:bat.field\n');
|
||||
});
|
||||
});
|
||||
describe('#blockHelperMissing', function() {
|
||||
it('should track contextPath for arrays', function() {
|
||||
var template = CompilerContext.compile('{{#field}}{{wycats name}}{{/field}}', {trackIds: true});
|
||||
|
||||
equals(template({field: [{name: 'foo'}]}, {helpers: helpers}), 'foo:field.0\n');
|
||||
});
|
||||
it('should track contextPath for keys', function() {
|
||||
var template = CompilerContext.compile('{{#field}}{{wycats name}}{{/field}}', {trackIds: true});
|
||||
|
||||
equals(template({field: {name: 'foo'}}, {helpers: helpers}), 'foo:field\n');
|
||||
});
|
||||
it('should handle nesting', function() {
|
||||
var template = CompilerContext.compile('{{#bat}}{{#field}}{{wycats name}}{{/field}}{{/bat}}', {trackIds: true});
|
||||
|
||||
equals(template({bat: {field: {name: 'foo'}}}, {helpers: helpers}), 'foo:bat.field\n');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('partials', function() {
|
||||
var helpers = {
|
||||
blockParams: function(name, options) {
|
||||
return name + ':' + options.ids[0] + '\n';
|
||||
},
|
||||
wycats: function(name, options) {
|
||||
return name + ':' + options.data.contextPath + '\n';
|
||||
}
|
||||
};
|
||||
|
||||
it('should pass track id for basic partial', function() {
|
||||
var template = CompilerContext.compile('Dudes: {{#dudes}}{{> dude}}{{/dudes}}', {trackIds: true}),
|
||||
hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
|
||||
|
||||
var partials = {
|
||||
dude: CompilerContext.compile('{{wycats name}}', {trackIds: true})
|
||||
};
|
||||
|
||||
equals(template(hash, {helpers: helpers, partials: partials}), 'Dudes: Yehuda:dudes.0\nAlan:dudes.1\n');
|
||||
});
|
||||
|
||||
it('should pass track id for context partial', function() {
|
||||
var template = CompilerContext.compile('Dudes: {{> dude dudes}}', {trackIds: true}),
|
||||
hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
|
||||
|
||||
var partials = {
|
||||
dude: CompilerContext.compile('{{#each this}}{{wycats name}}{{/each}}', {trackIds: true})
|
||||
};
|
||||
|
||||
equals(template(hash, {helpers: helpers, partials: partials}), 'Dudes: Yehuda:dudes..0\nAlan:dudes..1\n');
|
||||
});
|
||||
|
||||
it('should invalidate context for partials with parameters', function() {
|
||||
var template = CompilerContext.compile('Dudes: {{#dudes}}{{> dude . bar="foo"}}{{/dudes}}', {trackIds: true}),
|
||||
hash = {dudes: [{name: 'Yehuda', url: 'http://yehuda'}, {name: 'Alan', url: 'http://alan'}]};
|
||||
|
||||
var partials = {
|
||||
dude: CompilerContext.compile('{{wycats name}}', {trackIds: true})
|
||||
};
|
||||
|
||||
equals(template(hash, {helpers: helpers, partials: partials}), 'Dudes: Yehuda:true\nAlan:true\n');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -40,6 +40,17 @@ module.exports = function(grunt) {
|
||||
done();
|
||||
});
|
||||
});
|
||||
grunt.registerTask('test:min', function() {
|
||||
var done = this.async();
|
||||
|
||||
var runner = childProcess.fork('./spec/env/runner', ['--min'], {stdio: 'inherit'});
|
||||
runner.on('close', function(code) {
|
||||
if (code != 0) {
|
||||
grunt.fatal(code + ' tests failed');
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
grunt.registerTask('test:check-cov', function() {
|
||||
var done = this.async();
|
||||
|
||||
Reference in New Issue
Block a user