UNPKG

derby-parsing

Version:
748 lines (680 loc) 26.8 kB
var expect = require('expect.js'); var derbyTemplates = require('derby-templates'); var contexts = derbyTemplates.contexts; var expressions = derbyTemplates.expressions; var templates = derbyTemplates.templates; var parsing = require('../lib/index'); var createExpression = parsing.createExpression; var createTemplate = parsing.createTemplate; var controller = { plus: function(a, b) { return a + b; } , minus: function(a, b) { return a - b; } , greeting: function() { return 'Hi.'; } , keys: function(object) { var keys = []; for (var key in object) { keys.push(key); } return keys; } , passThrough: function(value) { return value; } , informal: { greeting: function() { return 'Yo!'; } } , Date: Date , global: global }; controller.model = { data: { key: 'green' , lightTemplate: createTemplate('light {{_page.colors[key].name}}') , _page: { colors: { green: { name: 'Green' , hex: '#0f0' , rgb: [0, 255, 0] , light: { hex: '#90ee90' } , dark: { hex: '#006400' } } } , key: 'green' , channel: 0 , variation: 'light' , variationHex: 'light.hex' , keys: ['red', 'green'] , index: 1 , tagName: 'div' , html: '<div>Hi</div>' , nums: [2, 11, 3, 7] , first: 2 , second: 3 , year: 2018 , date: new Date(1000) } } }; controller.model.scope = function(path) { return { _at: path , path: function() { return this._at; } }; }; var views = new templates.Views(); var contextMeta = new contexts.ContextMeta({views: views}); var context = new contexts.Context(contextMeta, controller); var view = new templates.View(); function stripContexts(dependencies) { if (!dependencies) return dependencies; for (var i = 0; i < dependencies.length; i++) { var dependency = dependencies[i]; for (var j = 0; j < dependency.length; j++) { var segment = dependency[j]; if (segment instanceof contexts.Context) { dependency[j] = {item: segment.item}; } } } return dependencies; } describe('template dependencies', function() { describe('text', function() { it('gets dependencies', function() { var template = createTemplate('Hi'); expect(template.dependencies(context)).to.be.null; expect(template.get(context)).to.equal('Hi'); }); }); describe('dynamic text', function() { it('gets dependencies', function() { var template = createTemplate('{{_page.key}}'); expect(template.dependencies(context)).to.eql([['_page', 'key']]); expect(template.get(context)).to.equal('green'); }); }); describe('with block', function() { it('gets dependencies', function() { var template = createTemplate( '{{with _page.key as #key}}' + '{{_page.colors[#key].name}}' + '{{/with}}'); expect(template.dependencies(context)).to.eql([ ['_page', 'key'], ['_page', 'colors', 'green', 'name'] ]); expect(template.get(context)).to.equal('Green'); }); }); describe('on block', function() { it('gets dependencies', function() { var template = createTemplate( '{{on _page.key}}' + '{{_page.variation}}' + '{{/on}}'); expect(template.dependencies(context)).to.eql([ ['_page', 'key'], ['_page', 'variation'] ]); expect(template.get(context)).to.equal('light'); }); }); describe('each block', function() { it('gets item alias dependencies', function() { var template = createTemplate( '{{each _page.keys as #key}}' + '{{#key}}' + '{{/each}}'); expect(stripContexts(template.dependencies(context))).to.eql([ ['_page', 'keys'], ['_page', 'keys', {item: 0}], ['_page', 'keys', {item: 1}] ]); expect(template.get(context)).to.equal('redgreen'); }); it('gets index alias dependencies', function() { var template = createTemplate( '{{each _page.keys as #key, #i}}' + '{{#i}}.' + '{{/each}}'); expect(stripContexts(template.dependencies(context))).to.eql([ ['_page', 'keys'], ['_page', 'keys'], ['_page', 'keys'], ]); expect(template.get(context)).to.equal('0.1.'); }); it('gets alias dependencies from a literal', function() { var template = createTemplate( '{{each [33, 77] as #key, #i}}' + '{{#i}},{{#key}};' + '{{/each}}'); expect(stripContexts(template.dependencies(context))).to.be.null; expect(template.get(context)).to.equal('0,33;1,77;'); }); }); describe('HTML', function() { it('gets empty Template dependencies', function() { var template = createTemplate(''); expect(template.dependencies(context)).to.be.null; expect(template.get(context)).to.equal(''); }); it('gets Doctype dependencies', function() { var template = createTemplate('<!DOCTYPE html>'); expect(template.dependencies(context)).to.be.null; expect(template.get(context)).to.equal('<!DOCTYPE html>'); }); it('gets Text dependencies', function() { var template = createTemplate('Hi!'); expect(template.dependencies(context)).to.be.null; expect(template.get(context)).to.equal('Hi!'); }); it('gets DynamicText dependencies', function() { var template = createTemplate('Choose {{_page.key}}'); expect(template.dependencies(context)).to.eql([ ['_page', 'key'] ]); expect(template.get(context)).to.equal('Choose green'); }); it('gets Comment dependencies', function() { var template = createTemplate('<!--[Copyright 1999]-->'); expect(template.dependencies(context)).to.be.null; expect(template.get(context)).to.equal('<!--[Copyright 1999]-->'); }); it.skip('gets DynamicComment dependencies from parsed template', function() { // Template tag within comment is not parsed. It probably should be, // since we do parse the content of other special regions, such as the // text inside of scripts and styles var template = createTemplate('<!--[Copyright {{_page.year}}]-->'); expect(template.dependencies(context)).to.eql([ ['_page', 'year'] ]); expect(template.get(context)).to.equal('<!--[Copyright 2018]-->'); }); it('gets DynamicComment dependencies', function() { var expression = createExpression('_page.year'); var template = new templates.DynamicComment(expression); expect(template.dependencies(context)).to.eql([ ['_page', 'year'] ]); expect(template.get(context)).to.equal('<!--2018-->'); }); it('gets Html dependencies', function() { // It is not currently possible to create a template of type Html via // derby-parsing, as there is no syntax that would require it var template = new templates.Html('<div>Hi</div>'); expect(template.dependencies(context)).to.be.null; expect(template.get(context)).to.equal('<div>Hi</div>'); }); it('gets DynamicHtml dependencies', function() { var template = createTemplate('{{unescaped _page.html}}'); expect(template.dependencies(context)).to.eql([ ['_page', 'html'] ]); expect(template.get(context)).to.equal('<div>Hi</div>'); }); it('gets Element dependencies', function() { var template = createTemplate('<div>Hi<br>there</div>'); expect(template.dependencies(context)).to.be.null; expect(template.get(context)).to.equal('<div>Hi<br>there</div>'); }); it('gets DynamicElement dependencies', function() { var template = createTemplate('<tag is="{{_page.tagName}}">Hello</tag>'); expect(template.dependencies(context)).to.eql([ ['_page', 'tagName'] ]); expect(template.get(context)).to.equal('<div>Hello</div>'); }); it('gets Attribute dependencies', function() { var template = createTemplate('<img src="foo">'); expect(template.dependencies(context)).to.be.null; expect(template.get(context)).to.equal('<img src="foo">'); }); it('gets DynamicAttribute dependencies', function() { var template = createTemplate('<img src="{{_page.key}}">'); expect(template.dependencies(context)).to.eql([ ['_page', 'key'] ]); expect(template.get(context)).to.equal('<img src="green">'); }); }); }); describe('expression dependencies', function() { describe('literal', function() { it('gets literal dependencies', function() { var expression = createExpression('34'); expect(expression.dependencies(context)).to.be.null; }); }); describe('path', function() { it('gets path dependencies', function() { var expression = createExpression('_page.colors.green.name'); expect(expression.dependencies(context)).to.eql([['_page', 'colors', 'green', 'name']]); }); }); describe('brackets', function() { it('gets bracket + path dependencies', function() { var expression = createExpression('_page.colors[_page.key].name'); expect(expression.dependencies(context)).to.eql([ ['_page', 'key'], ['_page', 'colors', 'green', 'name'] ]); }); it('gets bracket + path + bracket + path dependencies', function() { var expression = createExpression('_page.colors[_page.key].rgb[_page.channel]'); expect(expression.dependencies(context)).to.eql([ ['_page', 'key'], ['_page', 'channel'], ['_page', 'colors', 'green', 'rgb', 0] ]); }); it('gets bracket + bracket + path dependencies', function() { var expression = createExpression('_page.colors[_page.key][_page.variation].hex'); expect(expression.dependencies(context)).to.eql([ ['_page', 'key'], ['_page', 'variation'], ['_page', 'colors', 'green', 'light', 'hex'] ]); }); it('gets nested bracket + path dependencies', function() { var expression = createExpression('_page.colors[_page.keys[_page.index]].name'); expect(expression.dependencies(context)).to.eql([ ['_page', 'index'], ['_page', 'keys', 1], ['_page', 'colors', 'green', 'name'] ]); }); }); describe('fn', function() { it('gets path + path dependencies', function() { var expression = createExpression('plus(_page.nums[0], _page.nums[1])'); expect(expression.dependencies(context)).to.eql([ ['_page', 'nums', 0, '*'], ['_page', 'nums', 1, '*'] ]); }); it('gets path + fn dependencies', function() { var expression = createExpression('plus(_page.nums[0], minus(_page.nums[3], _page.nums[2]))'); expect(expression.dependencies(context)).to.eql([ ['_page', 'nums', 0, '*'], ['_page', 'nums', 3, '*'], ['_page', 'nums', 2, '*'] ]); }); it('gets bracket + bracket dependencies', function() { var expression = createExpression('plus(_page.nums[_page.first], _page.nums[_page.second])'); expect(expression.dependencies(context)).to.eql([ ['_page', 'first'], ['_page', 'nums', 2, '*'], ['_page', 'second'], ['_page', 'nums', 3, '*'] ]); }); it('gets fn inside bracket dependencies', function() { var expression = createExpression('_page.keys[minus(_page.nums[2], _page.nums[0])]'); expect(expression.dependencies(context)).to.eql([ ['_page', 'nums', 2, '*'], ['_page', 'nums', 0, '*'], ['_page', 'keys', 1] ]); }); }); describe('operators', function() { it('gets path + path dependencies', function() { var expression = createExpression('_page.nums[0] + _page.nums[1]'); expect(expression.dependencies(context)).to.eql([ ['_page', 'nums', 0, '*'], ['_page', 'nums', 1, '*'] ]); }); it('gets chained operator dependencies', function() { var expression = createExpression('_page.nums[0] + (_page.nums[3] - _page.nums[2])'); expect(expression.dependencies(context)).to.eql([ ['_page', 'nums', 0, '*'], ['_page', 'nums', 3, '*'], ['_page', 'nums', 2, '*'] ]); }); it('gets bracket + bracket dependencies', function() { var expression = createExpression('_page.nums[_page.first] + _page.nums[_page.second]'); expect(expression.dependencies(context)).to.eql([ ['_page', 'first'], ['_page', 'nums', 2, '*'], ['_page', 'second'], ['_page', 'nums', 3, '*'] ]); }); it('gets operator inside bracket dependencies', function() { var expression = createExpression('_page.keys[_page.nums[2] - _page.nums[0]]'); expect(expression.dependencies(context)).to.eql([ ['_page', 'nums', 2, '*'], ['_page', 'nums', 0, '*'], ['_page', 'keys', 1], ]); }); it('gets path + literal dependencies', function() { var expression = createExpression('_page.nums[0] + 3'); expect(expression.dependencies(context)).to.eql([ ['_page', 'nums', 0, '*'] ]); }); it('gets path + literal + path dependencies', function() { var expression = createExpression('_page.nums[0] + (100 - _page.nums[2])'); expect(expression.dependencies(context)).to.eql([ ['_page', 'nums', 0, '*'], ['_page', 'nums', 2, '*'] ]); }); it('gets path + bracket dependencies', function() { var expression = createExpression('_page.nums[2] + _page.nums[_page.second]'); expect(expression.dependencies(context)).to.eql([ ['_page', 'nums', 2, '*'], ['_page', 'second'], ['_page', 'nums', 3, '*'] ]); }); it('gets path + literal inside bracket dependencies', function() { var expression = createExpression('_page.keys[_page.nums[2] - 2]'); expect(expression.dependencies(context)).to.eql([ ['_page', 'nums', 2, '*'], ['_page', 'keys', 1] ]); }); }); describe('relative paths', function() { describe('with block', function() { it('gets dependencies', function() { var aliasExpression = createExpression('with _page.colors.green'); var blockContext = context.child(aliasExpression); var expression = createExpression('this'); expect(expression.dependencies(blockContext)).to.eql([ ['_page', 'colors', 'green'] ]); expect(expression.get(blockContext).name).to.eql('Green'); }); it('gets subpath dependencies', function() { var aliasExpression = createExpression('with _page.colors.green'); var blockContext = context.child(aliasExpression); var expression = createExpression('this.name'); expect(expression.dependencies(blockContext)).to.eql([ ['_page', 'colors', 'green', 'name'] ]); expect(expression.get(blockContext)).to.eql('Green'); }); it('gets function dependencies', function() { var aliasExpression = createExpression('with passThrough(_page.colors.green)'); var blockContext = context.child(aliasExpression); var expression = createExpression('this'); expect(expression.dependencies(blockContext)).to.eql([ ['_page', 'colors', 'green', '*'] ]); expect(expression.get(blockContext).name).to.eql('Green'); }); it('gets subpath from function dependencies', function() { var aliasExpression = createExpression('with passThrough(_page.colors.green)'); var blockContext = context.child(aliasExpression); var expression = createExpression('this.name'); expect(expression.dependencies(blockContext)).to.eql([ ['_page', 'colors', 'green', '*'] ]); expect(expression.get(blockContext)).to.eql('Green'); }); it('gets template in model dependencies', function() { var aliasExpression = createExpression('with lightTemplate'); var blockContext = context.child(aliasExpression); var expression = createExpression('this'); expect(expression.dependencies(blockContext)).to.eql([ ['key'], ['_page', 'colors', 'green', 'name'], ['lightTemplate'] ]); expect(expression.get(blockContext)).a(templates.Template); }); it('gets subpath from template in model dependencies', function() { // Getting a template returns a string, so this combination is not // likely to be of much use. However, this test is included to clarify // what is expected behavior var aliasExpression = createExpression('with lightTemplate'); var blockContext = context.child(aliasExpression); var expression = createExpression('this.length'); expect(expression.dependencies(blockContext)).to.eql([ ['key'], ['_page', 'colors', 'green', 'name'], ['lightTemplate', 'length'] ]); expect(expression.get(blockContext)).to.eql(11); }); }); }); describe('aliases', function() { describe('with block', function() { it('gets dependencies', function() { var aliasExpression = createExpression('with _page.colors.green as #color'); var blockContext = context.child(aliasExpression); var expression = createExpression('#color'); expect(expression.dependencies(blockContext)).to.eql([ ['_page', 'colors', 'green'] ]); expect(expression.get(blockContext).name).to.eql('Green'); }); it('gets subpath dependencies', function() { var aliasExpression = createExpression('with _page.colors.green as #color'); var blockContext = context.child(aliasExpression); var expression = createExpression('#color.name'); expect(expression.dependencies(blockContext)).to.eql([ ['_page', 'colors', 'green', 'name'] ]); expect(expression.get(blockContext)).to.eql('Green'); }); it('gets function dependencies', function() { var aliasExpression = createExpression('with passThrough(_page.colors.green) as #color'); var blockContext = context.child(aliasExpression); var expression = createExpression('#color'); expect(expression.dependencies(blockContext)).to.eql([ ['_page', 'colors', 'green', '*'] ]); expect(expression.get(blockContext).name).to.eql('Green'); }); it('gets subpath from function dependencies', function() { var aliasExpression = createExpression('with passThrough(_page.colors.green) as #color'); var blockContext = context.child(aliasExpression); var expression = createExpression('#color.name'); expect(expression.dependencies(blockContext)).to.eql([ ['_page', 'colors', 'green', '*'] ]); expect(expression.get(blockContext)).to.eql('Green'); }); it('gets template in model dependencies', function() { var aliasExpression = createExpression('with lightTemplate as #color'); var blockContext = context.child(aliasExpression); var expression = createExpression('#color'); expect(expression.dependencies(blockContext)).to.eql([ ['key'], ['_page', 'colors', 'green', 'name'], ['lightTemplate'] ]); expect(expression.get(blockContext)).a(templates.Template); }); it('gets subpath from template in model dependencies', function() { // Getting a template returns a string, so this combination is not // likely to be of much use. However, this test is included to clarify // what is expected behavior var aliasExpression = createExpression('with lightTemplate as #color'); var blockContext = context.child(aliasExpression); var expression = createExpression('#color.length'); expect(expression.dependencies(blockContext)).to.eql([ ['key'], ['_page', 'colors', 'green', 'name'], ['lightTemplate', 'length'] ]); expect(expression.get(blockContext)).to.eql(11); }); }); describe('each block', function() { it('gets item alias dependencies', function() { var aliasExpression = createExpression('each _page.keys as #key, #index'); var eachContext = context.eachChild(aliasExpression, 0); var expression = createExpression('#key'); expect(expression.dependencies(eachContext)).to.eql([ ['_page', 'keys', eachContext] ]); expect(expression.get(eachContext)).to.eql('red'); }); it('gets subpath from item alias dependencies', function() { var aliasExpression = createExpression('each _page.keys as #key, #index'); var eachContext = context.eachChild(aliasExpression, 0); var expression = createExpression('#key.length'); expect(expression.dependencies(eachContext)).to.eql([ ['_page', 'keys', eachContext, 'length'] ]); expect(expression.get(eachContext)).to.eql(3); }); it('gets key alias dependencies', function() { var aliasExpression = createExpression('each _page.keys as #key, #index'); var eachContext = context.eachChild(aliasExpression, 0); var expression = createExpression('#index'); expect(expression.dependencies(eachContext)).to.eql([ ['_page', 'keys'] ]); expect(expression.get(eachContext)).to.eql(0); }); }); }); describe('view attributes', function() { describe('expression values', function() { it('gets path dependencies', function() { var attributes = { color: createExpression('_page.colors.green') }; var viewContext = context.viewChild(view, attributes); var expression = createExpression('@color'); expect(expression.dependencies(viewContext)).to.eql([ ['_page', 'colors', 'green'] ]); expect(expression.get(viewContext).name).to.eql('Green'); }); it('gets subpath from path dependencies', function() { var attributes = { color: createExpression('_page.colors.green') }; var viewContext = context.viewChild(view, attributes); var expression = createExpression('@color.name'); expect(expression.dependencies(viewContext)).to.eql([ ['_page', 'colors', 'green', 'name'] ]); expect(expression.get(viewContext)).to.eql('Green'); }); it('gets function dependencies', function() { var attributes = { color: createExpression('passThrough(_page.colors.green)') }; var viewContext = context.viewChild(view, attributes); var expression = createExpression('@color'); expect(expression.dependencies(viewContext)).to.eql([ ['_page', 'colors', 'green', '*'] ]); expect(expression.get(viewContext).name).to.eql('Green'); }); it('gets subpath from function dependencies', function() { var attributes = { color: createExpression('passThrough(_page.colors.green)') }; var viewContext = context.viewChild(view, attributes); var expression = createExpression('@color.name'); expect(expression.dependencies(viewContext)).to.eql([ ['_page', 'colors', 'green', '*'] ]); expect(expression.get(viewContext)).to.eql('Green'); }); it('gets bracket dependencies', function() { var attributes = { color: createExpression('_page.colors[key]') }; var viewContext = context.viewChild(view, attributes); var expression = createExpression('@color'); expect(expression.dependencies(viewContext)).to.eql([ ['key'], ['_page', 'colors', 'green'] ]); expect(expression.get(viewContext).name).to.eql('Green'); }); it('gets subpath from bracket dependencies', function() { var attributes = { color: createExpression('_page.colors[key]') }; var viewContext = context.viewChild(view, attributes); var expression = createExpression('@color.name'); expect(expression.dependencies(viewContext)).to.eql([ ['key'], ['_page', 'colors', 'green', 'name'] ]); expect(expression.get(viewContext)).to.eql('Green'); }); }); describe('template values', function() { it('gets function template attribute dependencies', function() { var attributes = { color: createTemplate('light{{_page.colors.green.name}}') }; var viewContext = context.viewChild(view, attributes); var expression = createExpression('@color'); expect(expression.dependencies(viewContext)).to.eql([ ['_page', 'colors', 'green', 'name'] ]); expect(expression.get(viewContext)).a(templates.Template); }); it('gets subpath from function template attribute dependencies', function() { var attributes = { color: createTemplate('light{{_page.colors.green.name}}') }; var viewContext = context.viewChild(view, attributes); var expression = createExpression('@color.length'); expect(expression.dependencies(viewContext)).to.eql([ ['_page', 'colors', 'green', 'name'] ]); expect(expression.get(viewContext)).equal(10); }); it('gets template in model attribute dependencies', function() { var attributes = { color: createExpression('lightTemplate') }; var viewContext = context.viewChild(view, attributes); var expression = createExpression('@color'); expect(expression.dependencies(viewContext)).to.eql([ ['key'], ['_page', 'colors', 'green', 'name'], ['lightTemplate'] ]); expect(expression.get(viewContext)).a(templates.Template); }); it('gets subpath from template in model attribute dependencies', function() { var attributes = { color: createExpression('lightTemplate') }; var viewContext = context.viewChild(view, attributes); var expression = createExpression('@color.length'); expect(expression.dependencies(viewContext)).to.eql([ ['key'], ['_page', 'colors', 'green', 'name'], ['lightTemplate', 'length'] ]); expect(expression.get(viewContext)).equal(11); }); }); }); });