mirror of
https://github.com/harttle/liquidjs.git
synced 2026-09-16 21:00:40 -07:00
fix: stack overflow on large number of templates, #513
This commit is contained in:
+38
-56
@@ -7,25 +7,6 @@ export interface Thenable<T> {
|
||||
catch (reject: resolver): Thenable<T>;
|
||||
}
|
||||
|
||||
function createResolvedThenable<T> (value: T): Thenable<T> {
|
||||
const ret = {
|
||||
then: (resolve: resolver) => resolve(value),
|
||||
catch: () => ret
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
function createRejectedThenable<T> (err: Error): Thenable<T> {
|
||||
const ret = {
|
||||
then: (resolve: resolver, reject?: resolver) => {
|
||||
if (reject) return reject(err)
|
||||
return ret
|
||||
},
|
||||
catch: (reject: resolver) => reject(err)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
function isThenable<T> (val: any): val is Thenable<T> {
|
||||
return val && isFunction(val.then)
|
||||
}
|
||||
@@ -34,48 +15,49 @@ 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 thenable (Promise compatible)
|
||||
export function toThenable<T> (val: IteratorResult<unknown, T> | Thenable<T> | any): Thenable<T> {
|
||||
if (isThenable(val)) return val
|
||||
if (isAsyncIterator(val)) return reduce()
|
||||
return createResolvedThenable(val)
|
||||
|
||||
function reduce<T> (prev?: T): Thenable<T> {
|
||||
let state
|
||||
// convert an async iterator to a Promise
|
||||
export async function toPromise<T> (val: Generator<unknown, T, unknown> | Thenable<T> | T): Promise<T> {
|
||||
if (!isAsyncIterator(val)) return val
|
||||
let value: unknown
|
||||
let done = false
|
||||
let next = 'next'
|
||||
do {
|
||||
const state = val[next](value)
|
||||
done = state.done
|
||||
value = state.value
|
||||
next = 'next'
|
||||
try {
|
||||
state = val.next(prev)
|
||||
if (isAsyncIterator(value)) value = toPromise(value)
|
||||
if (isThenable(value)) value = await value
|
||||
} catch (err) {
|
||||
return createRejectedThenable(err as Error)
|
||||
next = 'throw'
|
||||
value = err
|
||||
}
|
||||
} while (!done)
|
||||
return value as T
|
||||
}
|
||||
|
||||
if (state.done) return createResolvedThenable(state.value)
|
||||
return toThenable(state.value!).then(reduce, err => {
|
||||
let state
|
||||
// convert an async iterator to a value in a synchronous maner
|
||||
export function toValue<T> (val: Generator<unknown, T, unknown> | T): T {
|
||||
if (!isAsyncIterator(val)) return val
|
||||
let value: any
|
||||
let done = false
|
||||
let next = 'next'
|
||||
do {
|
||||
const state = val[next](value)
|
||||
done = state.done
|
||||
value = state.value
|
||||
next = 'next'
|
||||
if (isAsyncIterator(value)) {
|
||||
try {
|
||||
state = val.throw!(err)
|
||||
} catch (e) {
|
||||
return createRejectedThenable(e as Error)
|
||||
value = toValue(value)
|
||||
} catch (err) {
|
||||
next = 'throw'
|
||||
value = err
|
||||
}
|
||||
if (state.done) return createResolvedThenable(state.value)
|
||||
return reduce(state.value)
|
||||
})
|
||||
}
|
||||
}
|
||||
} while (!done)
|
||||
return value
|
||||
}
|
||||
|
||||
export function toPromise<T> (val: Generator<unknown, T, unknown> | Thenable<T> | T): Promise<T> {
|
||||
return Promise.resolve(toThenable(val))
|
||||
}
|
||||
|
||||
// get the value of async iterator in synchronous manner
|
||||
export function toValue<T> (val: Generator<unknown, T, unknown> | Thenable<T> | T): T {
|
||||
let ret: T
|
||||
toThenable(val)
|
||||
.then((x: any) => {
|
||||
ret = x
|
||||
return createResolvedThenable(ret)
|
||||
})
|
||||
.catch((err: Error) => {
|
||||
throw err
|
||||
})
|
||||
return ret!
|
||||
}
|
||||
export const toThenable = toPromise
|
||||
|
||||
Reference in New Issue
Block a user