mirror of
https://github.com/harttle/liquidjs.git
synced 2026-09-26 13:45:15 -07:00
refactor: rename toValue to toValueSync
This commit is contained in:
+5
-5
@@ -12,7 +12,7 @@ import { TagMap } from './template/tag/tag-map'
|
|||||||
import { FilterMap } from './template/filter/filter-map'
|
import { FilterMap } from './template/filter/filter-map'
|
||||||
import { LiquidOptions, normalizeDirectoryList, NormalizedFullOptions, normalize, RenderOptions } from './liquid-options'
|
import { LiquidOptions, normalizeDirectoryList, NormalizedFullOptions, normalize, RenderOptions } from './liquid-options'
|
||||||
import { FilterImplOptions } from './template/filter/filter-impl-options'
|
import { FilterImplOptions } from './template/filter/filter-impl-options'
|
||||||
import { toPromise, toValue } from './util/async'
|
import { toPromise, toValueSync } from './util/async'
|
||||||
|
|
||||||
export * from './util/error'
|
export * from './util/error'
|
||||||
export * from './types'
|
export * from './types'
|
||||||
@@ -47,7 +47,7 @@ export class Liquid {
|
|||||||
return toPromise(this._render(tpl, scope, { ...renderOptions, sync: false }))
|
return toPromise(this._render(tpl, scope, { ...renderOptions, sync: false }))
|
||||||
}
|
}
|
||||||
public renderSync (tpl: Template[], scope?: object, renderOptions?: RenderOptions): any {
|
public renderSync (tpl: Template[], scope?: object, renderOptions?: RenderOptions): any {
|
||||||
return toValue(this._render(tpl, scope, { ...renderOptions, sync: true }))
|
return toValueSync(this._render(tpl, scope, { ...renderOptions, sync: true }))
|
||||||
}
|
}
|
||||||
public renderToNodeStream (tpl: Template[], scope?: object, renderOptions: RenderOptions = {}): NodeJS.ReadableStream {
|
public renderToNodeStream (tpl: Template[], scope?: object, renderOptions: RenderOptions = {}): NodeJS.ReadableStream {
|
||||||
const ctx = new Context(scope, this.options, renderOptions)
|
const ctx = new Context(scope, this.options, renderOptions)
|
||||||
@@ -62,7 +62,7 @@ export class Liquid {
|
|||||||
return toPromise(this._parseAndRender(html, scope, { ...renderOptions, sync: false }))
|
return toPromise(this._parseAndRender(html, scope, { ...renderOptions, sync: false }))
|
||||||
}
|
}
|
||||||
public parseAndRenderSync (html: string, scope?: object, renderOptions?: RenderOptions): any {
|
public parseAndRenderSync (html: string, scope?: object, renderOptions?: RenderOptions): any {
|
||||||
return toValue(this._parseAndRender(html, scope, { ...renderOptions, sync: true }))
|
return toValueSync(this._parseAndRender(html, scope, { ...renderOptions, sync: true }))
|
||||||
}
|
}
|
||||||
|
|
||||||
public _parsePartialFile (file: string, sync?: boolean, currentFile?: string) {
|
public _parsePartialFile (file: string, sync?: boolean, currentFile?: string) {
|
||||||
@@ -75,7 +75,7 @@ export class Liquid {
|
|||||||
return toPromise<Template[]>(this.parser.parseFile(file, false))
|
return toPromise<Template[]>(this.parser.parseFile(file, false))
|
||||||
}
|
}
|
||||||
public parseFileSync (file: string): Template[] {
|
public parseFileSync (file: string): Template[] {
|
||||||
return toValue<Template[]>(this.parser.parseFile(file, true))
|
return toValueSync<Template[]>(this.parser.parseFile(file, true))
|
||||||
}
|
}
|
||||||
public async renderFile (file: string, ctx?: object, renderOptions?: RenderOptions) {
|
public async renderFile (file: string, ctx?: object, renderOptions?: RenderOptions) {
|
||||||
const templates = await this.parseFile(file)
|
const templates = await this.parseFile(file)
|
||||||
@@ -98,7 +98,7 @@ export class Liquid {
|
|||||||
return toPromise(this._evalValue(str, ctx))
|
return toPromise(this._evalValue(str, ctx))
|
||||||
}
|
}
|
||||||
public evalValueSync (str: string, ctx: Context): any {
|
public evalValueSync (str: string, ctx: Context): any {
|
||||||
return toValue(this._evalValue(str, ctx))
|
return toValueSync(this._evalValue(str, ctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
public registerFilter (name: string, filter: FilterImplOptions) {
|
public registerFilter (name: string, filter: FilterImplOptions) {
|
||||||
|
|||||||
+10
-25
@@ -1,23 +1,8 @@
|
|||||||
import { isFunction } from './underscore'
|
import { isPromise, isIterator } from './underscore'
|
||||||
|
|
||||||
type resolver = (x?: any) => any
|
|
||||||
|
|
||||||
export interface Thenable<T> {
|
|
||||||
then (resolve: resolver, reject?: resolver): Thenable<T>;
|
|
||||||
catch (reject: resolver): Thenable<T>;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isThenable<T> (val: any): val is Thenable<T> {
|
|
||||||
return val && isFunction(val.then)
|
|
||||||
}
|
|
||||||
|
|
||||||
function isAsyncIterator (val: any): val is IterableIterator<any> {
|
|
||||||
return val && isFunction(val.next) && isFunction(val.throw) && isFunction(val.return)
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert an async iterator to a Promise
|
// convert an async iterator to a Promise
|
||||||
export async function toPromise<T> (val: Generator<unknown, T, unknown> | Thenable<T> | T): Promise<T> {
|
export async function toPromise<T> (val: Generator<unknown, T, unknown> | Promise<T> | T): Promise<T> {
|
||||||
if (!isAsyncIterator(val)) return val
|
if (!isIterator(val)) return val
|
||||||
let value: unknown
|
let value: unknown
|
||||||
let done = false
|
let done = false
|
||||||
let next = 'next'
|
let next = 'next'
|
||||||
@@ -27,8 +12,8 @@ export async function toPromise<T> (val: Generator<unknown, T, unknown> | Thenab
|
|||||||
value = state.value
|
value = state.value
|
||||||
next = 'next'
|
next = 'next'
|
||||||
try {
|
try {
|
||||||
if (isAsyncIterator(value)) value = toPromise(value)
|
if (isIterator(value)) value = toPromise(value)
|
||||||
if (isThenable(value)) value = await value
|
if (isPromise(value)) value = await value
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
next = 'throw'
|
next = 'throw'
|
||||||
value = err
|
value = err
|
||||||
@@ -37,9 +22,9 @@ export async function toPromise<T> (val: Generator<unknown, T, unknown> | Thenab
|
|||||||
return value as T
|
return value as T
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert an async iterator to a value in a synchronous maner
|
// convert an async iterator to a value in a synchronous manner
|
||||||
export function toValue<T> (val: Generator<unknown, T, unknown> | T): T {
|
export function toValueSync<T> (val: Generator<unknown, T, unknown> | T): T {
|
||||||
if (!isAsyncIterator(val)) return val
|
if (!isIterator(val)) return val
|
||||||
let value: any
|
let value: any
|
||||||
let done = false
|
let done = false
|
||||||
let next = 'next'
|
let next = 'next'
|
||||||
@@ -48,9 +33,9 @@ export function toValue<T> (val: Generator<unknown, T, unknown> | T): T {
|
|||||||
done = state.done
|
done = state.done
|
||||||
value = state.value
|
value = state.value
|
||||||
next = 'next'
|
next = 'next'
|
||||||
if (isAsyncIterator(value)) {
|
if (isIterator(value)) {
|
||||||
try {
|
try {
|
||||||
value = toValue(value)
|
value = toValueSync(value)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
next = 'throw'
|
next = 'throw'
|
||||||
value = err
|
value = err
|
||||||
|
|||||||
@@ -14,6 +14,14 @@ export function isFunction (value: any): value is Function {
|
|||||||
return typeof value === 'function'
|
return typeof value === 'function'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isPromise<T> (val: any): val is Promise<T> {
|
||||||
|
return val && isFunction(val.then)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isIterator (val: any): val is IterableIterator<any> {
|
||||||
|
return val && isFunction(val.next) && isFunction(val.throw) && isFunction(val.return)
|
||||||
|
}
|
||||||
|
|
||||||
export function escapeRegex (str: string) {
|
export function escapeRegex (str: string) {
|
||||||
return str.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
|
return str.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,6 +58,33 @@ describe('Liquid', function () {
|
|||||||
expect(html).to.equal('FOO')
|
expect(html).to.equal('FOO')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
describe('#parseAndRenderSync', function () {
|
||||||
|
const engine = new Liquid()
|
||||||
|
it('should parse and render variable output', function () {
|
||||||
|
const html = engine.parseAndRenderSync('{{"foo"}}')
|
||||||
|
expect(html).to.equal('foo')
|
||||||
|
})
|
||||||
|
it('should parse and render complex output', function () {
|
||||||
|
const tpl = '{{ "Welcome|to]Liquid" | split: "|" | join: "("}}'
|
||||||
|
const html = engine.parseAndRenderSync(tpl)
|
||||||
|
expect(html).to.equal('Welcome(to]Liquid')
|
||||||
|
})
|
||||||
|
it('should support for-in with variable', function () {
|
||||||
|
const src = '{% assign total = 3 | minus: 1 %}' +
|
||||||
|
'{% for i in (1..total) %}{{ i }}{% endfor %}'
|
||||||
|
const html = engine.parseAndRenderSync(src, {})
|
||||||
|
return expect(html).to.equal('12')
|
||||||
|
})
|
||||||
|
it('should support `globals` render option', function () {
|
||||||
|
const src = '{{ foo }}'
|
||||||
|
const html = engine.parseAndRenderSync(src, {}, { globals: { foo: 'FOO' } })
|
||||||
|
return expect(html).to.equal('FOO')
|
||||||
|
})
|
||||||
|
it('should support `strictVariables` render option', function () {
|
||||||
|
const src = '{{ foo }}'
|
||||||
|
return expect(() => engine.parseAndRenderSync(src, {}, { strictVariables: true })).throw(/undefined variable/)
|
||||||
|
})
|
||||||
|
})
|
||||||
describe('#express()', function () {
|
describe('#express()', function () {
|
||||||
const liquid = new Liquid({ root: '/root' })
|
const liquid = new Liquid({ root: '/root' })
|
||||||
const render = liquid.express()
|
const render = liquid.express()
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Tokenizer } from '../../../src/parser/tokenizer'
|
|||||||
import { expect } from 'chai'
|
import { expect } from 'chai'
|
||||||
import { Drop } from '../../../src/drop/drop'
|
import { Drop } from '../../../src/drop/drop'
|
||||||
import { Context } from '../../../src/context/context'
|
import { Context } from '../../../src/context/context'
|
||||||
import { toPromise } from '../../../src/util/async'
|
import { toPromise, toValueSync } from '../../../src/util/async'
|
||||||
import { defaultOperators } from '../../../src/render/operator'
|
import { defaultOperators } from '../../../src/render/operator'
|
||||||
import { createTrie } from '../../../src/util/operator-trie'
|
import { createTrie } from '../../../src/util/operator-trie'
|
||||||
|
|
||||||
@@ -158,4 +158,21 @@ describe('Expression', function () {
|
|||||||
expect(await toPromise(create('obj[keys["what\'s this"]]').evaluate(ctx, false))).to.equal('FOO')
|
expect(await toPromise(create('obj[keys["what\'s this"]]').evaluate(ctx, false))).to.equal('FOO')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('sync', function () {
|
||||||
|
it('should eval literal', function () {
|
||||||
|
expect(toValueSync(create('2.4').evaluate(ctx, false))).to.equal(2.4)
|
||||||
|
})
|
||||||
|
it('should return false for "1==2"', () => {
|
||||||
|
expect(toValueSync(create('1==2').evaluate(ctx, false))).to.equal(false)
|
||||||
|
})
|
||||||
|
it('should escape quote', function () {
|
||||||
|
const ctx = new Context({ quote: '"' })
|
||||||
|
expect(toValueSync(create('"\\"" == quote').evaluate(ctx, false))).to.equal(true)
|
||||||
|
})
|
||||||
|
it('should allow nested property access', function () {
|
||||||
|
const ctx = new Context({ obj: { foo: 'FOO' }, keys: { "what's this": 'foo' } })
|
||||||
|
expect(toValueSync(create('obj[keys["what\'s this"]]').evaluate(ctx, false))).to.equal('FOO')
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -76,6 +76,6 @@ describe('filter', function () {
|
|||||||
it('should support key value pairs', async function () {
|
it('should support key value pairs', async function () {
|
||||||
filters.set('add', (a, b) => b[0] + ':' + (a + b[1]))
|
filters.set('add', (a, b) => b[0] + ':' + (a + b[1]))
|
||||||
const two = new NumberToken(new IdentifierToken('2', 0, 1), undefined)
|
const two = new NumberToken(new IdentifierToken('2', 0, 1), undefined)
|
||||||
expect(await toPromise((filters.create('add', [['num', two]]).render(3, ctx)))).to.equal('num:5')
|
expect(await toPromise(filters.create('add', [['num', two]]).render(3, ctx))).to.equal('num:5')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { toPromise, toValue } from '../../../src/util/async'
|
import { toPromise, toValueSync } from '../../../src/util/async'
|
||||||
import { expect, use } from 'chai'
|
import { expect, use } from 'chai'
|
||||||
import * as chaiAsPromised from 'chai-as-promised'
|
import * as chaiAsPromised from 'chai-as-promised'
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ describe('utils/async', () => {
|
|||||||
expect(ret).to.equal('barfoo')
|
expect(ret).to.equal('barfoo')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
describe('#toValue()', function () {
|
describe('#toValueSync()', function () {
|
||||||
it('should throw Error if dependency throws syncly', () => {
|
it('should throw Error if dependency throws syncly', () => {
|
||||||
function * foo (): Generator<Generator<never>> {
|
function * foo (): Generator<Generator<never>> {
|
||||||
return yield bar()
|
return yield bar()
|
||||||
@@ -83,7 +83,7 @@ describe('utils/async', () => {
|
|||||||
function * bar (): Generator<never> {
|
function * bar (): Generator<never> {
|
||||||
throw new Error('bar')
|
throw new Error('bar')
|
||||||
}
|
}
|
||||||
expect(() => toValue(foo())).to.throw('bar')
|
expect(() => toValueSync(foo())).to.throw('bar')
|
||||||
})
|
})
|
||||||
it('should resume yield after catch', () => {
|
it('should resume yield after catch', () => {
|
||||||
function * foo (): Generator<unknown, never, never> {
|
function * foo (): Generator<unknown, never, never> {
|
||||||
@@ -95,7 +95,7 @@ describe('utils/async', () => {
|
|||||||
function * bar (): Generator<never> {
|
function * bar (): Generator<never> {
|
||||||
throw new Error('bar')
|
throw new Error('bar')
|
||||||
}
|
}
|
||||||
expect(toValue(foo())).to.equal('foo')
|
expect(toValueSync(foo())).to.equal('foo')
|
||||||
})
|
})
|
||||||
it('should resume return after catch', () => {
|
it('should resume return after catch', () => {
|
||||||
function * foo (): Generator<Generator<never>, string> {
|
function * foo (): Generator<Generator<never>, string> {
|
||||||
@@ -107,7 +107,10 @@ describe('utils/async', () => {
|
|||||||
function * bar (): Generator<never> {
|
function * bar (): Generator<never> {
|
||||||
throw new Error('bar')
|
throw new Error('bar')
|
||||||
}
|
}
|
||||||
expect(toValue(foo())).to.equal('foo')
|
expect(toValueSync(foo())).to.equal('foo')
|
||||||
|
})
|
||||||
|
it('should return non iterator value as it is', () => {
|
||||||
|
expect(toValueSync('foo')).to.equal('foo')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user