feat: exported Drop interface for #107

Deprecate snake_cased options and APIs, sed #109
This commit is contained in:
harttle
2019-02-28 00:05:08 +08:00
parent b69c3a3203
commit 7bee9fc92d
26 changed files with 227 additions and 179 deletions
+27 -14
View File
@@ -4,25 +4,38 @@ import * as chaiAsPromised from 'chai-as-promised'
use(chaiAsPromised)
class SettingsDrop extends Liquid.Types.Drop {
foo: string = 'FOO'
bar() {
return 'BAR'
}
liquidMethodMissing(key: string) {
return key.toUpperCase()
}
}
describe('drop', function () {
var engine: Liquid
const settings = new SettingsDrop()
let engine: Liquid
beforeEach(function () {
engine = new Liquid()
})
it('should support liquid_method_missing', async function () {
it('should support liquidMethodMissing', async function () {
let i = 0
const src = `{{settings.foo}},{{settings.foo}},{{settings.foo}}`
const ctx = { settings: { liquid_method_missing: () => i++ } }
const html = await engine.parseAndRender(src, ctx)
return expect(html).to.equal('0,1,2')
const src = `{{settings.foo}},{{settings.bar}},{{settings.coo}}`
const html = await engine.parseAndRender(src, { settings })
return expect(html).to.equal('FOO,BAR,COO')
})
it('should test blank strings', async function () {
const src = `
{% unless settings.fp_heading == blank %}
<h1>{{ settings.fp_heading }}</h1>
{% endunless %}`
var ctx = { settings: { fp_heading: '' } }
const html = await engine.parseAndRender(src, ctx)
return expect(html).to.match(/^\s+$/)
describe('BlandDrop', function () {
it('should test blank strings', async function () {
const src = `
{% unless settings.fp_heading == blank %}
<h1>{{ settings.fp_heading }}</h1>
{% endunless %}`
var ctx = { settings: { fp_heading: '' } }
const html = await engine.parseAndRender(src, ctx)
return expect(html).to.match(/^\s+$/)
})
})
})
+7 -12
View File
@@ -9,18 +9,13 @@ describe('.parseAndRender()', function () {
beforeEach(function () {
engine = new Liquid()
strictEngine = new Liquid({
strict_filters: true
strictFilters: true
})
})
it('should stringify object', async function () {
var ctx = { obj: { foo: 'bar' } }
const html = await engine.parseAndRender('{{obj}}', ctx)
return expect(html).to.equal('{"foo":"bar"}')
})
it('should stringify array ', async function () {
var ctx = { arr: [-2, 'a'] }
const html = await engine.parseAndRender('{{arr}}', ctx)
return expect(html).to.equal('[-2,"a"]')
return expect(html).to.equal('-2,a')
})
it('should render undefined as empty', async function () {
const html = await engine.parseAndRender('foo{{zzz}}bar', {})
@@ -30,7 +25,7 @@ describe('.parseAndRender()', function () {
const html = await engine.parseAndRender('{{"foo" | filter1}}', {})
return expect(html).to.equal('foo')
})
it('should throw upon undefined filter when strict_filters set', function () {
it('should throw upon undefined filter when strictFilters set', function () {
return expect(strictEngine.parseAndRender('{{"foo" | filter1}}', {})).to
.be.rejectedWith(/undefined filter: filter1/)
})
@@ -42,13 +37,13 @@ describe('.parseAndRender()', function () {
engine.parse('<html><head>{{obj}}</head></html>')
}).to.not.throw()
})
it('should render template multiple times', async function () {
const ctx = { obj: { foo: 'bar' } }
it('template should be able to be rendered multiple times', async function () {
const ctx = { obj: [1, 2] }
const template = engine.parse('{{obj}}')
const result = await engine.render(template, ctx)
expect(result).to.equal('{"foo":"bar"}')
expect(result).to.equal('1,2')
const result2 = await engine.render(template, ctx)
expect(result2).to.equal('{"foo":"bar"}')
expect(result2).to.equal('1,2')
})
it('should render filters', async function () {
var ctx = { names: ['alice', 'bob'] }
+1 -1
View File
@@ -19,7 +19,7 @@ describe('filters/array', function () {
return test(src, 'tiger')
})
it('should support map', function () {
return test('{{posts | map: "category"}}', '["foo","bar"]')
return test('{{posts | map: "category"}}', 'foo,bar')
})
it('should support reverse', function () {
return test('{{ "Ground control to Major Tom." | split: "" | reverse | join: "" }}',
+1 -1
View File
@@ -15,6 +15,6 @@ describe('filters/date', function () {
return test('{{ "foo" | date: "%Y"}}', 'foo')
})
it('should render object as string if not valid', function () {
return test('{{ obj | date: "%Y"}}', '{"foo":"bar"}')
return test('{{ obj | date: "%Y"}}', '[object Object]')
})
})
+1 -1
View File
@@ -31,7 +31,7 @@ describe('tags/assign', function () {
it('should assign as array', async function () {
const src = '{% assign foo=(1..3) %}{{foo}}'
const html = await liquid.parseAndRender(src)
return expect(html).to.equal('[1,2,3]')
return expect(html).to.equal('1,2,3')
})
it('should assign as filter result', async function () {
const src = '{% assign foo="a b" | capitalize | split: " " | first %}{{foo}}'
+35
View File
@@ -0,0 +1,35 @@
import { expect } from 'chai'
import Liquid from '../../../src/liquid'
describe('drop/drop', function () {
let liquid: Liquid
before(() => (liquid = new Liquid()))
class CustomDrop extends Liquid.Types.Drop {
name: string = 'NAME'
getName() {
return 'GETNAME'
}
}
class CustomDropWithMethodMissing extends CustomDrop {
liquidMethodMissing(key: string) {
return key.toUpperCase()
}
}
it('should call corresponding method', async function () {
const html = await liquid.parseAndRender(`{{obj.getName}}`, {obj: new CustomDrop()})
expect(html).to.equal('GETNAME')
})
it('should read corresponding property', async function () {
const html = await liquid.parseAndRender(`{{obj.name}}`, {obj: new CustomDrop()})
expect(html).to.equal('NAME')
})
it('should output empty string if not exist', async function () {
const html = await liquid.parseAndRender(`{{obj.foo}}`, {obj: new CustomDrop()})
expect(html).to.equal('')
})
it('should respect liquidMethodMissing', async function () {
const html = await liquid.parseAndRender(`{{obj.foo}}`, {obj: new CustomDropWithMethodMissing()})
expect(html).to.equal('FOO')
})
})
+8 -8
View File
@@ -4,26 +4,26 @@ import Liquid from '../../../src/liquid'
describe('LiquidOptions#*_delimiter_*', function () {
it('should respect tag_delimiter_*', async function () {
const engine = new Liquid({
tag_delimiter_left: '<%=',
tag_delimiter_right: '%>'
tagDelimiterLeft: '<%=',
tagDelimiterRight: '%>'
})
const html = await engine.parseAndRender('<%=if true%>foo<%=endif%> ')
return expect(html).to.equal('foo ')
})
it('should respect output_delimiter_*', async function () {
const engine = new Liquid({
output_delimiter_left: '<<',
output_delimiter_right: '>>'
outputDelimiterLeft: '<<',
outputDelimiterRight: '>>'
})
const html = await engine.parseAndRender('<< "liquid" | capitalize >>')
return expect(html).to.equal('Liquid')
})
it('should support trimming with tag_delimiter_* set', async function () {
const engine = new Liquid({
tag_delimiter_left: '<%=',
tag_delimiter_right: '%>',
trim_tag_left: true,
trim_tag_right: true
tagDelimiterLeft: '<%=',
tagDelimiterRight: '%>',
trimTagLeft: true,
trimTagRight: true
})
const html = await engine.parseAndRender(' <%=if true%> \tfoo\t <%=endif%> ')
return expect(html).to.equal('foo')
+5 -5
View File
@@ -10,22 +10,22 @@ describe('LiquidOptions#strict_*', function () {
extname: '.html'
})
})
it('should not throw when strict_variables false (default)', async function () {
it('should not throw when strictVariables false (default)', async function () {
const html = await engine.parseAndRender('before{{notdefined}}after', ctx)
return expect(html).to.equal('beforeafter')
})
it('should throw when strict_variables true', function () {
it('should throw when strictVariables true', function () {
const tpl = engine.parse('before{{notdefined}}after')
const opts = {
strict_variables: true
strictVariables: true
}
return expect(engine.render(tpl, ctx, opts)).to
.be.rejectedWith(/undefined variable: notdefined/)
})
it('should pass strict_variables to render by parseAndRender', function () {
it('should pass strictVariables to render by parseAndRender', function () {
const html = 'before{{notdefined}}after'
const opts = {
strict_variables: true
strictVariables: true
}
return expect(engine.parseAndRender(html, ctx, opts)).to
.be.rejectedWith(/undefined variable: notdefined/)
+7 -7
View File
@@ -6,34 +6,34 @@ describe('LiquidOptions#trimming', function () {
describe('tag trimming', function () {
it('should respect trim_tag_left', async function () {
const engine = new Liquid({ trim_tag_left: true })
const engine = new Liquid({ trim_tag_left: true } as any)
const html = await engine.parseAndRender(' \n \t{%if true%}foo{%endif%} ')
return expect(html).to.equal('foo ')
})
it('should respect trim_tag_right', async function () {
const engine = new Liquid({ trim_tag_right: true })
const engine = new Liquid({ trim_tag_right: true } as any)
const html = await engine.parseAndRender('\t{%if true%}foo{%endif%} \n')
return expect(html).to.equal('\tfoo')
})
it('should not trim value', async function () {
const engine = new Liquid({ trim_tag_left: true, trim_tag_right: true })
const engine = new Liquid({ trim_tag_left: true, trim_tag_right: true } as any)
const html = await engine.parseAndRender('{%if true%}a {{name}} b{%endif%}', ctx)
return expect(html).to.equal('a harttle b')
})
})
describe('value trimming', function () {
it('should respect trim_output_left', async function () {
const engine = new Liquid({ trim_output_left: true })
const engine = new Liquid({ trim_output_left: true } as any)
const html = await engine.parseAndRender(' \n \t{{name}} ', ctx)
return expect(html).to.equal('harttle ')
})
it('should respect trim_output_right', async function () {
const engine = new Liquid({ trim_output_right: true })
const engine = new Liquid({ trim_output_right: true } as any)
const html = await engine.parseAndRender(' \n \t{{name}} ', ctx)
return expect(html).to.equal(' \n \tharttle')
})
it('should respect not trim tag', async function () {
const engine = new Liquid({ trim_output_left: true, trim_output_right: true })
const engine = new Liquid({ trim_output_left: true, trim_output_right: true } as any)
const html = await engine.parseAndRender('\t{% if true %} aha {%endif%}\t')
return expect(html).to.equal('\t aha \t')
})
@@ -46,7 +46,7 @@ describe('LiquidOptions#trimming', function () {
return expect(html).to.equal('aharttle')
})
it('should respect to greedy:false by default', async function () {
const engine = new Liquid({ greedy: false })
const engine = new Liquid({ greedy: false } as any)
const html = await engine.parseAndRender(src, ctx)
return expect(html).to.equal('\n a \nharttle ')
})
+2 -2
View File
@@ -5,8 +5,8 @@ import { mock, restore } from '../../stub/mockfs'
let engine = new Liquid()
const strictEngine = new Liquid({
strict_variables: true,
strict_filters: true
strictVariables: true,
strictFilters: true
})
describe('error', function () {
+10
View File
@@ -0,0 +1,10 @@
import { expect } from 'chai'
import { Drop } from '../../../src/drop/drop'
describe('drop/drop', function () {
class CustomDrop extends Drop { }
it('.valueOf() should return undefined by default', async function () {
expect(new CustomDrop().valueOf()).to.be.undefined
})
})
+2 -2
View File
@@ -181,11 +181,11 @@ describe('scope', function () {
expect(scope.get('foo')).to.equal('bar')
})
})
describe('strict_variables', function () {
describe('strictVariables', function () {
let scope: Scope
beforeEach(function () {
scope = new Scope(ctx, {
strict_variables: true
strictVariables: true
} as any)
})
it('should throw when variable not defined', function () {
+5 -12
View File
@@ -25,20 +25,13 @@ describe('Output', function () {
})
const output = new Output({ value: 'foo' } as OutputToken, false)
const html = await output.render(scope)
return expect(html).to.equal('{"obj":{"arr":["a",2]}}')
})
it('should skip circular property', async function () {
const ctx = { foo: { num: 2 }, bar: 'bar' } as any
ctx.foo.circular = ctx
const output = new Output({ value: 'foo' } as OutputToken, false)
const html = await output.render(new Scope(ctx))
return expect(html).equal('{"num":2,"circular":{"bar":"bar"}}')
return expect(html).to.equal('[object Object]')
})
it('should skip function property', async function () {
const scope = new Scope({ obj: { foo: 'foo', bar: (x: any) => x } })
const output = new Output({ value: 'obj' } as OutputToken, false)
const html = await output.render(scope)
return expect(html).to.equal('{"foo":"foo"}')
return expect(html).to.equal('[object Object]')
})
it('should respect to .toString()', async () => {
const scope = new Scope({ obj: { toString: () => 'FOO' } })
@@ -52,9 +45,9 @@ describe('Output', function () {
const str = await output.render(scope)
return expect(str).to.equal('FOO')
})
it('should respect to .liquid_method_missing()', async () => {
const scope = new Scope({ obj: { liquid_method_missing: (x: string) => x.toUpperCase() } })
const output = new Output({ value: 'obj.foo' } as OutputToken, false)
it('should respect to .toString()', async () => {
const scope = new Scope({ obj: { toString: () => 'FOO' } })
const output = new Output({ value: 'obj' } as OutputToken, false)
const str = await output.render(scope)
return expect(str).to.equal('FOO')
})
-4
View File
@@ -34,10 +34,6 @@ describe('util/underscore', function () {
it('should return "" for undefined', function () {
expect(_.stringify(undefined)).to.equal('')
})
it('should use Object.prototype.toString if no toString method exists', function () {
const obj = { toString: undefined }
expect(_.stringify(obj)).to.equal('[object Object]')
})
it('should return regex string for RegExp', function () {
const reg = /foo/g
expect(_.stringify(reg)).to.equal('/foo/g')