refactor: strictly typed

This commit is contained in:
harttle
2019-02-23 00:49:54 +08:00
parent 51f7e66f60
commit 5b6100d12b
86 changed files with 2630 additions and 2590 deletions
+2 -2
View File
@@ -2,10 +2,10 @@ import { expect } from 'chai'
import Liquid from '../..'
describe('.evalValue()', function () {
var engine
var engine: Liquid
beforeEach(() => { engine = new Liquid() })
it('should throw when scope undefined', function () {
expect(() => engine.evalValue('{{"foo"}}')).to.throw(/scope undefined/)
expect(() => engine.evalValue('{{"foo"}}', null as any)).to.throw(/scope undefined/)
})
})
+2 -2
View File
@@ -8,7 +8,7 @@ describe('express()', function () {
const root = resolve(__dirname, '../stub/root')
const views = resolve(__dirname, '../stub/views')
const partials = resolve(__dirname, '../stub/partials')
let app, engine
let app: express.Application, engine: Liquid
beforeEach(function () {
app = express()
@@ -45,7 +45,7 @@ describe('express()', function () {
}
const file = '/not-exist.html'
const ctx = {}
engine.express().call(view, file, ctx, function (err) {
engine.express().call(view, file, ctx, function (err: any) {
try {
expect(err.code).to.equal('ENOENT')
expect(err.message).to.match(/Failed to lookup/)
+1 -1
View File
@@ -5,7 +5,7 @@ import * as chaiAsPromised from 'chai-as-promised'
use(chaiAsPromised)
describe('.parseAndRender()', function () {
var engine, strictEngine
var engine: Liquid, strictEngine: Liquid
beforeEach(function () {
engine = new Liquid()
strictEngine = new Liquid({
+1 -1
View File
@@ -8,7 +8,7 @@ use(chaiAsPromised)
describe('#renderFile()', function () {
const root = resolve(__dirname, '../stub/root')
const views = resolve(__dirname, '../stub/views')
let engine
let engine: Liquid
beforeEach(function () {
engine = new Liquid({
root,
+6 -6
View File
@@ -1,5 +1,5 @@
import Liquid from '../../dist/liquid.js'
import { createFakeServer, useFakeXMLHttpRequest } from 'sinon'
import * as sinon from 'sinon'
import { expect, use } from 'chai'
import { JSDOM } from 'jsdom'
import * as chaiAsPromised from 'chai-as-promised'
@@ -7,13 +7,13 @@ import * as chaiAsPromised from 'chai-as-promised'
use(chaiAsPromised)
describe('xhr', () => {
if (+process.version.match(/^v(\d+)/)[1] < 8) {
if (+(process.version.match(/^v(\d+)/) as RegExpMatchArray)[1] < 8) {
console.info('jsdom not supported, skipping xhr...')
return
}
let server, engine
let server: sinon.SinonFakeServer, engine: Liquid
beforeEach(() => {
server = createFakeServer()
server = sinon.fakeServer.create()
server.autoRespond = true
server.respondWith('GET', 'https://example.com/views/hello.html',
[200, { 'Content-Type': 'text/plain' }, 'hello {{name}}'])
@@ -22,7 +22,7 @@ describe('xhr', () => {
contentType: 'text/html',
includeNodeLocations: true
});
(global as any).XMLHttpRequest = useFakeXMLHttpRequest();
(global as any).XMLHttpRequest = sinon.FakeXMLHttpRequest;
(global as any).document = dom.window.document
engine = new Liquid({
root: 'https://example.com/views/',
@@ -68,7 +68,7 @@ describe('xhr', () => {
it('should throw error', function () {
const result = expect(engine.renderFile('hello.html'))
.to.be.rejectedWith('An error occurred whilst receiving the response.');
(global as any).XMLHttpRequest.onCreate = function (request) {
(global as any).XMLHttpRequest.onCreate = function (request: sinon.SinonFakeXMLHttpRequest) {
setTimeout(() => request.error())
}
return result
+1 -1
View File
@@ -21,7 +21,7 @@ export function mock (options: { [path: string]: (string | fileDescriptor) }) {
return file.content
}
fs.exists = async function (path) {
fs.exists = async function (path: string) {
console.log('mock fs exists called', path)
return !!files[path]
}
+1 -1
View File
@@ -12,7 +12,7 @@ export const ctx = {
posts: [{ category: 'foo' }, { category: 'bar' }]
}
export async function test (src, dst) {
export async function test (src: string, dst: string) {
const html = await liquid.parseAndRender(src, ctx)
return expect(html).to.equal(dst)
}
+2 -1
View File
@@ -1,11 +1,12 @@
import Liquid from 'src/liquid'
import { expect, use } from 'chai'
import * as chaiAsPromised from 'chai-as-promised'
import IContext from 'src/scope/icontext';
use(chaiAsPromised)
describe('tags/for', function () {
let liquid, ctx
let liquid: Liquid, ctx: IContext
before(function () {
liquid = new Liquid()
liquid.registerTag('throwingTag', {
+1 -1
View File
@@ -3,7 +3,7 @@ import { expect } from 'chai'
import { mock, restore } from 'test/stub/mockfs'
describe('tags/include', function () {
let liquid
let liquid: Liquid
before(function () {
liquid = new Liquid({
root: '/',
+1 -1
View File
@@ -3,7 +3,7 @@ import { expect } from 'chai'
import { mock, restore } from 'test/stub/mockfs'
describe('tags/layout', function () {
let liquid
let liquid: Liquid
before(function () {
liquid = new Liquid({
root: '/',
+1 -1
View File
@@ -5,7 +5,7 @@ import * as chaiAsPromised from 'chai-as-promised'
use(chaiAsPromised)
describe('tags/unless', function () {
let liquid
let liquid: Liquid
before(() => { liquid = new Liquid() })
it('should render else when predicate yields true', async function () {
+3 -3
View File
@@ -8,7 +8,7 @@ const resolve = fs.resolve
describe('fs/browser', function () {
describe('#resolve()', function () {
if (+process.version.match(/^v(\d+)/)[1] < 8) {
if (+(process.version.match(/^v(\d+)/) as RegExpMatchArray)[1] < 8) {
console.info('jsdom not supported, skipping template-browser...')
return
}
@@ -54,9 +54,9 @@ describe('fs/browser', function () {
})
describe('#readFile()', () => {
let server
let server: sinon.SinonFakeServer
beforeEach(() => {
server = sinon.createFakeServer()
server = sinon.fakeServer.create()
server.autoRespond = true
server.respondWith('GET', 'https://example.com/views/hello.html',
[200, { 'Content-Type': 'text/plain' }, 'hello {{name}}']);
+1 -1
View File
@@ -3,7 +3,7 @@ import Liquid from 'src/liquid'
import { mock, restore } from 'test/stub/mockfs'
describe('LiquidOptions#cache', function () {
let engine
let engine: Liquid
beforeEach(function () {
engine = new Liquid({
root: '/root/',
+2 -2
View File
@@ -33,14 +33,14 @@ describe('Liquid', function () {
})
after(restore)
it('should render single template', function (done) {
render.call({ root: '.' }, 'foo', null, (err, result) => {
render.call({ root: '.' }, 'foo', null as any, (err: Error | null, result: string | undefined) => {
if (err) return done(err)
expect(result).to.equal('foo')
done()
})
})
it('should render single template with Array-typed root', function (done) {
render.call({ root: ['.'] }, 'foo', null, (err, result) => {
render.call({ root: ['.'] }, 'foo', null as any, (err: Error | null, result: string | undefined) => {
if (err) return done(err)
expect(result).to.equal('foo')
done()
+1 -1
View File
@@ -2,7 +2,7 @@ import Liquid from 'src/liquid'
import { expect } from 'chai'
describe('LiquidOptions#strict_*', function () {
let engine
let engine: Liquid
const ctx = {}
beforeEach(function () {
engine = new Liquid({
+1 -1
View File
@@ -56,7 +56,7 @@ describe('tokenizer', function () {
const tokens = tokenizer.tokenize(html)
expect(tokens.length).to.equal(1)
expect(tokens[0]).instanceOf(TagToken)
expect(tokens[0].args).to.equal('a:a\nb:1.23')
expect((tokens[0] as TagToken).args).to.equal('a:a\nb:1.23')
expect(tokens[0].raw).to.equal('{%foo\na:a\nb:1.23\n%}')
})
it('should handle multiple lines value', function () {
+3 -3
View File
@@ -2,12 +2,12 @@ import { expect } from 'chai'
import Scope from 'src/scope/scope'
import Token from 'src/parser/token'
import Tag from 'src/template/tag/tag'
import Filter from 'src/template/filter'
import Filter from 'src/template/filter/Filter'
import Render from 'src/render/render'
import HTML from 'src/template/html'
describe('render', function () {
let render
let render: Render
before(function () {
Filter.clear()
Tag.clear()
@@ -16,7 +16,7 @@ describe('render', function () {
describe('.renderTemplates()', function () {
it('should throw when scope undefined', function () {
expect(render.renderTemplates([])).to.be.rejectedWith(/scope undefined/)
expect(render.renderTemplates([], null as any)).to.be.rejectedWith(/scope undefined/)
})
it('should render html', async function () {
+1 -1
View File
@@ -3,7 +3,7 @@ import { expect } from 'chai'
import { evalExp, evalValue, isTruthy } from 'src/render/syntax'
describe('expression', function () {
let scope
let scope: Scope
beforeEach(function () {
scope = new Scope({
+4 -3
View File
@@ -1,10 +1,11 @@
import * as chai from 'chai'
import Scope from 'src/scope/scope'
import IContext from 'src/scope/icontext';
const expect = chai.expect
describe('scope', function () {
let scope, ctx
let scope: Scope, ctx: IContext
beforeEach(function () {
ctx = {
foo: 'zoo',
@@ -68,7 +69,7 @@ describe('scope', function () {
}
expect(fn).to.not.throw()
expect(scope.get('notdefined')).to.equal(undefined)
expect(scope.get(false)).to.equal(undefined)
expect(scope.get(false as any)).to.equal(undefined)
})
it('should throw for invalid path', function () {
@@ -169,7 +170,7 @@ describe('scope', function () {
})
})
describe('strict_variables', function () {
let scope
let scope: Scope
beforeEach(function () {
scope = new Scope(ctx, {
strict_variables: true
+2 -2
View File
@@ -1,14 +1,14 @@
import * as chai from 'chai'
import * as sinon from 'sinon'
import * as sinonChai from 'sinon-chai'
import Filter from 'src/template/filter'
import Filter from 'src/template/filter/filter'
import Scope from 'src/scope/scope'
chai.use(sinonChai)
const expect = chai.expect
describe('filter', function () {
let scope
let scope: Scope
beforeEach(function () {
Filter.clear()
scope = new Scope()
+3 -3
View File
@@ -2,7 +2,7 @@ import * as chai from 'chai'
import Scope from 'src/scope/scope'
import Output from 'src/template/output'
import OutputToken from 'src/parser/output-token'
import Filter from 'src/template/filter'
import Filter from 'src/template/filter/filter'
const expect = chai.expect
@@ -35,7 +35,7 @@ describe('Output', function () {
return expect(html).equal('{"num":2,"circular":{"bar":"bar"}}')
})
it('should skip function property', async function () {
const scope = new Scope({ obj: { foo: 'foo', bar: x => x } })
const scope = new Scope({ obj: { foo: 'foo', bar: (x: any) => x } })
const output = new Output({ value: 'obj' } as OutputToken)
const html = await output.render(scope)
return expect(html).to.equal('{"foo":"foo"}')
@@ -53,7 +53,7 @@ describe('Output', function () {
return expect(str).to.equal('FOO')
})
it('should respect to .liquid_method_missing()', async () => {
const scope = new Scope({ obj: { liquid_method_missing: x => x.toUpperCase() } })
const scope = new Scope({ obj: { liquid_method_missing: (x: string) => x.toUpperCase() } })
const output = new Output({ value: 'obj.foo' } as OutputToken)
const str = await output.render(scope)
return expect(str).to.equal('FOO')
+3 -3
View File
@@ -11,7 +11,7 @@ const expect = chai.expect
const liquid = new Liquid()
describe('tag', function () {
let scope
let scope: Scope
before(function () {
scope = new Scope({
foo: 'bar',
@@ -56,7 +56,7 @@ describe('tag', function () {
})
describe('hash', function () {
let spy, token
let spy: sinon.SinonSpy, token: TagToken
beforeEach(function () {
spy = sinon.spy()
Tag.register('foo', {
@@ -67,7 +67,7 @@ describe('tag', function () {
value: 'foo aa:foo bb: arr[0] cc: 2.3\ndd:bar.coo',
name: 'foo',
args: 'aa:foo bb: arr[0] cc: 2.3\ndd:bar.coo'
}
} as TagToken
})
it('should call tag.render with scope', async function () {
await new Tag(token, [], liquid).render(scope)
+2 -2
View File
@@ -2,13 +2,13 @@ import * as chai from 'chai'
import * as sinonChai from 'sinon-chai'
import * as sinon from 'sinon'
import Scope from 'src/scope/scope'
import Filter from 'src/template/filter'
import Filter from 'src/template/filter/filter'
import Value from 'src/template/value'
chai.use(sinonChai)
const expect = chai.expect
const add = (l, r) => l + r
const add = (l: number, r: number) => l + r
describe('Value', function () {
beforeEach(() => Filter.clear())
+2 -44
View File
@@ -32,10 +32,10 @@ describe('error', function () {
expect(err.stack).to.contain(message.join('\n'))
expect(err.name).to.equal('TokenizationError')
})
it('should contain the whole template content in err.input', async function () {
it('should contain the whole template content in err.token.input', async function () {
const html = 'bar\nfoo{% . a %}\nfoo'
const err = await expect(engine.parseAndRender(html)).be.rejected
expect(err.input).to.equal(html)
expect(err.token.input).to.equal(html)
})
it('should contain line number in err.token.line', async function () {
const err = await expect(engine.parseAndRender('1\n2\n{% . a %}\n4')).be.rejected
@@ -49,25 +49,12 @@ describe('error', function () {
expect(err.stack).to.contain('at Liquid.parse')
})
describe('captureStackTrace compatibility', function () {
const captureStackTrace = Error.captureStackTrace
before(() => (Error.captureStackTrace = null))
after(() => (Error.captureStackTrace = captureStackTrace))
it('should be empty when captureStackTrace undefined', async function () {
const err = await expect(engine.parseAndRender('{% . a %}')).be.rejected
expect(err.stack).to.contain('illegal tag syntax')
expect(err.stack).to.not.contain('at Object.parse')
})
})
it('should contain file path in err.file', async function () {
const html = '<html>\n<head>\n\n{% . a %}\n\n'
mock({
'/foo.html': html
})
const err = await expect(engine.renderFile('/foo.html')).be.rejected
restore()
expect(err.name).to.equal('TokenizationError')
expect(err.file).to.equal(path.resolve('/foo.html'))
})
it('should throw error with line and pos if tag unmatched', async function () {
const err = await expect(engine.parseAndRender('1\n2\nfoo{% assign a = 4 }\n4')).be.rejected
expect(err.name).to.equal('TokenizationError')
@@ -187,12 +174,6 @@ describe('error', function () {
expect(err.stack).to.contain(message.join('\n'))
expect(err.name).to.equal('RenderError')
})
it('should contain the whole template content in err.input', async function () {
const html = 'bar\nfoo{%throwingTag%}\nfoo'
const err = await expect(engine.parseAndRender(html)).be.rejected
expect(err.input).to.equal(html)
expect(err.name).to.equal('RenderError')
})
it('should contain line number in err.token.line', async function () {
const src = '1\n2\n{{1|throwingFilter}}\n4'
const err = await expect(engine.parseAndRender(src)).be.rejected
@@ -204,18 +185,6 @@ describe('error', function () {
expect(err.message).to.contain('intended render reject')
expect(err.stack).to.match(/at .*:\d+:\d+/)
})
it('should contain file path in err.file', async function () {
const html = '<html>\n<head>\n\n{% throwingTag %}\n\n'
mock({
'/foo.html': html
})
const err = await expect(engine.renderFile('/foo.html')).be.rejected
restore()
console.log(err, err.name)
expect(err.name).to.equal('RenderError')
expect(err.file).to.equal(path.resolve('/foo.html'))
})
})
describe('ParseError', function () {
@@ -296,16 +265,5 @@ describe('error', function () {
expect(err.stack).to.contain('ParseError: tag -a not found')
expect(err.stack).to.match(/at .*:\d+:\d+\)/)
})
it('should contain file path in err.file', async function () {
const html = '<html>\n<head>\n\n{% raw %}\n\n'
mock({
'/foo.html': html
})
const err = await expect(engine.renderFile('/foo.html')).be.rejected
restore()
expect(err.name).to.equal('ParseError')
expect(err.file).to.equal(path.resolve('/foo.html'))
})
})
})
+6 -48
View File
@@ -1,68 +1,26 @@
import * as chai from 'chai'
import * as sinon from 'sinon'
import * as sinonChai from 'sinon-chai'
import * as chaiAsPromised from 'chai-as-promised'
const expect = chai.expect
chai.use(sinonChai)
chai.use(chaiAsPromised)
const P = require('src/util/promise')
describe('util/promise', function () {
describe('.anySeries()', function () {
it('should resolve in series', function () {
const spy1 = sinon.spy()
const spy2 = sinon.spy()
return P
.anySeries(
['first', 'second'],
(item, idx) => new Promise(function (resolve, reject) {
if (idx === 0) {
setTimeout(function () {
spy1()
reject(new Error('first cb'))
}, 10)
} else {
spy2()
resolve('foo')
}
}))
.then(() => expect(spy2).to.have.been.calledAfter(spy1))
})
it('should reject when all rejected', function () {
const p = P.anySeries(['first', 'second', 'third'],
item => Promise.reject(new Error(item)))
return expect(p).to.be.rejectedWith('third')
})
it('should resolve the value that first callback resolved', async () => {
const result = await P.anySeries(
['first', 'second'],
item => Promise.resolve(item)
)
return expect(result).to.equal('first')
})
it('should not call rest of callbacks once resolved', () => {
const spy = sinon.spy()
return P
.anySeries(['first', 'second'], (item, idx) => {
if (idx > 0) {
spy()
}
return Promise.resolve(item)
})
.then(() => expect(spy).to.not.have.been.called)
})
})
describe('.mapSeries()', async function () {
it('should resolve when all resolved', async function () {
const result = await P.mapSeries(
['first', 'second', 'third'],
item => Promise.resolve(item)
(item: string) => Promise.resolve(item)
)
return expect(result).to.deep.equal(['first', 'second', 'third'])
})
it('should reject with the error that first callback rejected', () => {
const p = P.mapSeries(['first', 'second'],
item => Promise.reject(item))
(item: string) => Promise.reject(item))
return expect(p).to.rejectedWith('first')
})
it('should resolve in series', function () {
@@ -71,7 +29,7 @@ describe('util/promise', function () {
return P
.mapSeries(
['first', 'second'],
(item, idx) => new Promise(function (resolve) {
(item: string, idx: number) => new Promise(function (resolve) {
if (idx === 0) {
setTimeout(function () {
spy1()
@@ -87,7 +45,7 @@ describe('util/promise', function () {
it('should not call rest of callbacks once rejected', () => {
const spy = sinon.spy()
return P
.mapSeries(['first', 'second'], (item, idx) => {
.mapSeries(['first', 'second'], (item: string, idx: number) => {
if (idx > 0) {
spy()
}
+2 -2
View File
@@ -4,8 +4,8 @@ import t from 'src/util/strftime'
const expect = chai.expect
describe('util/strftime', function () {
let now
let then
let now: Date
let then: Date
before(function () {
mockUTC()
now = new Date('2016-01-04T13:15:23.000Z')
+3 -47
View File
@@ -3,6 +3,7 @@ import * as sinonChai from 'sinon-chai'
import * as sinon from 'sinon'
import { RenderError, RenderBreakError } from 'src/util/error'
import * as _ from 'src/util/underscore'
import ITemplate from 'src/template/itemplate'
const expect = chai.expect
chai.use(sinonChai)
@@ -17,7 +18,7 @@ describe('util/underscore', function () {
token: {
input: 'xx'
}
}
} as ITemplate
expect(_.isError(new RenderError(new Error(), tpl))).to.be.true
})
it('should return true for RenderBreakError', function () {
@@ -104,7 +105,7 @@ describe('util/underscore', function () {
})
describe('.isObject()', function () {
it('should return true for function', function () {
expect(_.isObject(x => x)).to.be.true
expect(_.isObject((x: any) => x)).to.be.true
})
it('should return true for plain object', function () {
expect(_.isObject({})).to.be.true
@@ -116,49 +117,4 @@ describe('util/underscore', function () {
expect(_.isObject(2)).to.be.false
})
})
describe('.assign()', function () {
it('should handle null dst', function () {
expect(_.assign(null, {
foo: 'bar'
})).to.deep.equal({
foo: 'bar'
})
})
it('should assign 2 objects', function () {
const src = {
foo: 'foo',
bar: 'bar'
}
const dst = {
foo: 'bar',
kaa: 'kaa'
}
expect(_.assign(dst, src)).to.deep.equal({
foo: 'foo',
bar: 'bar',
kaa: 'kaa'
})
})
it('should assign 3 objects', function () {
expect(_.assign({
foo: 'foo'
}, {
bar: 'bar'
}, {
car: 'car'
})).to.deep.equal({
foo: 'foo',
bar: 'bar',
car: 'car'
})
})
})
describe('.uniq()', function () {
it('should handle empty array', function () {
expect(_.uniq([])).to.deep.equal([])
})
it('should do uniq', function () {
expect(_.uniq([1, 'a', 'a', 1])).to.deep.equal([1, 'a'])
})
})
})