lib/src/util/support/Messages.ts

140 lines
3.7 KiB
TypeScript
Raw Normal View History

2021-06-03 03:36:25 +00:00
import {collect} from '../collection/Collection'
import {InvalidJSONStateError, JSONState, Rehydratable} from './Rehydratable'
import {Pipe} from './Pipe'
2021-06-02 01:59:40 +00:00
/**
* A class for building and working with messages grouped by keys.
*/
export class Messages implements Rehydratable {
protected messages: {[key: string]: string[]} = {}
/**
* @param [allMessages] an initial array of messages to put in the "all" key
*/
constructor(allMessages?: string[]) {
if ( allMessages ) {
this.messages.all = allMessages
}
}
/** All group keys of messages. */
public keys(): string[] {
return Object.keys(this.messages)
}
/** Add a message to a group. */
public put(key: string, message: string): this {
if ( !this.messages[key] ) {
this.messages[key] = []
}
this.messages[key].push(message)
return this
}
/** Returns true if the given group has the message. */
public has(key: string, message: string): boolean {
2021-06-03 03:36:25 +00:00
return Boolean(this.messages[key]?.includes(message))
2021-06-02 01:59:40 +00:00
}
/**
* Returns true if any messages are found.
* @param [forKeys] if provided, only search the given keys
*/
2021-06-03 03:36:25 +00:00
public any(forKeys?: string[]): boolean {
2021-06-02 01:59:40 +00:00
if ( forKeys ) {
return forKeys.map(key => this.messages[key])
.filter(Boolean)
.some((bag: string[]) => bag.length)
}
return Object.values(this.messages).some((bag: string[]) => bag.length)
}
/**
* Returns the first message.
* @param [forKey] if provided, only search the given key
*/
2021-06-03 03:36:25 +00:00
public first(forKey?: string): string | undefined {
if ( !forKey ) {
forKey = Object.keys(this.messages)[0]
}
2021-06-02 01:59:40 +00:00
if ( forKey && this.messages[forKey].length ) {
return this.messages[forKey][0]
}
}
/**
* Return all messages in a flat array.
* @param [forKey] if provided, only search the given key
*/
2021-06-03 03:36:25 +00:00
public all(forKey?: string): string[] {
2021-06-02 01:59:40 +00:00
if ( forKey ) {
return this.messages[forKey] || []
}
2021-06-03 03:36:25 +00:00
return collect<string[]>(Object.values(this.messages)).collapse()
.all() as string[]
2021-06-02 01:59:40 +00:00
}
/**
* Flat array of only distinct messages.
* @param [forKey] if provided, only search the given key
*/
2021-06-03 03:36:25 +00:00
public unique(forKey?: string): string[] {
return collect<string>(this.all(forKey)).unique<string>()
.all()
2021-06-02 01:59:40 +00:00
}
/**
* Get the total number of messages.
* @param [forKey] if provided, only search the given key
*/
public count(forKey?: string): number {
return this.all(forKey).length
}
async dehydrate(): Promise<JSONState> {
return this.messages
}
rehydrate(state: JSONState): void {
if ( typeof state === 'object' && !Array.isArray(state) ) {
let all = true
for ( const key in state ) {
2021-06-03 03:36:25 +00:00
if ( !Object.prototype.hasOwnProperty.call(state, key) ) {
continue
}
2021-06-02 01:59:40 +00:00
const set = state[key]
if ( !(Array.isArray(set) && set.every(x => typeof x === 'string')) ) {
2021-06-03 03:36:25 +00:00
all = false
break
2021-06-02 01:59:40 +00:00
}
}
if ( all ) {
2021-06-03 03:36:25 +00:00
this.messages = state as any
2021-06-02 01:59:40 +00:00
}
}
2021-06-03 03:36:25 +00:00
throw new InvalidJSONStateError('Invalid message state object.', { state })
2021-06-02 01:59:40 +00:00
}
2021-06-03 03:36:25 +00:00
toJSON(): {[key: string]: string[]} {
2021-06-02 01:59:40 +00:00
return this.messages
}
2021-06-03 03:36:25 +00:00
toString(): string {
return JSON.stringify(this.toJSON())
2021-06-02 01:59:40 +00:00
}
/**
* Get a new Pipe object wrapping this instance.
*/
pipe(): Pipe<Messages> {
return Pipe.wrap<Messages>(this)
}
}