Finish fleshing out Model; refactor mixin types; TRUNCATE
This commit is contained in:
@@ -496,7 +496,9 @@ export class AsyncCollection<T> {
|
||||
|
||||
if ( !fetched_indices.includes(index) ) {
|
||||
fetched_indices.push(index)
|
||||
random_items.push(await this._items.at_index(index))
|
||||
const item = await this._items.at_index(index)
|
||||
if ( typeof item !== 'undefined' )
|
||||
random_items.push(item)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ export class StopIteration extends Error {}
|
||||
export abstract class Iterable<T> {
|
||||
protected index = 0
|
||||
|
||||
abstract async at_index(i: number): Promise<T>
|
||||
abstract async at_index(i: number): Promise<T | undefined>
|
||||
abstract async from_range(start: number, end: number): Promise<Collection<T>>
|
||||
abstract async count(): Promise<number>
|
||||
abstract clone(): Iterable<T>
|
||||
|
||||
@@ -29,17 +29,17 @@ export default abstract class Logger {
|
||||
case LoggingLevel.Success:
|
||||
return green('success')
|
||||
case LoggingLevel.Error:
|
||||
return red('error')
|
||||
return red(' error')
|
||||
case LoggingLevel.Warning:
|
||||
return yellow('warning')
|
||||
case LoggingLevel.Info:
|
||||
return blue('info')
|
||||
return blue(' info')
|
||||
case LoggingLevel.Debug:
|
||||
return cyan('debug')
|
||||
return cyan(' debug')
|
||||
case LoggingLevel.Verbose:
|
||||
return gray('verbose')
|
||||
case LoggingLevel.Silent:
|
||||
return gray('silent')
|
||||
return gray(' silent')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ class Logging {
|
||||
level,
|
||||
output,
|
||||
date: new Date,
|
||||
caller_name: this.get_caller_info(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,6 +74,14 @@ class Logging {
|
||||
public remove_logger(logger_class: typeof Logger) {
|
||||
this._loggers = this._loggers.filter(x => !(x instanceof logger_class))
|
||||
}
|
||||
|
||||
protected get_caller_info(level = 5): string {
|
||||
let e = new Error
|
||||
if ( !e.stack ) return 'Unknown'
|
||||
return e.stack.split(' at ')
|
||||
.slice(level)
|
||||
.map((x: string): string => x.trim().split(' (')[0].split('.')[0].split(':')[0])[0]
|
||||
}
|
||||
}
|
||||
|
||||
export { Logging }
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import AbstractLogger from './Logger.ts'
|
||||
import { LogMessage } from './types.ts'
|
||||
import { gray } from '../../external/std.ts'
|
||||
import { gray, cyan } from '../../external/std.ts'
|
||||
|
||||
export default class StandardLogger extends AbstractLogger {
|
||||
public async write(message: LogMessage): Promise<void> {
|
||||
const prefix = this.level_display(message.level)
|
||||
const text = `${prefix} ${gray(this.format_date(message.date))}`
|
||||
const text = `${prefix} ${gray(this.format_date(message.date))} (${cyan(message.caller_name || 'Unknown')})`
|
||||
console.log(text, message.output)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ interface LogMessage {
|
||||
level: LoggingLevel,
|
||||
date: Date,
|
||||
output: any,
|
||||
caller_name: string,
|
||||
}
|
||||
|
||||
const isLogMessage = (something: any): something is LogMessage => {
|
||||
|
||||
115
lib/src/support/BehaviorSubject.ts
Normal file
115
lib/src/support/BehaviorSubject.ts
Normal file
@@ -0,0 +1,115 @@
|
||||
export class UnsubscribeError extends Error {}
|
||||
export class CompletedObservableError extends Error {
|
||||
constructor() {
|
||||
super('This observable can no longer be pushed to, as it has been completed.')
|
||||
}
|
||||
}
|
||||
|
||||
export type SubscriberFunction<T> = (val: T) => any
|
||||
export type SubscriberErrorFunction = (error: Error) => any
|
||||
export type SubscriberCompleteFunction<T> = (val?: T) => any
|
||||
|
||||
export type ComplexSubscriber<T> = {
|
||||
next?: SubscriberFunction<T>,
|
||||
error?: SubscriberErrorFunction,
|
||||
complete?: SubscriberCompleteFunction<T>,
|
||||
}
|
||||
|
||||
export type Subscription<T> = SubscriberFunction<T> | ComplexSubscriber<T>
|
||||
export type Unsubscribe = { unsubscribe: () => void }
|
||||
|
||||
export class BehaviorSubject<T> {
|
||||
protected subscribers: ComplexSubscriber<T>[] = []
|
||||
protected _is_complete: boolean = false
|
||||
protected _value?: T
|
||||
protected _has_push: boolean = false
|
||||
|
||||
public subscribe(subscriber: Subscription<T>): Unsubscribe {
|
||||
if ( typeof subscriber === 'function' ) {
|
||||
this.subscribers.push({ next: subscriber })
|
||||
} else {
|
||||
this.subscribers.push(subscriber)
|
||||
}
|
||||
|
||||
return {
|
||||
unsubscribe: () => {
|
||||
this.subscribers = this.subscribers.filter(x => x !== subscriber)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public to_promise(): Promise<T> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const { unsubscribe } = this.subscribe({
|
||||
next: (val: T) => {
|
||||
resolve(val)
|
||||
unsubscribe()
|
||||
},
|
||||
error: (error: Error) => {
|
||||
reject(error)
|
||||
unsubscribe()
|
||||
},
|
||||
complete: (val?: T) => {
|
||||
resolve(val)
|
||||
unsubscribe()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
public async next(val: T): Promise<void> {
|
||||
if ( this._is_complete ) throw new CompletedObservableError()
|
||||
this._value = val
|
||||
this._has_push = true
|
||||
for ( const subscriber of this.subscribers ) {
|
||||
if ( subscriber.next ) {
|
||||
try {
|
||||
await subscriber.next(val)
|
||||
} catch (e) {
|
||||
if ( e instanceof UnsubscribeError ) {
|
||||
this.subscribers = this.subscribers.filter(x => x !== subscriber)
|
||||
} else if (subscriber.error) {
|
||||
await subscriber.error(e)
|
||||
} else {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async push(vals: T[]): Promise<void> {
|
||||
if ( this._is_complete ) throw new CompletedObservableError()
|
||||
await Promise.all(vals.map(val => this.next(val)))
|
||||
}
|
||||
|
||||
public async complete(final_val?: T): Promise<void> {
|
||||
if ( this._is_complete ) throw new CompletedObservableError()
|
||||
if ( typeof final_val === 'undefined' ) final_val = this.value()
|
||||
else this._value = final_val
|
||||
|
||||
for ( const subscriber of this.subscribers ) {
|
||||
if ( subscriber.complete ) {
|
||||
try {
|
||||
await subscriber.complete(final_val)
|
||||
} catch (e) {
|
||||
if ( subscriber.error ) {
|
||||
await subscriber.error(e)
|
||||
} else {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this._is_complete = true
|
||||
}
|
||||
|
||||
public value(): T | undefined {
|
||||
return this._value
|
||||
}
|
||||
|
||||
public is_complete(): boolean {
|
||||
return this._is_complete
|
||||
}
|
||||
}
|
||||
@@ -7,3 +7,5 @@ export function applyMixins(derivedCtor: any, baseCtors: any[]) {
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export type Constructor<T = {}> = new (...args: any[]) => T
|
||||
|
||||
Reference in New Issue
Block a user