pref: remove await/async from internal async calls

This commit is contained in:
harttle
2019-10-26 08:57:33 -05:00
committed by Jun Yang
parent d4ad4b8a8c
commit b82fa9ed2b
40 changed files with 416 additions and 380 deletions
+29 -28
View File
@@ -1,6 +1,7 @@
import { Expression } from '../../../src/render/expression'
import { expect } from 'chai'
import { Context } from '../../../src/context/context'
import { toThenable } from '../../../src/util/async'
describe('Expression', function () {
let ctx: Context
@@ -16,57 +17,57 @@ describe('Expression', function () {
})
})
it('should throw when context not defined', async function () {
return expect(new Expression().value()).to.be.rejectedWith(/context not defined/)
it('should throw when context not defined', done => {
toThenable(new Expression().value(undefined!)).catch(err => {
expect(err.message).to.match(/context not defined/)
done()
return 0 as any
})
})
it('should eval simple expression', async function () {
expect(await new Expression('1 < 2').value(ctx)).to.equal(true)
expect(await new Expression('1 < 2').value(ctx)).to.equal(true)
expect(await new Expression('2 <= 2').value(ctx)).to.equal(true)
expect(await new Expression('one <= two').value(ctx)).to.equal(true)
expect(await new Expression('x contains "x"').value(ctx)).to.equal(false)
expect(await new Expression('x contains "X"').value(ctx)).to.equal(true)
expect(await new Expression('1 contains "x"').value(ctx)).to.equal(false)
expect(await new Expression('y contains "x"').value(ctx)).to.equal(false)
expect(await new Expression('z contains "x"').value(ctx)).to.equal(false)
expect(await new Expression('(1..5) contains 3').value(ctx)).to.equal(true)
expect(await new Expression('(1..5) contains 6').value(ctx)).to.equal(false)
expect(await new Expression('"<=" == "<="').value(ctx)).to.equal(true)
expect(await toThenable(new Expression('1 < 2').value(ctx))).to.equal(true)
expect(await toThenable(new Expression('1 < 2').value(ctx))).to.equal(true)
expect(await toThenable(new Expression('2 <= 2').value(ctx))).to.equal(true)
expect(await toThenable(new Expression('one <= two').value(ctx))).to.equal(true)
expect(await toThenable(new Expression('x contains "x"').value(ctx))).to.equal(false)
expect(await toThenable(new Expression('x contains "X"').value(ctx))).to.equal(true)
expect(await toThenable(new Expression('1 contains "x"').value(ctx))).to.equal(false)
expect(await toThenable(new Expression('y contains "x"').value(ctx))).to.equal(false)
expect(await toThenable(new Expression('z contains "x"').value(ctx))).to.equal(false)
expect(await toThenable(new Expression('(1..5) contains 3').value(ctx))).to.equal(true)
expect(await toThenable(new Expression('(1..5) contains 6').value(ctx))).to.equal(false)
expect(await toThenable(new Expression('"<=" == "<="').value(ctx))).to.equal(true)
})
describe('complex expression', function () {
it('should support value or value', async function () {
expect(await new Expression('false or true').value(ctx)).to.equal(true)
expect(await toThenable(new Expression('false or true').value(ctx))).to.equal(true)
})
it('should support < and contains', async function () {
expect(await new Expression('1 < 2 and x contains "x"').value(ctx)).to.equal(false)
expect(await toThenable(new Expression('1 < 2 and x contains "x"').value(ctx))).to.equal(false)
})
it('should support < or contains', async function () {
expect(await new Expression('1 < 2 or x contains "x"').value(ctx)).to.equal(true)
expect(await toThenable(new Expression('1 < 2 or x contains "x"').value(ctx))).to.equal(true)
})
it('should support value and !=', async function () {
expect(await new Expression('empty and empty != ""').value(ctx)).to.equal(false)
expect(await toThenable(new Expression('empty and empty != ""').value(ctx))).to.equal(false)
})
it('should recognize quoted value', async function () {
expect(await new Expression('">"').value(ctx)).to.equal('>')
expect(await toThenable(new Expression('">"').value(ctx))).to.equal('>')
})
it('should evaluate from right to left', async function () {
expect(await new Expression('true or false and false').value(ctx)).to.equal(true)
expect(await new Expression('true and false and false or true').value(ctx)).to.equal(false)
expect(await toThenable(new Expression('true or false and false').value(ctx))).to.equal(true)
expect(await toThenable(new Expression('true and false and false or true').value(ctx))).to.equal(false)
})
it('should recognize property access', async function () {
const ctx = new Context({ obj: { foo: true } })
expect(await new Expression('obj["foo"] and true').value(ctx)).to.equal(true)
expect(await toThenable(new Expression('obj["foo"] and true').value(ctx))).to.equal(true)
})
})
it('should eval range expression', async function () {
expect(await new Expression('(2..4)').value(ctx)).to.deep.equal([2, 3, 4])
expect(await new Expression('(two..4)').value(ctx)).to.deep.equal([2, 3, 4])
})
it('should support sync', function () {
expect(new Expression('empty and empty != ""').valueSync(ctx)).to.equal(false)
expect(await toThenable(new Expression('(2..4)').value(ctx))).to.deep.equal([2, 3, 4])
expect(await toThenable(new Expression('(two..4)').value(ctx))).to.deep.equal([2, 3, 4])
})
})
+2 -5
View File
@@ -5,6 +5,7 @@ import { Tag } from '../../../src/template/tag/tag'
import { Filter } from '../../../src/template/filter/filter'
import { Render } from '../../../src/render/render'
import { HTML } from '../../../src/template/html'
import { toThenable } from '../../../src/util/async'
describe('render', function () {
let render: Render
@@ -15,14 +16,10 @@ describe('render', function () {
})
describe('.renderTemplates()', function () {
it('should throw when scope undefined', function () {
expect(render.renderTemplates([], null as any)).to.be.rejectedWith(/scope undefined/)
})
it('should render html', async function () {
const scope = new Context()
const token = { type: 'html', value: '<p>' } as Token
const html = await render.renderTemplates([new HTML(token)], scope)
const html = await toThenable(render.renderTemplates([new HTML(token)], scope))
return expect(html).to.equal('<p>')
})
})
+5 -5
View File
@@ -5,20 +5,20 @@ import { expect } from 'chai'
describe('Value', function () {
it('should eval number variable', async function () {
const ctx = new Context({ one: 1 })
expect(new Value('one').valueSync(ctx)).to.equal(1)
expect(new Value('one').value(ctx)).to.equal(1)
})
it('question mark should be valid variable name', async function () {
const ctx = new Context({ 'has_value?': true })
expect(new Value('has_value?').valueSync(ctx)).to.equal(true)
expect(new Value('has_value?').value(ctx)).to.equal(true)
})
it('should eval string variable', async function () {
const ctx = new Context({ x: 'XXX' })
expect(new Value('x').valueSync(ctx)).to.equal('XXX')
expect(new Value('x').value(ctx)).to.equal('XXX')
})
it('should eval null literal', async function () {
expect(new Value('null').valueSync({})).to.be.null
expect(new Value('null').value({} as any)).to.be.null
})
it('should eval nil literal', async function () {
expect(new Value('nil').valueSync({})).to.be.null
expect(new Value('nil').value({} as any)).to.be.null
})
})
+10 -14
View File
@@ -3,6 +3,7 @@ import * as sinon from 'sinon'
import * as sinonChai from 'sinon-chai'
import { Filter } from '../../../../src/template/filter/filter'
import { Context } from '../../../../src/context/context'
import { toThenable } from '../../../../src/util/async'
chai.use(sinonChai)
const expect = chai.expect
@@ -19,40 +20,40 @@ describe('filter', function () {
})
it('should render input if filter not registered', async function () {
expect(await new Filter('undefined', [], false).render('foo', ctx)).to.equal('foo')
expect(await toThenable(new Filter('undefined', [], false).render('foo', ctx))).to.equal('foo')
})
it('should call filter impl with correct arguments', async function () {
const spy = sinon.spy()
Filter.register('foo', spy)
await new Filter('foo', ['33'], false).render('foo', ctx)
await toThenable(new Filter('foo', ['33'], false).render('foo', ctx))
expect(spy).to.have.been.calledWith('foo', 33)
})
it('should call filter impl with correct this arg', async function () {
const spy = sinon.spy()
Filter.register('foo', spy)
await new Filter('foo', ['33'], false).render('foo', ctx)
await toThenable(new Filter('foo', ['33'], false).render('foo', ctx))
expect(spy).to.have.been.calledOn(sinon.match.has('context', ctx))
})
it('should render a simple filter', async function () {
Filter.register('upcase', x => x.toUpperCase())
expect(await new Filter('upcase', [], false).render('foo', ctx)).to.equal('FOO')
expect(await toThenable(new Filter('upcase', [], false).render('foo', ctx))).to.equal('FOO')
})
it('should render filters with argument', async function () {
Filter.register('add', (a, b) => a + b)
expect(await new Filter('add', ['2'], false).render(3, ctx)).to.equal(5)
expect(await toThenable(new Filter('add', ['2'], false).render(3, ctx))).to.equal(5)
})
it('should render filters with multiple arguments', async function () {
Filter.register('add', (a, b, c) => a + b + c)
expect(await new Filter('add', ['2', '"c"'], false).render(3, ctx)).to.equal('5c')
expect(await toThenable(new Filter('add', ['2', '"c"'], false).render(3, ctx))).to.equal('5c')
})
it('should pass Objects/Drops as it is', async function () {
Filter.register('name', a => a.constructor.name)
class Foo {}
expect(await new Filter('name', [], false).render(new Foo(), ctx)).to.equal('Foo')
expect(await toThenable(new Filter('name', [], false).render(new Foo(), ctx))).to.equal('Foo')
})
it('should not throw when filter name illegal', function () {
@@ -61,13 +62,8 @@ describe('filter', function () {
}).to.not.throw()
})
it('should support sync', function () {
Filter.register('add', (a, b) => a + b)
expect(new Filter('add', ['2'], false).renderSync(3, ctx)).to.equal(5)
})
it('should support key value pairs', function () {
it('should support key value pairs', async function () {
Filter.register('add', (a, b) => b[0] + ':' + (a + b[1]))
expect(new Filter('add', [['num', '2']], false).renderSync(3, ctx)).to.equal('num:5')
expect(await toThenable((new Filter('add', [['num', '2']], false).render(3, ctx)))).to.equal('num:5')
})
})
+3 -6
View File
@@ -1,4 +1,5 @@
import * as chai from 'chai'
import { toThenable } from '../../../src/util/async'
import { Hash } from '../../../src/template/tag/hash'
import { Context } from '../../../src/context/context'
@@ -6,15 +7,11 @@ const expect = chai.expect
describe('Hash', function () {
it('should parse variable', async function () {
const hash = await Hash.create('num:foo', new Context({ foo: 3 }))
const hash = await toThenable(Hash.create('num:foo', new Context({ foo: 3 })))
expect(hash.num).to.equal(3)
})
it('should parse literals', async function () {
const hash = await Hash.create('num:3', new Context())
expect(hash.num).to.equal(3)
})
it('should support sync', function () {
const hash = Hash.createSync('num:3', new Context())
const hash = await toThenable(Hash.create('num:3', new Context()))
expect(hash.num).to.equal(3)
})
})
+6 -5
View File
@@ -1,4 +1,5 @@
import * as chai from 'chai'
import { toThenable } from '../../../src/util/async'
import { Context } from '../../../src/context/context'
import { Output } from '../../../src/template/output'
import { OutputToken } from '../../../src/parser/output-token'
@@ -7,7 +8,7 @@ import { Filter } from '../../../src/template/filter/filter'
const expect = chai.expect
describe('Output', function () {
const emitter = { write: (html: string) => (emitter.html += html), html: '' }
const emitter: any = { write: (html: string) => (emitter.html += html), html: '' }
beforeEach(function () {
Filter.clear()
emitter.html = ''
@@ -18,25 +19,25 @@ describe('Output', function () {
foo: { obj: { arr: ['a', 2] } }
})
const output = new Output({ value: 'foo' } as OutputToken, false)
await output.render(scope, emitter)
await toThenable(output.render(scope, emitter))
return expect(emitter.html).to.equal('[object Object]')
})
it('should skip function property', async function () {
const scope = new Context({ obj: { foo: 'foo', bar: (x: any) => x } })
const output = new Output({ value: 'obj' } as OutputToken, false)
await output.render(scope, emitter)
await toThenable(output.render(scope, emitter))
return expect(emitter.html).to.equal('[object Object]')
})
it('should respect to .toString()', async () => {
const scope = new Context({ obj: { toString: () => 'FOO' } })
const output = new Output({ value: 'obj' } as OutputToken, false)
await output.render(scope, emitter)
await toThenable(output.render(scope, emitter))
return expect(emitter.html).to.equal('FOO')
})
it('should respect to .toString()', async () => {
const scope = new Context({ obj: { toString: () => 'FOO' } })
const output = new Output({ value: 'obj' } as OutputToken, false)
await output.render(scope, emitter)
await toThenable(output.render(scope, emitter))
return expect(emitter.html).to.equal('FOO')
})
})
+8 -7
View File
@@ -5,6 +5,7 @@ import * as sinon from 'sinon'
import * as sinonChai from 'sinon-chai'
import { Liquid } from '../../../src/liquid'
import { TagToken } from '../../../src/parser/tag-token'
import { toThenable } from '../../../src/util/async'
chai.use(sinonChai)
const expect = chai.expect
@@ -12,7 +13,7 @@ const liquid = new Liquid()
describe('Tag', function () {
let ctx: Context
const emitter = { write: (html: string) => (emitter.html += html), html: '' }
const emitter: any = { write: (html: string) => (emitter.html += html), html: '' }
before(function () {
ctx = new Context({
foo: 'bar',
@@ -55,7 +56,7 @@ describe('Tag', function () {
value: 'foo',
name: 'foo'
} as TagToken
await new Tag(token, [], liquid).render(ctx, emitter)
await toThenable(new Tag(token, [], liquid).render(ctx, emitter))
expect(spy).to.have.been.called
})
@@ -74,29 +75,29 @@ describe('Tag', function () {
} as TagToken
})
it('should call tag.render with scope', async function () {
await new Tag(token, [], liquid).render(ctx, emitter)
await toThenable(new Tag(token, [], liquid).render(ctx, emitter))
expect(spy).to.have.been.calledWithMatch(ctx)
})
it('should resolve identifier hash', async function () {
await new Tag(token, [], liquid).render(ctx, emitter)
await toThenable(new Tag(token, [], liquid).render(ctx, emitter))
expect(spy).to.have.been.calledWithMatch({}, {
aa: 'bar'
})
})
it('should accept space between key/value', async function () {
await new Tag(token, [], liquid).render(ctx, emitter)
await toThenable(new Tag(token, [], liquid).render(ctx, emitter))
expect(spy).to.have.been.calledWithMatch({}, {
bb: 2
})
})
it('should resolve number value hash', async function () {
await new Tag(token, [], liquid).render(ctx, emitter)
await toThenable(new Tag(token, [], liquid).render(ctx, emitter))
expect(spy).to.have.been.calledWithMatch(ctx, {
cc: 2.3
})
})
it('should resolve property access hash', async function () {
await new Tag(token, [], liquid).render(ctx, emitter)
await toThenable(new Tag(token, [], liquid).render(ctx, emitter))
expect(spy).to.have.been.calledWithMatch(ctx, {
dd: 'uoo'
})
+2 -1
View File
@@ -1,4 +1,5 @@
import * as chai from 'chai'
import { toThenable } from '../../../src/util/async'
import * as sinonChai from 'sinon-chai'
import * as sinon from 'sinon'
import { Context } from '../../../src/context/context'
@@ -120,7 +121,7 @@ describe('Value', function () {
const scope = new Context({
foo: { bar: 'bar' }
})
await tpl.value(scope)
await toThenable(tpl.value(scope))
expect(date).to.have.been.calledWith('bar', 'b')
expect(time).to.have.been.calledWith('y', 2)
})
+106
View File
@@ -0,0 +1,106 @@
import { toThenable, toValue } from '../../../src/util/async'
import { expect, use } from 'chai'
import * as chaiAsPromised from 'chai-as-promised'
use(chaiAsPromised)
describe('utils/async', () => {
describe('#toThenable()', function () {
it('should support iterable with single return statement', async () => {
function * foo () {
return 'foo'
}
const result = await toThenable(foo())
expect(result).to.equal('foo')
})
it('should support promise', async () => {
function foo () {
return Promise.resolve('foo')
}
const result = await toThenable(foo())
expect(result).to.equal('foo')
})
it('should resolve dependency', async () => {
function * foo () {
return yield bar()
}
function * bar () {
return 'bar'
}
const result = await toThenable(foo())
expect(result).to.equal('bar')
})
it('should support promise dependency', async () => {
function * foo () {
return yield Promise.resolve('foo')
}
const result = await toThenable(foo())
expect(result).to.equal('foo')
})
it('should reject Promise if dependency throws syncly', done => {
function * foo () {
return yield bar()
}
function * bar (): IterableIterator<any> {
throw new Error('bar')
}
toThenable(foo()).catch(err => {
expect(err.message).to.equal('bar')
done()
return 0 as any
})
})
it('should resume promise after catch', async () => {
function * foo () {
let ret = ''
try {
yield bar()
} catch (e) {
ret += 'bar'
}
ret += 'foo'
return ret
}
function * bar (): IterableIterator<any> {
throw new Error('bar')
}
const ret = await toThenable(foo())
expect(ret).to.equal('barfoo')
})
})
describe('#toValue()', function () {
it('should throw Error if dependency throws syncly', () => {
function * foo () {
return yield bar()
}
function * bar (): IterableIterator<any> {
throw new Error('bar')
}
expect(() => toValue(foo())).to.throw('bar')
})
it('should resume yield after catch', () => {
function * foo () {
try {
yield bar()
} catch (e) {}
return yield 'foo'
}
function * bar (): IterableIterator<any> {
throw new Error('bar')
}
expect(toValue(foo())).to.equal('foo')
})
it('should resume return after catch', () => {
function * foo () {
try {
yield bar()
} catch (e) {}
return 'foo'
}
function * bar (): IterableIterator<any> {
throw new Error('bar')
}
expect(toValue(foo())).to.equal('foo')
})
})
})