Skip to content

Commit

Permalink
chore(TypeScript): ship Liquid to class
Browse files Browse the repository at this point in the history
BREAKING CHANGE: calling `Liquid()` without `new` now becomes invalid
  • Loading branch information
harttle committed Feb 14, 2019
1 parent a626de6 commit 1cc7249
Show file tree
Hide file tree
Showing 27 changed files with 124 additions and 126 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ Parse and Render:

```javascript
var Liquid = require('liquidjs');
var engine = Liquid();
var engine = new Liquid();

engine
.parseAndRender('{{name | capitalize}}', {name: 'alice'})
Expand All @@ -83,7 +83,7 @@ engine
## Render from File

```javascript
var engine = Liquid({
var engine = new Liquid({
root: path.resolve(__dirname, 'views/'), // dirs to lookup layouts/includes
extname: '.liquid' // the extname used for layouts/includes, defaults ""
});
Expand Down
6 changes: 3 additions & 3 deletions demo/express/app.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
const express = require('express')
const Liquid = require('../..')

let app = express()
let engine = Liquid({
const app = express()
const engine = new Liquid({
root: __dirname, // for layouts and partials
extname: '.liquid'
})
Expand All @@ -12,7 +12,7 @@ app.set('views', ['./partials', './views']) // specify the views directory
app.set('view engine', 'liquid') // set to default

app.get('/', function (req, res) {
let todos = ['fork and clone', 'make it better', 'make a pull request']
const todos = ['fork and clone', 'make it better', 'make a pull request']
res.render('todolist', {
todos: todos,
title: 'Welcome to liquidjs!'
Expand Down
2 changes: 1 addition & 1 deletion demo/reactjs/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class App extends Component {

componentDidMount() {

let engine = Liquid({
let engine = new Liquid({
root: path.resolve(__dirname, 'views/'), // dirs to lookup layouts/includes
extname: '.liquid' // the extname used for layouts/includes, defaults
});
Expand Down
134 changes: 66 additions & 68 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,48 +12,68 @@ import { ParseError, TokenizationError, RenderBreakError, AssertionError } from
import tags from './tags/index'
import filters from './filters'

const _engine = {
init: function (tag, filter, options) {
export default class Liquid {
private cache: object
private options: any
private tags: any
private filters: any
private parser: any
private renderer: any

constructor (options) {
options = _.assign({
root: ['.'],
cache: false,
extname: '',
dynamicPartials: true,
trim_tag_right: false,
trim_tag_left: false,
trim_value_right: false,
trim_value_left: false,
greedy: true,
strict_filters: false,
strict_variables: false
}, options)
options.root = normalizeStringArray(options.root)

if (options.cache) {
this.cache = {}
}
this.options = options
this.tag = tag
this.filter = filter
this.parser = Parser(tag, filter)
this.tags = Tag()
this.filters = Filter(options)
this.parser = Parser(this.tags, this.filters)
this.renderer = Render()

tags(this, Liquid)
filters(this, Liquid)

return this
},
parse: function (html, filepath) {
}
parse(html: string, filepath?: string) {
const tokens = tokenizer.parse(html, filepath, this.options)
return this.parser.parse(tokens)
},
render: function (tpl, ctx, opts) {
}
render(tpl: string, ctx: any, opts: any) {
opts = _.assign({}, this.options, opts)
const scope = new Scope(ctx, opts)
return this.renderer.renderTemplates(tpl, scope)
},
parseAndRender: async function (html, ctx, opts) {
}
async parseAndRender(html, ctx, opts) {
const tpl = await this.parse(html)
return this.render(tpl, ctx, opts)
},
getTemplate: async function (file, root) {
}
async getTemplate(file, root) {
const filepath = await template.resolve(file, root, this.options)
return this.respectCache(filepath, async () => {
const str = await template.read(filepath)
return this.parse(str, filepath)
})
},
renderFile: async function (file, ctx, opts) {
}
async renderFile(file, ctx, opts) {
opts = _.assign({}, opts)
const templates = await this.getTemplate(file, opts.root)
return this.render(templates, ctx, opts)
},
respectCache: async function (key, getter) {
}
async respectCache (key, getter) {
const cacheEnabled = this.options.cache
if (cacheEnabled && this.cache[key]) {
return this.cache[key]
Expand All @@ -63,21 +83,21 @@ const _engine = {
this.cache[key] = value
}
return value
},
evalValue: function (str, scope) {
}
evalValue (str, scope) {
const tpl = this.parser.parseValue(str.trim())
return this.renderer.evalValue(tpl, scope)
},
registerFilter: function (name, filter) {
return this.filter.register(name, filter)
},
registerTag: function (name, tag) {
return this.tag.register(name, tag)
},
plugin: function (plugin) {
}
registerFilter (name, filter) {
return this.filters.register(name, filter)
}
registerTag (name, tag) {
return this.tags.register(name, tag)
}
plugin (plugin) {
return plugin.call(this, Liquid)
},
express: function (opts) {
}
express (opts) {
opts = opts || {}
const self = this
return function (filePath, ctx, cb) {
Expand All @@ -87,47 +107,25 @@ const _engine = {
self.renderFile(filePath, ctx, opts).then(html => cb(null, html), cb)
}
}
static default = Liquid
static isTruthy = isTruthy
static isFalsy = isFalsy
static evalExp = evalExp
static evalValue = evalValue
static Types = {
ParseError,
TokenizationError,
RenderBreakError,
AssertionError,
AssignScope: {},
CaptureScope: {},
IncrementScope: {},
DecrementScope: {}
}
}

function normalizeStringArray (value) {
if (_.isArray(value)) return value
if (_.isString(value)) return [value]
throw new TypeError('illegal root: ' + value)
}

export default function Liquid (options) {
options = _.assign({
root: ['.'],
cache: false,
extname: '',
dynamicPartials: true,
trim_tag_right: false,
trim_tag_left: false,
trim_value_right: false,
trim_value_left: false,
greedy: true,
strict_filters: false,
strict_variables: false
}, options)
options.root = normalizeStringArray(options.root)

const engine = _.create(_engine)
engine.init(Tag(), Filter(options), options)
return engine
}

Liquid.default = Liquid
Liquid.isTruthy = isTruthy
Liquid.isFalsy = isFalsy
Liquid.evalExp = evalExp
Liquid.evalValue = evalValue
Liquid.Types = {
ParseError,
TokenizationError,
RenderBreakError,
AssertionError,
AssignScope: {},
CaptureScope: {},
IncrementScope: {},
DecrementScope: {}
}
6 changes: 3 additions & 3 deletions src/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import * as path from 'path'
import { anySeries } from './util/promise'
import * as fs from 'fs'

const statFileAsync = _.promisify(fs.stat)
const readFileAsync = _.promisify(fs.readFile)
const statFileAsync = <(filepath: string) => Promise<object>>_.promisify(fs.stat)
const readFileAsync = <(filepath: string, encoding: string) => Promise<string>>_.promisify(fs.readFile)

export async function resolve (filepath, root, options) {
if (!path.extname(filepath)) {
Expand All @@ -24,6 +24,6 @@ export async function resolve (filepath, root, options) {
})
}

export async function read (filepath) {
export async function read (filepath): Promise<string> {
return readFileAsync(filepath, 'utf8')
}
2 changes: 1 addition & 1 deletion test/e2e/express.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ describe('engine#express()', function () {

beforeEach(function () {
app = express()
engine = Liquid({
engine = new Liquid({
root: '/root',
extname: '.html'
})
Expand Down
4 changes: 2 additions & 2 deletions test/e2e/parse-and-render.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ chai.use(require('chai-as-promised'))
describe('.parseAndRender()', function () {
var engine, strictEngine
beforeEach(function () {
engine = Liquid()
strictEngine = Liquid({
engine = new Liquid()
strictEngine = new Liquid({
strict_filters: true
})
})
Expand Down
10 changes: 5 additions & 5 deletions test/e2e/render-file.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ chai.use(require('chai-as-promised'))
describe('#renderFile()', function () {
var engine
beforeEach(function () {
engine = Liquid({
engine = new Liquid({
root: '/root/',
extname: '.html'
})
Expand All @@ -29,7 +29,7 @@ describe('#renderFile()', function () {
.to.eventually.equal('foo')
})
it('should find files without extname', function () {
var engine = Liquid({ root: '/root' })
var engine = new Liquid({ root: '/root' })
return expect(engine.renderFile('/root/files/bar', {}))
.to.eventually.equal('bar')
})
Expand All @@ -38,7 +38,7 @@ describe('#renderFile()', function () {
.to.eventually.equal('foo')
})
it('should resolve array as root', function () {
engine = Liquid({
engine = new Liquid({
root: ['/boo', '/root/'],
extname: '.html'
})
Expand All @@ -50,7 +50,7 @@ describe('#renderFile()', function () {
files[process.cwd() + '/foo.html'] = 'FOO'
mock(files)

engine = Liquid({
engine = new Liquid({
extname: '.html'
})
return expect(engine.renderFile('foo.html'))
Expand All @@ -64,7 +64,7 @@ describe('#renderFile()', function () {
return expect(engine.renderFile('files/name', { name: 'harttle' })).to.eventually.equal('My name is harttle.')
})
it('should throw with lookup list when file not exist', function () {
engine = Liquid({
engine = new Liquid({
root: ['/boo', '/root/'],
extname: '.html'
})
Expand Down
14 changes: 7 additions & 7 deletions test/e2e/xhr.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ describe('xhr', () => {
})
global.XMLHttpRequest = sinon.useFakeXMLHttpRequest()
global.document = dom.window.document
engine = Liquid({
engine = new Liquid({
root: 'https://example.com/views/',
extname: '.html'
})
Expand Down Expand Up @@ -78,7 +78,7 @@ describe('xhr', () => {
})
describe('#renderFile() with root specified', () => {
it('should support undefined root', () => {
engine = Liquid({
engine = new Liquid({
extname: '.html'
})
server.respondWith('GET', 'https://example.com/foo/hello.html',
Expand All @@ -87,7 +87,7 @@ describe('xhr', () => {
.to.eventually.equal('hello alice5')
})
it('should support empty root', () => {
engine = Liquid({
engine = new Liquid({
root: '',
extname: '.html'
})
Expand All @@ -97,7 +97,7 @@ describe('xhr', () => {
.to.eventually.equal('hello alice5')
})
it('should support with relative path', () => {
engine = Liquid({
engine = new Liquid({
root: './views/',
extname: '.html'
})
Expand All @@ -107,7 +107,7 @@ describe('xhr', () => {
.to.eventually.equal('hello alice5')
})
it('should support with absolute path', () => {
engine = Liquid({
engine = new Liquid({
root: '/views/',
extname: '.html'
})
Expand All @@ -117,7 +117,7 @@ describe('xhr', () => {
.to.eventually.equal('hello alice5')
})
it('should support with url', () => {
engine = Liquid({
engine = new Liquid({
root: 'https://foo.com/bar/',
extname: '.html'
})
Expand All @@ -141,7 +141,7 @@ describe('xhr', () => {
.then(html => expect(html).to.equal('foo2'))
})
it('should respect cache=true option', () => {
engine = Liquid({
engine = new Liquid({
root: '/views/',
extname: '.html',
cache: true
Expand Down
4 changes: 2 additions & 2 deletions test/unit/options/cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ chai.use(chaiAsPromised)
describe('cache options', function () {
let engine
beforeEach(function () {
engine = Liquid({
engine = new Liquid({
root: '/root/',
extname: '.html'
})
Expand All @@ -28,7 +28,7 @@ describe('cache options', function () {
.then(x => expect(x).to.equal('bar'))
})
it('should respect cache=true option', function () {
engine = Liquid({
engine = new Liquid({
root: '/root/',
extname: '.html',
cache: true
Expand Down

0 comments on commit 1cc7249

Please sign in to comment.