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
+35 -61
View File
@@ -1,98 +1,77 @@
import * as _ from './underscore'
import { __extends } from 'tslib'
import Token from 'src/parser/token'
import ITemplate from 'src/template/itemplate'
function captureStack () {
if (Error.captureStackTrace) {
Error.captureStackTrace(this, this.constructor)
}
}
abstract class LiquidError {
name: string
message: string
stack: string
private file: string
private input: string
abstract class LiquidError extends Error {
private token: Token
private originalError: Error
constructor (err, token) {
this.input = token.input
this.file = token.file
constructor (err: Error, token: Token) {
super(err.message)
this.originalError = err
this.token = token
}
captureStackTrace (obj) {
this.name = obj.constructor.name
captureStack.call(obj)
protected update() {
const err = this.originalError
const context = mkContext(this.input, this.token.line)
const context = mkContext(this.token)
this.message = mkMessage(err.message, this.token)
this.stack = this.message + '\n' + context +
'\n' + (this.stack || this.message) +
(err.stack ? '\nFrom ' + err.stack : '')
'\n' + this.stack + '\nFrom ' + err.stack
}
}
export class TokenizationError extends LiquidError {
constructor (message, token) {
super({ message }, token)
super.captureStackTrace(this)
constructor (message: string, token: Token) {
super(new Error(message), token)
this.name = 'TokenizationError'
super.update()
}
}
TokenizationError.prototype = _.create(Error.prototype) as any
TokenizationError.prototype.constructor = TokenizationError
export class ParseError extends LiquidError {
constructor (err, token) {
constructor (err: Error, token: Token) {
super(err, token)
this.name = 'ParseError'
this.message = err.message
super.captureStackTrace(this)
super.update()
}
}
ParseError.prototype = _.create(Error.prototype) as any
ParseError.prototype.constructor = ParseError
export class RenderError extends LiquidError {
constructor (err, tpl) {
constructor (err: Error, tpl: ITemplate) {
super(err, tpl.token)
this.name = 'RenderError'
this.message = err.message
super.captureStackTrace(this)
super.update()
}
}
RenderError.prototype = _.create(Error.prototype) as any
RenderError.prototype.constructor = RenderError
export class RenderBreakError {
message: string
resolvedHTML: string
constructor (message) {
captureStack.call(this)
export class RenderBreakError extends Error {
resolvedHTML: string = ''
constructor (message: string) {
super(message)
this.name = 'RenderBreakError'
this.message = message + ''
}
}
RenderBreakError.prototype = _.create(Error.prototype) as any
RenderBreakError.prototype.constructor = RenderBreakError
export class AssertionError {
message: string
constructor (message) {
captureStack.call(this)
export class AssertionError extends Error {
constructor (message: string) {
super(message)
this.name = 'AssertionError'
this.message = message + ''
}
}
AssertionError.prototype = _.create(Error.prototype) as any
AssertionError.prototype.constructor = AssertionError
function mkContext (input, targetLine) {
const lines = input.split('\n')
const begin = Math.max(targetLine - 2, 1)
const end = Math.min(targetLine + 3, lines.length)
function mkContext (token: Token) {
const lines = token.input.split('\n')
const begin = Math.max(token.line - 2, 1)
const end = Math.min(token.line + 3, lines.length)
const context = _
.range(begin, end + 1)
.map(lineNumber => {
const indicator = (lineNumber === targetLine) ? '>> ' : ' '
const indicator = (lineNumber === token.line) ? '>> ' : ' '
const num = _.padStart(String(lineNumber), String(end).length)
const text = lines[lineNumber - 1]
return `${indicator}${num}| ${text}`
@@ -102,13 +81,8 @@ function mkContext (input, targetLine) {
return context
}
function mkMessage (msg, token) {
msg = msg || ''
if (token.file) {
msg += ', file:' + token.file
}
if (token.line) {
msg += `, line:${token.line}, col:${token.col}`
}
function mkMessage (msg: string, token: Token) {
if (token.file) msg += `, file:${token.file}`
msg += `, line:${token.line}, col:${token.col}`
return msg
}
+6 -17
View File
@@ -1,26 +1,15 @@
/*
* Call functions in serial until someone resolved.
* @param iterable the array to iterate with.
* @param iteratee returns a new promise.
* The iteratee is invoked with three arguments: (value, index, iterable).
*/
export function anySeries (iterable, iteratee) {
let ret: Promise<any> = Promise.reject(new Error('init'))
iterable.forEach(function (item, idx) {
ret = ret.catch(() => iteratee(item, idx, iterable))
})
return ret
}
/*
* Call functions in serial until someone rejected.
* @param {Array} iterable the array to iterate with.
* @param {Array} iteratee returns a new promise.
* The iteratee is invoked with three arguments: (value, index, iterable).
*/
export function mapSeries (iterable, iteratee) {
let ret: Promise<any> = Promise.resolve('init')
const result = []
export function mapSeries<T1, T2> (
iterable: T1[],
iteratee: (item: T1, idx: number, iterable: T1[]) => Promise<T2> | T2
): Promise<T2[]> {
let ret = Promise.resolve(0)
const result: T2[] = []
iterable.forEach(function (item, idx) {
ret = ret
.then(() => iteratee(item, idx, iterable))
+39 -39
View File
@@ -16,18 +16,18 @@ const suffixes = {
'default': 'th'
}
function abbr (str) {
function abbr (str: string) {
return str.slice(0, 3)
}
// prototype extensions
const _date = {
daysInMonth: function (d) {
daysInMonth: function (d: Date) {
const feb = _date.isLeapYear(d) ? 29 : 28
return [31, feb, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
},
getDayOfYear: function (d) {
getDayOfYear: function (d: Date) {
let num = 0
for (let i = 0; i < d.getMonth(); ++i) {
num += _date.daysInMonth(d)[i]
@@ -35,7 +35,7 @@ const _date = {
return num + d.getDate()
},
getWeekOfYear: function (d, startDay) {
getWeekOfYear: function (d: Date, startDay: number) {
// Skip to startDay of this week
const now = this.getDayOfYear(d) + (startDay - d.getDay())
// Find the first startDay of the year
@@ -44,111 +44,111 @@ const _date = {
return padStart(String(Math.floor((now - then) / 7) + 1), 2, '0')
},
isLeapYear: function (d) {
isLeapYear: function (d: Date) {
const year = d.getFullYear()
return !!((year & 3) === 0 && (year % 100 || (year % 400 === 0 && year)))
},
getSuffix: function (d) {
getSuffix: function (d: Date) {
const str = d.getDate().toString()
const index = parseInt(str.slice(-1))
return suffixes[index] || suffixes['default']
},
century: function (d) {
century: function (d: Date) {
return parseInt(d.getFullYear().toString().substring(0, 2), 10)
}
}
const formatCodes = {
a: function (d) {
a: function (d: Date) {
return dayNamesShort[d.getDay()]
},
A: function (d) {
A: function (d: Date) {
return dayNames[d.getDay()]
},
b: function (d) {
b: function (d: Date) {
return monthNamesShort[d.getMonth()]
},
B: function (d) {
B: function (d: Date) {
return monthNames[d.getMonth()]
},
c: function (d) {
c: function (d: Date) {
return d.toLocaleString()
},
C: function (d) {
C: function (d: Date) {
return _date.century(d)
},
d: function (d) {
d: function (d: Date) {
return padStart(d.getDate(), 2, '0')
},
e: function (d) {
e: function (d: Date) {
return padStart(d.getDate(), 2)
},
H: function (d) {
H: function (d: Date) {
return padStart(d.getHours(), 2, '0')
},
I: function (d) {
I: function (d: Date) {
return padStart(String(d.getHours() % 12 || 12), 2, '0')
},
j: function (d) {
j: function (d: Date) {
return padStart(_date.getDayOfYear(d), 3, '0')
},
k: function (d) {
k: function (d: Date) {
return padStart(d.getHours(), 2)
},
l: function (d) {
l: function (d: Date) {
return padStart(String(d.getHours() % 12 || 12), 2)
},
L: function (d) {
L: function (d: Date) {
return padStart(d.getMilliseconds(), 3, '0')
},
m: function (d) {
m: function (d: Date) {
return padStart(d.getMonth() + 1, 2, '0')
},
M: function (d) {
M: function (d: Date) {
return padStart(d.getMinutes(), 2, '0')
},
p: function (d) {
p: function (d: Date) {
return (d.getHours() < 12 ? 'AM' : 'PM')
},
P: function (d) {
P: function (d: Date) {
return (d.getHours() < 12 ? 'am' : 'pm')
},
q: function (d) {
q: function (d: Date) {
return _date.getSuffix(d)
},
s: function (d) {
s: function (d: Date) {
return Math.round(d.valueOf() / 1000)
},
S: function (d) {
S: function (d: Date) {
return padStart(d.getSeconds(), 2, '0')
},
u: function (d) {
u: function (d: Date) {
return d.getDay() || 7
},
U: function (d) {
U: function (d: Date) {
return _date.getWeekOfYear(d, 0)
},
w: function (d) {
w: function (d: Date) {
return d.getDay()
},
W: function (d) {
W: function (d: Date) {
return _date.getWeekOfYear(d, 1)
},
x: function (d) {
x: function (d: Date) {
return d.toLocaleDateString()
},
X: function (d) {
X: function (d: Date) {
return d.toLocaleTimeString()
},
y: function (d) {
y: function (d: Date) {
return d.getFullYear().toString().substring(2, 4)
},
Y: function (d) {
Y: function (d: Date) {
return d.getFullYear()
},
z: function (d) {
z: function (d: Date) {
const tz = d.getTimezoneOffset() / 60 * 100
return (tz > 0 ? '-' : '+') + padStart(String(Math.abs(tz)), 4, '0')
},
@@ -159,7 +159,7 @@ const formatCodes = {
(formatCodes as any).h = formatCodes.b;
(formatCodes as any).N = formatCodes.L
export default function (d, format) {
export default function (d: Date, format: string) {
let output = ''
let remaining = format
@@ -179,6 +179,6 @@ export default function (d, format) {
// Add the format code
const ch = results[0].charAt(1)
const func = formatCodes[ch]
output += func ? func.call(this, d) : '%' + ch
output += func ? func.call(null, d) : '%' + ch
}
}
+15 -43
View File
@@ -14,10 +14,12 @@ export function isFunction (value: any) {
return typeof value === 'function'
}
export function promisify (fn) {
return function (...args) {
export function promisify<T1, T2> (fn: (arg1: T1, cb: (err: Error | null, result: T2) => void) => void): (arg1: T1) => Promise<T2>;
export function promisify<T1, T2, T3> (fn: (arg1: T1, arg2: T2, cb: (err: Error | null, result: T3) => void) => void):(arg1: T1, arg2: T2) => Promise<T3>;
export function promisify (fn: any) {
return function (...args: any[]) {
return new Promise((resolve, reject) => {
fn(...args, (err, result) => {
fn(...args, (err: Error, result: any) => {
err ? reject(err) : resolve(result)
})
})
@@ -35,7 +37,7 @@ export function stringify (value: any): string {
}
function defaultToString (value: any): string {
const cache = []
const cache: string[] = []
return JSON.stringify(value, (key, value) => {
if (isObject(value)) {
if (cache.indexOf(value) !== -1) {
@@ -75,7 +77,10 @@ export function isError (value: any): boolean {
* @param {Function} iteratee The function invoked per iteration.
* @return {Object} Returns object.
*/
export function forOwn (object, iteratee: ((val: any, key: string, obj: object) => boolean | void)) {
export function forOwn <T>(
object: {[key: string]: T} | undefined,
iteratee: ((val: T, key: string, obj: {[key: string]: T}) => boolean | void)
) {
object = object || {}
for (const k in object) {
if (object.hasOwnProperty(k)) {
@@ -85,45 +90,12 @@ export function forOwn (object, iteratee: ((val: any, key: string, obj: object)
return object
}
/*
* Assigns own enumerable string keyed properties of source objects to the destination object.
* Source objects are applied from left to right.
* Subsequent sources overwrite property assignments of previous sources.
*
* Note: This method mutates object and is loosely based on Object.assign.
*
* @param {Object} object The destination object.
* @param {...Object} sources The source objects.
* @return {Object} Returns object.
*/
export function assign (obj: object, ...srcs: object[]): object {
obj = isObject(obj) ? obj : {}
srcs.forEach(src => binaryAssign(obj, src))
return obj
}
function binaryAssign (target: object, src: object): object {
for (const key in src) if (src.hasOwnProperty(key)) target[key] = src[key]
return target
}
export function last (arr: any[]): any {
export function last <T>(arr: T[]): T;
export function last (arr: string): string;
export function last (arr: any[] | string): any | string {
return arr[arr.length - 1]
}
export function uniq (arr: any[]): any[] {
const u = {}
const a = []
for (let i = 0, l = arr.length; i < l; ++i) {
if (u.hasOwnProperty(arr[i])) {
continue
}
a.push(arr[i])
u[arr[i]] = 1
}
return a
}
/*
* Checks if value is the language type of Object.
* (e.g. arrays, functions, objects, regexes, new Number(0), and new String(''))
@@ -144,13 +116,13 @@ export function isObject (value: any): boolean {
* negative — if you'd like a negative range, use a negative step.
*/
export function range (start: number, stop?: number, step?: number) {
if (arguments.length === 1) {
if (stop === undefined) {
stop = start
start = 0
}
step = step || 1
const arr = []
const arr: number[] = []
for (let i = start; i < stop; i += step) {
arr.push(i)
}